# BeanEnhance 实例增强
MornBoot提供更多的注解对实例进行描述,使用BeanCaches
实例缓存批量检索需要的实例。在1.2.0+
版本中,实例增强还支持对方法的缓存、检索和调用。
Since:v1.0.0
# Functions
- 实例缓存、检索、事件回调
- 方法缓存、检索、调用
- 快速自定义注解
# 实例注解
使用@Name
、@Tag
、@Target
为实例设置名称、标签、目标,以便在需要的时候检索这些实例。
# 示例
@Slf4j
@Component
@Name("caramel") // 为实例命名
@Tag("small") // 标签,描述实例的特征
@Target(Food.class) // 目标,描述实例的作用目标
public class Caramel implements Pet {
@Override
public String eat(Food food) {
log.info("{}在吃{}...", "caramel", food.getName());
return "fishBone";
}
}
# 实例缓存
实例增强设计的使用场景是频繁的检索有共性的Bean。为了避免检索耗费时间,检索操作默认使用BeanCaches
完成。
BeanCaches
依赖SpringBoot的缓存机制,因此必须开启缓存注解@EnableCaching
。
# 示例
// 获取名为`caramel`的宠物
Pet caramel = BeanCaches.nameBean(Pet.class, "caramel");
// 获取标签为`small`的宠物
// 注意:此例中,BeanCaches会尝试检索所有标签为`small`的实例,而不限于`Pet`的子类
Pet small = (Pet) BeanCaches.tagBean(null, "small");
// 获取所有目标为`Food`的宠物
List<Pet> foods = BeanCaches.targetBeans(Pet.class, Food.class);
caramel.eat(new Food("fish")); // log:caramel在吃fish...
# 示例:观察者模式
基于BeanCaches
编写观察者模式极为简洁,你甚至不需要在被观察者中,维护观察者的列表。因为BeanCaches
会配合Spring容器检索所有的观察者实例。利用@Name
、@Tag
等注解,你还可以更为灵活的指定特定的观察者。
// 被观察者
public class Subject {
/**
* 状态
*/
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
/**
* 通知全部观察者
*/
private void notifyObservers() {
List<Observer> observers = BeanCaches.targetBeans(Observer.class, Subject.class);
for (Observer observer : observers) {
observer.update(state);
}
}
}
// 观察者
public interface Observer {
/**
* 更新
*
* @param state 被观察者状态
*/
void update(int state);
}
// 状态观察者
@Slf4j
@Component
@Target(Subject.class)
public class StateObserver implements Observer {
@Override
public void update(int state) {
log.info("Subject's state is {}", state);
}
}
# 示例:BeanProcessor
基于MornBoot内置的函数式接口,我们可以将代码进一步简化。
// 被观察者
public class Subject {
/**
* 状态
*/
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
/**
* 通知全部观察者
*/
private void notifyObservers() {
BeanFunctionUtils.processes(StateProcessor.class, this);
}
}
// 状态观察者
@Slf4j
@Component
@Tag
public class StateObserver implements BeanProcessor<Subject> {
@Override
public void handle(Subject source) {
log.info("Subject's state is {}", source.getState());
}
}
# 函数式接口
MornBoot提供多种函数式接口,同时也支持JDK内置的函数式接口,如:Consumer
、Runable
等。
- BeanAdapter
- BeanConverter
- BeanProcessor
- BeanProducer
# 示例:混合检索
BeanCaches
支持同时按多种条件检索Bean。
// 构建检索条件,按标签和目标检索
String[] tags = Tags.from(Color.class, "yellow").add("big").toArray();
AnnotationIdentifyCase identifyCase = AnnotationIdentifyCase.builder()
.tags(tags).target(Toy.class).build();
Dog dog = BeanCaches.bean(Dog.class, identifyCase);
# 方法增强
类似于实例增强,我们可以使用@Function
注解为方法命名,以便在需要的时候调用它。
@Function
默认使用方法名作为调用名称。
# 方法描述
@Slf4j
@Component
@Tag
public class Dog {
@Function
public String eat(String food) {
log.info("狗在吃{}...", food);
return "bone";
}
@Function
public void play() {
log.info("狗在玩...");
}
}
# 方法调用
方法增强适用于调用多个类中的相似方法,而且支持不同类、不同参数、不同返回值的多个方法,BeanFunctions
会尽量调整参数传入顺序、数目,以便正确调用这些方法。
// 构建检索条件,检索名为`eat`的方法
AnnotationIdentifyCase functionId = AnnotationIdentifyCase.builder().name("eat").build();
List<FunctionHolder> functions = BeanCaches.functions(functionId);
// 调用`eat`方法
List<String> returns = BeanFunctions.call(functions, "meat"); // log:狗在吃meat