# 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内置的函数式接口,如:ConsumerRunable等。

  • 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