本文的素材来自读者的一个问题,他看过我之前写的一篇博文聊聊如何把第三方服务注册到我们项目的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);
}
}