Spring

使用Spring的BeanPostProcessor优雅的实现工

2021-11-25  本文已影响0人  随风_d6a2

最近在学习状态设计模式时,发现一个实现工厂模式的优雅方式,那就是借助注解和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
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

上一篇下一篇

猜你喜欢

热点阅读