美文网首页Spring
使用Spring的BeanPostProcessor优雅的实现工

使用Spring的BeanPostProcessor优雅的实现工

作者: 随风_d6a2 | 来源:发表于2021-11-25 19:41 被阅读0次

    最近在学习状态设计模式时,发现一个实现工厂模式的优雅方式,那就是借助注解和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<Integer, StatusProcessor> 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优雅的实现工厂模式的文章就介绍到这了,希望能给你带来一些帮助和启发!

    作者:GuangHui
    链接:https://www.jianshu.com/p/83efd9a2d3d5
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    相关文章

      网友评论

        本文标题:使用Spring的BeanPostProcessor优雅的实现工

        本文链接:https://www.haomeiwen.com/subject/rfjztrtx.html