最近在学习状态设计模式时,发现一个实现工厂模式的优雅方式,那就是借助注解和Spring的BeanPostProcessor。使用处理器BeanPostProcessor可以在bean初始化的前后对bean进行操作,所以我们可以在bean初始化后对自己的目标bean进行缓存,进而实现我们想要的处理逻辑。
BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口,点击源码可以查看到BeanPostProcessor中有两个方法:
- (1)postProcessBeforeInitialization方法;
- (2)postProcessAfterInitialization方法;
两个方面的运行顺序如下:
- (1)Spring IOC容器实例化Bean
- (2)调用BeanPostProcessor的postProcessBeforeInitialization方法
- (3)调用bean实例的初始化方法
- (4)调用BeanPostProcessor的postProcessAfterInitialization方法
注意:实测项目中只能有一个BeanPostProcessor的实现,当出现多个时,只是加载了一次。注意此点,避免踩坑。
背景
当我们需要根据不同的状态调用接口不同的实现时,可以使用工厂模式实现。而之前最常用的方式就是通过多个if else的静态工厂方式进行处理。
进入主题
通过BeanPostProcessor实现相同接口的不同实现bean的工厂。
1 定义一个注解,用于标记不同的实现bean
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Component
public @interface OrderStatusProcessor {
/**
* 状态枚举
*/
OrderStatusEnum status() ;
}
状态枚举定义:
@Getter
@AllArgsConstructor
public enum OrderStatusEnum {
CREATE(1, "新建"),
COMPLETE(2, "完成"),
CANCLE(3, "取消");
private final Integer statusCode;
private final String statusDesc;
public static OrderStatusEnum getEnumByCode(Integer statusCode) {
if (statusCode == null) {
return null;
}
return Arrays.stream(values()).filter(e -> e.getStatusCode().equals(statusCode)).findFirst().orElse(null);
}
}
2 定义接口处理类
public interface StatusProcessor {
public boolean action(OrderInfo orderInfo);
}
Model定义:
@Data
@Builder
public class OrderInfo {
/**
* 订单编号
*/
private Long orderId;
/**
* 订单状态:1-新建;2-完成;3-取消;
*/
private Integer orderStatus;
}
3 自定义处理器实现,并用自定义的注解进行标识
@Slf4j
@OrderStatusProcessor(status = OrderStatusEnum.CREATE)
public class StatusCreateProcessor implements StatusProcessor {
@Override
public boolean action(OrderInfo orderInfo) {
log.info("订单==>编号:({}),执行({})操作。",orderInfo.getOrderId(),OrderStatusEnum.getEnumByCode(orderInfo.getOrderStatus()).getStatusDesc());
return false;
}
}
@Slf4j
@OrderStatusProcessor(status = OrderStatusEnum.COMPLETE)
public class StatusCompleteProcessor implements StatusProcessor {
@Override
public boolean action(OrderInfo orderInfo) {
log.info("订单==>编号:({}),执行({})操作。",orderInfo.getOrderId(),OrderStatusEnum.getEnumByCode(orderInfo.getOrderStatus()).getStatusDesc());
return false;
}
}
@Slf4j
@OrderStatusProcessor(status = OrderStatusEnum.CANCLE)
public class StatusCancleProcessor implements StatusProcessor {
@Override
public boolean action(OrderInfo orderInfo) {
log.info("订单==>编号:({}),执行({})操作。",orderInfo.getOrderId(),OrderStatusEnum.getEnumByCode(orderInfo.getOrderStatus()).getStatusDesc());
return false;
}
}
4 通过BeanPostProcessor实现对bean后置处理,对注解的类型bean对象进行缓存
@Slf4j
@Component
public class StatusProcessRegistry implements BeanPostProcessor {
/**
* 第一层key是订单状态。
* 第二层是对应的处理器。
*/
private static Map statusProcessMap = new ConcurrentHashMap<>();
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("beanName =============>"+beanName);
if (bean instanceof StatusProcessor && bean.getClass().isAnnotationPresent(OrderStatusProcessor.class)) {
OrderStatusProcessor annotation = bean.getClass().getAnnotation(OrderStatusProcessor.class);
OrderStatusEnum orderStatusEnum = annotation.status();
Integer statusCode = orderStatusEnum.getStatusCode();
if (!statusProcessMap.containsKey(statusCode)){
statusProcessMap.put(statusCode,(StatusProcessor)bean);
}
}
return bean;
}
public StatusProcessor acquireStatusProcess(Integer statusCode) {
return statusProcessMap.get(statusCode);
}
}
5 状态机引擎处理类定义
@AllArgsConstructor
@Component
public class OrderOperatorEngine {
private final StatusProcessRegistry statusProcessRegistry;
public boolean operate(OrderInfo orderInfo) throws Exception{
// 获取当前事件处理器
StatusProcessor statusProcessor = statusProcessRegistry.acquireStatusProcess(orderInfo.getOrderStatus());
if (statusProcessor == null) {
throw new Exception("NOT_FOUND_PROCESSOR");
}
// 执行处理逻辑
return statusProcessor.action(orderInfo);
}
}
6 Rest Controller定义
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/myorder")
public class OrderController {
private final OrderOperatorEngine orderOperatorEngine;
@GetMapping("/update/{orderId}/{orderStatus}")
public void accept(@PathVariable(value = "orderId") Long orderId, @PathVariable(value = "orderStatus") Integer orderStatus) {
OrderInfo orderInfo = OrderInfo.builder()
.orderId(orderId)
.orderStatus(orderStatus)
.build();
log.info("updateOrder info:{}", JSON.toJSONString(orderInfo));
try {
orderOperatorEngine.operate(orderInfo);
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
7 演示日志
###|||2021-10-19 21:49:21.651|||INFO|||656c12ff21d64eec9226f68d9db5d999.201.16346513616080000|||-|||http-nio-8080-exec-3|||OrderController--->updateOrder info:{"orderId":10001,"orderStatus":2}
###|||2021-10-19 21:49:21.652|||INFO|||656c12ff21d64eec9226f68d9db5d999.201.16346513616080000|||-|||http-nio-8080-exec-3|||StatusCompleteProcessor--->订单==>编号:(10001),执行(完成)操作。
###|||2021-10-19 21:49:29.350|||INFO|||656c12ff21d64eec9226f68d9db5d999.204.16346513693480000|||-|||http-nio-8080-exec-6|||OrderController--->updateOrder info:{"orderId":10001,"orderStatus":1}
###|||2021-10-19 21:49:29.350|||INFO|||656c12ff21d64eec9226f68d9db5d999.204.16346513693480000|||-|||http-nio-8080-exec-6|||StatusCreateProcessor--->订单==>编号:(10001),执行(新建)操作。
###|||2021-10-19 21:49:38.690|||INFO|||656c12ff21d64eec9226f68d9db5d999.208.16346513786880000|||-|||http-nio-8080-exec-10|||OrderController--->updateOrder info:{"orderId":10001,"orderStatus":3}
###|||2021-10-19 21:49:38.690|||INFO|||656c12ff21d64eec9226f68d9db5d999.208.16346513786880000|||-|||http-nio-8080-exec-10|||StatusCancleProcessor--->订单==>编号:(10001),执行(取消)操作。
到此这篇关于详解使用Spring的BeanPostProcessor优雅的实现工厂模式的文章就介绍到这了,希望能给你带来一些帮助和启发!