首先,在讲解 BeanPostProcessor
的应用之前,我们肯定得先要知道 BeanPostProcessor
是什么,以及它的特性是什么。那么,我们先来看一看它的源码:
// org.springframework.beans.factory.config.BeanPostProcessor
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
可以看到,BeanPostProcessor
接口中定义了两个方法,它们的作用分别是(注意到它们发挥作用的时间点与这两个方法的名字有关):
postProcessBeforeInitialization
: bean 初始化方法调用前被调用postProcessAfterInitialization
: bean 初始化方法调用后被调用
注意到,这两个方法的执行时机都是在 bean 完成实例化之后,且会作为参数传递到方法中(bean 参数即需要操作的容器 bean 实例;beanName 即 bean 实例的名称)。
理解了 BeanPostProcessor
的接口定义之后,我们来看一个它在业务系统中的经典用法。
我们可以思考一个优惠券结算(或核销)的场景:业务系统中通常会定义多种优惠券,比如满减券、满返券、折扣券等等;虽然它们的使用规则都不相同,但是它们的处理接口定义却是一样的。此时,我们就可以通过 BeanPostProcessor
接口来聚合这些优惠券的 “Process Bean”,以避免每一次都要注入所有的优惠券处理器 Bean。下面,我们就来通过代码实现这个功能(特性)。
优惠券枚举类
定义一个枚举类,包含我们的业务系统所支持的所有优惠券类型(可以根据需要自行扩展),如以下代码所示:
@Getter
@AllArgsConstructor
public enum CouponTypeEnum {
MAN_JIAN("man_jian", "满减券"),
MAN_FAN("man_fan", "满返券"),
ZHE_KOU("zhe_kou", "折扣券"),
;
private final String type;
private final String description;
}
优惠券处理器注解
这个注解用于标注在优惠券处理器类上,用于指定优惠券处理器的类型,即这个处理器是用于处理哪一类优惠券的。如以下代码所示:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CouponHandlerProcessor {
/** 优惠券类型 */
CouponTypeEnum value();
}
优惠券处理器接口定义及各个实现类
我们的核心实现是优惠券处理器,它们都有着相同的接口定义,并通过各个实现类达到不同的处理效果;且我们通过注解和枚举类标识出这个 “Service Bean” 是用于处理哪一类优惠券的(可以根据需要自行扩展,例如一个处理器可以处理多类优惠券)。如以下代码所示:
// 优惠券处理器服务接口定义
public interface ICouponHandlerService {
void process(String coupon);
}
// 满返券优惠券处理器
@Slf4j
@Service
@CouponHandlerProcessor(CouponTypeEnum.MAN_FAN)
public class ManFanCouponHandlerServiceImpl implements ICouponHandlerService {
@Override
public void process(String coupon) {
log.info("....");
}
}
// 满减券优惠券处理器
@Slf4j
@Service
@CouponHandlerProcessor(CouponTypeEnum.MAN_JIAN)
public class ManJianCouponHandlerServiceImpl implements ICouponHandlerService {
@Override
public void process(String coupon) {
log.info("....");
}
}
// 折扣券优惠券处理器
@Slf4j
@Service
@CouponHandlerProcessor(CouponTypeEnum.ZHE_KOU)
public class ZheKouCouponHandlerServiceImpl implements ICouponHandlerService {
@Override
public void process(String coupon) {
log.info("....");
}
}
优惠券处理器工厂
工厂的功能是当你需要哪一种优惠券处理器的时候,就可以通过工厂的方法给到你。我们先来贴出代码,再去解释这里的实现思想。
@Slf4j
@Component
public class CouponHandlerFactory implements BeanPostProcessor {
private static final Map<CouponTypeEnum, ICouponHandlerService> serviceMap =
new ConcurrentHashMap<>();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof ICouponHandlerService) {
// 获取对象运行时对象类
Class<?> clazz = bean.getClass();
// 获取自定义的注解
CouponHandlerProcessor annotation = clazz.getAnnotation(CouponHandlerProcessor.class);
// TODO 是不是可以对 bean 进行校验
// 绑定对应关系
serviceMap.put(annotation.value(), (ICouponHandlerService) bean);
log.info("....");
}
return bean;
}
public ICouponHandlerService getHandler(CouponTypeEnum type) {
return serviceMap.get(type);
}
}
可以看到,我们所实现的优惠券处理器工厂类实现了 BeanPostProcessor
,且在 postProcessBeforeInitialization
方法中过滤 IOC 容器中的每一个 bean,获取到 bean 的 CouponHandlerProcessor
注解,识别处理器类型,放到 map 中。那么,当需要某一种优惠券处理器时,就可以通过指定类型返回对应的处理器。