1

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


linyb极客之路
336 声望193 粉丝