foreword
The material for this article comes from a question from a reader who has seen a blog post I wrote before talking about how to register third-party services into the spring container of our project . It happened that he also had a similar requirement in his project, so he adopted the third method introduced in my article.
调用beanFactory.registerSingleton()
At the beginning, the project was running fine. Later, he used AOP in this third-party service and found that AOP never took effect. So he messaged me. Let’s talk about this topic today, why the bean registered with registerSingleton() cannot make AOP take effect
root of the problem
The registerSingleton() method directly stores the bean in the singleton pool.
If you are familiar with the life cycle of beans, you should know that beans may be stored in the singleton pool after a series of post-processors. So this bean may be enhanced, which of course includes AOP enhancement
Using registerSingleton() is equivalent to taking a shortcut directly, without going through the post-processor, and directly storing it in the singleton pool in one step. If the third-party service comes out directly through new, it is an ordinary object, so after being injected into the IOC container, it is just an ordinary bean without any enhancement.
bug fix
Option 1: Instead of using registerSingleton(), use the BeanDefinition registration method
The essence of this method is to let the object go through the life cycle of the bean completely.
Example:
@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);
}
}
Option 2. Use registerSingleton(), but the injected object is not created by new, but directly injected into the AOP proxy object
Mainly use AOP's proxy api: AnnotationAwareAspectJAutoProxyCreator
Example
@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);
}
}
Summarize
For the above two schemes, scheme one is recommended. Because the solution has gone through the bean life cycle completely, this means that you can get various enhancements provided by spring. The second solution is more like hard-coding. If you want to use other enhanced functions of spring later, you must also call other APIs. However, if it can be determined that the business will not use the various extension functions provided by spring. Option two is also possible
demo link
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-registerSingleton-aop-invalid
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。