spring 核心后置处理器-ConfigurationClassPostProcessor

此篇博客由于能力有限,虽然有些讲不全,希望对你有所帮助。
先看下该处理器的继承图吧

这个工具类中有两个很重要的属性org.springframework.context.annotation.ConfigurationClassUtils

	private static final String CONFIGURATION_CLASS_FULL = "full";

	private static final String CONFIGURATION_CLASS_LITE = "lite";

这两个属性怎么解释呢

full 满的,我们可以理解为全部 而spring 中对应的 lite也可以理解为 一部分的

那么我们的主角@Configuration注解和这两个属性有什么关系呢,为什么在配置类中加与不加都是spring环境生效呢

我们先看环境中的代码

@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");

	}

}

我们进入该类的这段代码断点进去调试

	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));
	}

正常情况下这段代码只会进else if 由于spring设计的严谨性,这段代码会解析注册列表中(BeanDefinition)的所有bd,将检测到带有@Configuration注解的类放到另外一个bd集合中进入下次解析。在检测中会将带有该注解的类设置一个属性,就是isFull(简写),没有的就是lite(也间歇)属性,我们跑完到下一个断点解析

扫描二维码关注公众号,回复: 12977313 查看本文章

该类源码中第二次解析

	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;
		}

这一段代码可以这样理解将带有@Configuration的类放到一个map中,如果为空就直接返回,如果不为空就进入下面的代码,

下面的代码就不帖出来了,等下直接看结果我们就知道了,断点回到测试类。我们看有什么彩蛋

对,cglib代理。如果没加就不是了,直接看结果

为什么呢,这就是spring严谨性的厉害之处之一了(单例性原则)。我们先看下面的一段代码

看下初始化的环境代码

@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);
	}

}

加不加该注解,打印的结果都是init-user,如果改一下呢

@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();
	}
}
//此结果会打印两次

但是有个问题,打印的两个hashcode都是一样的,一样是单例的对象

由于水平有限,真正原因也不得而知

两个hashcode一样可能是因为spring在创建对象的时候会先从缓存的单例池(默认是单例,也可以理解为单例池)中拿一次(从缓存的单例池不知道是不是解决循环依赖的问题)第一次,再从真正的单例池去拿(bean的生命周期调用链是这样的步骤)

能力问题,只能后期再补了,也希望对你们有帮助,spring源码太难看了,由于没有证明过,网上的解释也不知道是不是对的(网上的帖子很乱,想找到一个正确的很难找到)。

猜你喜欢

转载自blog.csdn.net/qq_38108719/article/details/100592018