package org.spring.boot.example.config;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public final class RootConfig implements InitializingBean {
public RootConfig() {
System.out.println("============");
}
@Autowired
private ApplicationContext applicationContext;
@Bean
public MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor() {
return new MyBeanDefinitionRegistryPostProcessor();
}
@Override
public void afterPropertiesSet() throws Exception {
String id = applicationContext.getId();
System.out.println("id = " + id);
}
}
package org.spring.boot.example.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
以上这个类存在两个问题,你知道吗?又知道如何解决吗?以及其中的问题。
首先,对于@Configuration
注解的类不可以包含final关键字,通常IDE会警告,原因在与包含@Configuration
的类会被增强,而所谓的增强其实就是生成CGLIB动态代理,而CGLIB动态代理就是在运行时生成一个目标的子类,而加有final的类是不能够被继承的,没有子类。去掉final关键字。
其次,运行时会报空指针异常。如下图所示
处理方法也简单,添加一个static关键字,如下图所示
在@Configuration
注解的类中定义了包含@Bean
的方法用于配置相关的bean,但是首先这个@Configuration
注解的类也会作为一个bean,称为factoryBean,如果这个方法是静态的,在实例化对应的类的时候不需要实例化这个factoryBean,因为静态方法的反射不需要对象,而非静态方法是需要对象的,所谓非静态方法对应的bean的实例化就会导致对应factoryBean的实例化。在这个案例当中,MyBeanDefinitionRegistryPostProcessor
实例化的非常早,远在绝大多数的BeanPostProcessor
的实例化之前。而MyBeanDefinitionRegistryPostProcessor
的实例化导致RootConfig
类型Bean的创建,在此过程中,已经实例化的BeanPostProcessor
类型Bean会起作用,而其中用于处理@Autowired
注解的AutowiredAnnotationBeanPostProcessor
并没有实例化,所以此处的applicationContext并不会被注入。也就说,由于MyBeanDefinitionRegistryPostProcessor
实例化导致了RootConfig
的提前实例化和初始化,通过添加static
就可以避免了。
Make sure that the dependencies you inject that way are of the simplest kind only. @Configuration classes are processed quite early during the initialization of the context, and forcing a dependency to be injected this way may lead to unexpected early initialization. Whenever possible, resort to parameter-based injection, as in the preceding example.
Also, be particularly careful with BeanPostProcessor and BeanFactoryPostProcessor definitions through @Bean. Those should usually be declared as static @Bean methods, not triggering the instantiation of their containing configuration class.Otherwise, @Autowired and @Value may not work on the configuration class itself,since it is possible to create it as a bean instance earlier than AutowiredAnnotationBeanPostProcessor.