前言
本文的素材来自读者的一个问题,他看过我之前写的一篇博文聊聊如何把第三方服务注册到咱们我的项目的 spring 容器中。刚好他我的项目中也有相似这样的一个需要,他就采纳我文中介绍的第三种办法
调用 beanFactory.registerSingleton()
一开始我的项目运行得还能够,前面他在这个第三方服务中应用 AOP,发现 AOP 始终没有失效。于是他就给我留言了。明天就来聊一下这个话题, 为什么应用 registerSingleton() 注册的 bean,无奈使 AOP 失效
问题本源
registerSingleton() 这个办法间接将 bean 寄存到单例池外面了。
如果对 bean 的生命周期有理解的敌人,应该会晓得,bean 可能会通过一系列的后置处理器后,再寄存到单例池外面。因而这个 bean 可能是会被加强的,其中当然包含通过 AOP 加强
而应用 registerSingleton() 相当于是间接走捷径,不通过后置处理器,一步到位间接寄存到单例池中。如果第三方服务是间接通过 new 进去的,就是一个一般的对象,因而注入到 IOC 容器后,也只是一个一般的 bean,并没有任何加强
问题修复
计划一:不应用 registerSingleton(),而是应用 BeanDefinition 注册形式
这种形式实质是让这个对象残缺经验了 bean 的生命周期
示例:
@Configuration
public class HelloServiceConfiguration implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
beanDefinition.setBeanClass(HelloService.class);
HelloServiceProperties properties = new HelloServiceProperties();
properties.setBeanName("helloService");
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,properties);
defaultListableBeanFactory.registerBeanDefinition(properties.getBeanName(),beanDefinition);
}
}
计划二、应用 registerSingleton(),但注入的对象不是用 new 进去的,而是间接注入 AOP 代理对象
次要利用 AOP 的代理 api:AnnotationAwareAspectJAutoProxyCreator
示例
@Configuration
public class HelloServiceWithProxyConfiguration implements BeanFactoryAware, InitializingBean {
private BeanFactory beanFactory;
@Autowired
private AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}
@Override
public void afterPropertiesSet() throws Exception {DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory)beanFactory;
HelloServiceProperties properties = new HelloServiceProperties();
properties.setBeanName("helloService");
HelloService helloServicePrxoy = (HelloService) annotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization(new HelloService(properties), "helloService$$Prxoy");
defaultListableBeanFactory.registerSingleton(properties.getBeanName(),helloServicePrxoy);
}
}
总结
以上两种计划,倡议应用计划一。因为计划一残缺经验过 bean 的生命周期,这就意味着能够获取 spring 提供的各种加强性能。计划二反而更像是硬编码进去,如果前面要应用 spring 的其余加强的性能,就还必须调用其余 API。不过如果能够确定业务不会应用 spring 提供的各种扩大性能。计划二也是能够的
demo 链接
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-registerSingleton-aop-invalid