Spring core post processor-ConfigurationClassPostProcessor

Due to the limited ability of this blog, although some of it is incomplete, I hope it will be helpful to you.
Let's take a look at the inheritance diagram of the processor

There are two very important properties in this tool class org.springframework.context.annotation.ConfigurationClassUtils

	private static final String CONFIGURATION_CLASS_FULL = "full";

	private static final String CONFIGURATION_CLASS_LITE = "lite";

How to explain these two attributes

full, we can understand it as all and the corresponding lite in spring can also be understood as a part

So what is the relationship between our protagonist @Configuration annotation and these two attributes? Why does the spring environment take effect when adding or not adding in the configuration class?

Let's look at the code in the environment first

@Configuration
//@Import(TestImportSelector.class)
//@TestImportSelectorAnno
//@TestBeanFactoryPostProcessorAnno
@ComponentScan("org.springframework.test.main.*")
public class ScanConfig {
}

//测试

public class MainDemo {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac =
				new AnnotationConfigApplicationContext(ScanConfig.class);
		ScanConfig scanConfig = (ScanConfig) ac.getBean("scanConfig");

	}

}

Let's enter the breakpoint of this code of this class to debug

	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		int factoryId = System.identityHashCode(beanFactory);
		if (this.factoriesPostProcessed.contains(factoryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + beanFactory);
		}
		this.factoriesPostProcessed.add(factoryId);
		if (!this.registriesPostProcessed.contains(factoryId)) {
			// BeanDefinitionRegistryPostProcessor hook apparently not supported...
			// Simply call processConfigurationClasses lazily at this point then.
            //断点调式
			processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
		}
		//给配置类产生cglib代理。加了@Configuration注解的
		enhanceConfigurationClasses(beanFactory);
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}

 

Under normal circumstances, this code will only enter else if due to the rigor of spring design, this code will parse all bd in the registration list (BeanDefinition), and put the detected class with @Configuration annotations into another bd collection Go to the next analysis. In the detection, an attribute of the class with the annotation will be set, which is isFull (shorthand), and the one that is not is the lite (also intermittent) attribute. We run to the next breakpoint analysis

The second analysis in this type of source code

	public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
		Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
		for (String beanName : beanFactory.getBeanDefinitionNames()) {
			BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
				if (!(beanDef instanceof AbstractBeanDefinition)) {
					throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
							beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
				}
				else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
					logger.info("Cannot enhance @Configuration bean definition '" + beanName +
							"' since its singleton instance has been created too early. The typical cause " +
							"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
							"return type: Consider declaring such methods as 'static'.");
				}
				configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
			}
		}
		if (configBeanDefs.isEmpty()) {
			// nothing to enhance -> return immediately
			return;
		}

This piece of code can be understood in this way. Put the class with @Configuration in a map, if it is empty, it will return directly, if it is not empty, enter the following code,

The following code will not be posted, and we will know the result when we look at the result directly. The breakpoint returns to the test class. Let's see what easter eggs

 

Yes, cglib proxy. If you don’t add it, it’s not the case, just look at the result

Why? This is one of the strong points of spring rigor (singleton principle). Let's first look at the following piece of code

Look at the initialized environment code

@Configuration
@ComponentScan("org.springframework.test.main.*")
public class ScanConfig {

	@Bean
	public Test getTestBean(){
		return new Test();
	}

	@Bean
	public User getUserBean(){
		return new User();
	}
}

public class Test {

	public Test(){}
}

public class User {

	public User(){
		System.out.println("init-user");
	};
}

public class MainDemo {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac =
				new AnnotationConfigApplicationContext(ScanConfig.class);
	}

}

If this comment is added or not, the printed result is all init-user, if you change it

@Configuration
@ComponentScan("org.springframework.test.main.*")
public class ScanConfig {

	@Bean
	public Test getTestBean(){
		getUserBean();
		return new Test();
	}

	@Bean
	public User getUserBean(){
		return new User();
	}
}
//cglib此结果会打印一次.加入static关键字会失效

@ComponentScan("org.springframework.test.main.*")
public class ScanConfig {

	@Bean
	public Test getTestBean(){
		getUserBean();
		return new Test();
	}

	@Bean
	public User getUserBean(){
		return new User();
	}
}
//此结果会打印两次

But there is a problem. The two hashcodes printed are the same, and the same is the object of a singleton.

Due to the limited level, the real reason is not known

The two hashcodes may be the same because spring will first take it from the cached singleton pool (the default is a singleton, or it can be understood as a singleton pool) when creating an object (from the cached singleton pool, I don’t know if it is a solution. Circular dependency problem) For the first time, take it from the real singleton pool (the life cycle call chain of the bean is such a step)

The ability problem can only be fixed later, and I hope it will help you. The spring source code is too ugly. Since there is no proof, I don’t know if the online explanation is correct (the online posts are messy, I want to find a correct one. hard to find).

Guess you like

Origin blog.csdn.net/qq_38108719/article/details/100592018