摘要: 由于业务场景复杂,一个算法需要开发行为变化多端的多个实现类,然后在系统运行时根据不同场景装载不同的类实例。为了使源码具有更好的可扩展性和可重用性,在借鉴前人处理方法的基础上,介绍在Spring项目中,基于自定义注解实现动态匹配相关实现类示例,并调用其中的函数。
前言
在博文《Spring注解之自定义注解入门》中,介绍了如何使用Spring提供的元注解定义新注解的基本语法,本文在此基础之上介绍如何使用自定义注解动态匹配相关实现类实例,并调用其中的函数。
欲了解更多相关知识点请移步《Spring 动态绑定多实现类实例综述》。
业务场景回顾
需求描述:定制一个绘图工具,她根据客户端发送的指令可以画出正方形、矩形、圆形和三角形等各种各样的几何图形。例如,当客户端需要绘制三角形的时候,就调用绘制三角形的方法;当需要绘制圆形的时候,就调用绘制圆形的方法。
话不多说,直接上代码,我们首先创建自定义注解ShapeAn:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义画图注解
*
* @author Wiener
* @date 2021/1/30
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ShapeAn {
String value();
String beanName();
}
其中包含两个成员变量实现类bean昵称value和bean的中文名称 beanName。给每个接口类Shape的实现类添加自定义注解:
import com.eg.wiener.config.ShapeAn;
import com.eg.wiener.service.Shape;
import org.springframework.stereotype.Service;
/**
* 三角形
*
* @author Wiener
* @date 2021/1/7
*/
@ShapeAn(value = "triangleAn", beanName = "三角形画图工具")
@Service
public class Triangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Triangle::draw() method.");
}
}
// ---我是分割线---
import com.eg.wiener.config.ShapeAn;
import com.eg.wiener.service.Shape;
import org.springframework.stereotype.Service;
/**
* 正方形
*
* @author Wiener
* @date 2021/1/7
*/
@ShapeAn(value = "squareAn", beanName = "正方形画图工具")
@Service
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
// ---我是分割线---
import com.eg.wiener.config.ShapeAn;
import com.eg.wiener.service.Shape;
import org.springframework.stereotype.Service;
/**
* 矩形
*
* @author Wiener
* @date 2021/1/7
*/
@ShapeAn(value = "rectangleAn", beanName = "矩形画图工具")
@Service
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
// ---我是分割线---
import com.eg.wiener.config.ShapeAn;
import com.eg.wiener.service.Shape;
import org.springframework.stereotype.Service;
/**
* 圆形画图实现类
*
* @author Wiener
* @date 2021/1/7
*/
@ShapeAn(value = "circleAn", beanName = "圆形画图工具")
@Service
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
通过函数getBeansWithAnnotation(Class<? extends Annotation> annotationType)获取所有使用了自定义注解的bean:
import com.eg.wiener.config.ShapeAn;
import com.eg.wiener.service.Shape;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* 自定义注解实现画图工具类自动识别
*
* @author Wiener
* @date 2021/1/19
*/
@Component
public class ShapeServiceAnnotation implements ApplicationListener<ContextRefreshedEvent> {
private static Map<String, Shape> shapeMap = null;
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
ApplicationContext ac = contextRefreshedEvent.getApplicationContext();
Map<String, Object> beansWithAnnotation = ac.getBeansWithAnnotation(ShapeAn.class);
if (beansWithAnnotation != null) {
shapeMap = new HashMap<>();
beansWithAnnotation.forEach((key, value) ->{
String bizType = value.getClass().getAnnotation(ShapeAn.class).value();
shapeMap.put(bizType, (Shape) value);
});
}
}
public void draw(String bean) {
shapeMap.get(bean).draw();
}
}
在控制层创建测试方法:
@Autowired
private ShapeServiceAnnotation shapeServiceAnnotation;
/**
* xxx/drawByAnno?code=rectangleTem
* 由自定义注解实现
* @param code 实现类bean名称
* @return
*/
@GetMapping("/drawByAnno")
public String drawByAnno(String code) {
shapeServiceAnnotation.draw(code);
return "由自定义注解实现Bean装配成功";
}
我们只需要在客户端向函数 drawByAnno(String code)传入约定的入参rectangle和circle等即可完成方法调用。
结束语
一个接口由于场景不同,导致需要开发不同的实现类。本文介绍在Spring Boot项目中,基于自定义注解实现动态匹配相关实现类示例,并调用其中的函数。