Conditional实现bean按需加载
Conditional注解实现bean按需加载
最后更新于
Conditional注解实现bean按需加载
最后更新于
公司有一些项目是对外的,同样的功能在不同的客户有不同的要求;比如A客户要求支付使用微信支付,B客户要求支付使用支付宝。诸如此类的诉求有很多,需要能根据客户的需求做一些定制化。目前针对此类需求主要是通过不同代码分支来控制;随着客户的增多,代码控制又是一个比较头疼的问题。因此希望寻找一种更便捷的方式来解决。
通过技术实现一套代码应对不同客户的不同诉求。本文以支付为例
针对上诉诉求,很容易想到代理模式和策略模式,具体UML参考如下
1、支付入口在IPayService(PayProxy)
2、实际支付逻辑在IPayComponent(WxPayComponent/ZfbPayComponent)
3、具体使用IPayComponent哪个实现有PayComponentStrategy控制
4、每个具体的PayComponent有自己的依赖和配置(WxPayConf/ZfbPayConf)
在实际交付过程中,如果PayComponent具体实现及其依赖实际上只需要实例化一个;例如如果使用微信支付,那么ZfbPayComponent和ZfbPayConf这两个bean是不需要的;那么如何做到这个呢?
在Spring boot中,我们通常在class上加上@Component或者@Configurationg或者@Service注解实现bean的自动加载,这里我们去掉这些注解这些bean就不会自动加载了;去掉之后如何按需加载呢?这里可以参考Springboot的提供的EanbleXxx注解,再搭配一个Configuration注解即可
这样,在启动类上加上@EnableWxPay即可加载微信支付相关的bean了,同理可以制作一个@EnableZfbPay加载支付宝支付相关的bean了。到此问题基本解决
但是有个小小的点,通常来说,Controller我们不喜欢放到Configuration类中控制,有没有办法让Controller也实现按需加载呢,答案是有的,通过@Conditional系列注解来做,参考代码如下
然后看WxPayBeanCondition实现
可以看到condition的实现有判断分成2部分
1、factory.containsBean("wxPayComponent")
2、clazz.getAnnotation(EnableWxPay.class) != null
这是因为spring扫描的时候会优先扫描@Component(@Service,@Controller等)注解的class,如果是Configuration中定义的bean,在@Component注解表示的类被加载的时候,Configuration中定义的bean还没加载,此时走方式1判断会返回false,所以需要增加方式2
对于Conditional方式,spring boot也有一些内置的注解可以使用,比如@ConditionalOnBean、@ConditionalOnClass、@ConditionalOnProperty等等,此处不做介绍