最近在學(xué)習(xí)狀態(tài)設(shè)計(jì)模式時(shí),發(fā)現(xiàn)一個(gè)實(shí)現(xiàn)工廠模式的優(yōu)雅方式叶沛,那就是借助注解和Spring的BeanPostProcessor拴测。使用處理器BeanPostProcessor可以在bean初始化的前后對(duì)bean進(jìn)行操作壹将,所以我們可以在bean初始化后對(duì)自己的目標(biāo)bean進(jìn)行緩存,進(jìn)而實(shí)現(xiàn)我們想要的處理邏輯腺怯。
BeanPostProcessor是Spring IOC容器給我們提供的一個(gè)擴(kuò)展接口袱饭,點(diǎn)擊源碼可以查看到BeanPostProcessor中有兩個(gè)方法:
- (1)postProcessBeforeInitialization方法;
- (2)postProcessAfterInitialization方法呛占;
兩個(gè)方面的運(yùn)行順序如下:
- (1)Spring IOC容器實(shí)例化Bean
- (2)調(diào)用BeanPostProcessor的postProcessBeforeInitialization方法
- (3)調(diào)用bean實(shí)例的初始化方法
- (4)調(diào)用BeanPostProcessor的postProcessAfterInitialization方法
注意:實(shí)測(cè)項(xiàng)目中只能有一個(gè)BeanPostProcessor的實(shí)現(xiàn)虑乖,當(dāng)出現(xiàn)多個(gè)時(shí),只是加載了一次晾虑。注意此點(diǎn)疹味,避免踩坑。
背景
當(dāng)我們需要根據(jù)不同的狀態(tài)調(diào)用接口不同的實(shí)現(xiàn)時(shí)帜篇,可以使用工廠模式實(shí)現(xiàn)糙捺。而之前最常用的方式就是通過多個(gè)if else的靜態(tài)工廠方式進(jìn)行處理。
進(jìn)入主題
通過BeanPostProcessor實(shí)現(xiàn)相同接口的不同實(shí)現(xiàn)bean的工廠笙隙。
1 定義一個(gè)注解继找,用于標(biāo)記不同的實(shí)現(xiàn)bean
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Component
public @interface OrderStatusProcessor {
/**
* 狀態(tài)枚舉
*/
OrderStatusEnum status() ;
}
狀態(tài)枚舉定義:
@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 {
/**
* 訂單編號(hào)
*/
private Long orderId;
/**
* 訂單狀態(tài):1-新建;2-完成逃沿;3-取消婴渡;
*/
private Integer orderStatus;
}
3 自定義處理器實(shí)現(xiàn),并用自定義的注解進(jìn)行標(biāo)識(shí)
@Slf4j
@OrderStatusProcessor(status = OrderStatusEnum.CREATE)
public class StatusCreateProcessor implements StatusProcessor {
@Override
public boolean action(OrderInfo orderInfo) {
log.info("訂單==>編號(hào):({}),執(zhí)行({})操作凯亮。",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("訂單==>編號(hào):({}),執(zhí)行({})操作边臼。",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("訂單==>編號(hào):({}),執(zhí)行({})操作。",orderInfo.getOrderId(),OrderStatusEnum.getEnumByCode(orderInfo.getOrderStatus()).getStatusDesc());
return false;
}
}
4 通過BeanPostProcessor實(shí)現(xiàn)對(duì)bean后置處理假消,對(duì)注解的類型bean對(duì)象進(jìn)行緩存
@Slf4j
@Component
public class StatusProcessRegistry implements BeanPostProcessor {
/**
* 第一層key是訂單狀態(tài)柠并。
* 第二層是對(duì)應(yīng)的處理器。
*/
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 狀態(tài)機(jī)引擎處理類定義
@AllArgsConstructor
@Component
public class OrderOperatorEngine {
private final StatusProcessRegistry statusProcessRegistry;
public boolean operate(OrderInfo orderInfo) throws Exception{
// 獲取當(dāng)前事件處理器
StatusProcessor statusProcessor = statusProcessRegistry.acquireStatusProcess(orderInfo.getOrderStatus());
if (statusProcessor == null) {
throw new Exception("NOT_FOUND_PROCESSOR");
}
// 執(zhí)行處理邏輯
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--->訂單==>編號(hào):(10001),執(zhí)行(完成)操作富拗。
###|||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--->訂單==>編號(hào):(10001),執(zhí)行(新建)操作臼予。
###|||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--->訂單==>編號(hào):(10001),執(zhí)行(取消)操作。
到此這篇關(guān)于詳解使用Spring的BeanPostProcessor優(yōu)雅的實(shí)現(xiàn)工廠模式的文章就介紹到這了,希望能給你帶來一些幫助和啟發(fā)啃沪!