Spring内置后置PostProcess处理器深度剖析

Spring内置后置PostProcess处理器深度剖析,第1张

目录 

1、后置PostProcess的调用

2、ConfigurationClassPostProcessor后置处理器解析

3、@Configuration注解加与不加的区别

4、重复beanName的覆盖原则


1、后置PostProcess的调用

后置处理器在 new AnnotatedBeanDefinitionReader() 时加载,在 register(componentClasses) 中注册,在 refresh() 方法中被调用

public AnnotationConfigApplicationContext(Class... componentClasses) {
		// 1-生成三大组件:BeanFactory、BeanDefinitionReader、BeanDefinitionScanner
		this();
		// 2-注册BeanDefinition——>registerBeanDefinition
		register(componentClasses);
		// 3-Spring重点->Bean生命周期的实现
		refresh();
	}

在 refresh() 方法中 invokeBeanFactoryPostProcessors(beanFactory) 真正调用后置处理器

其过程图如下:

后置处理器的加载流程代码:

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {

		Set processedBeans = new HashSet<>();
		// 1-首先调用BeanDefinitionRegistryPostProcessor的后置处理器
		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List regularPostProcessors = new ArrayList<>();
			List registryProcessors = new ArrayList<>();
			// beanFactoryPostProcessors ->内容需要手动添加,一般为空
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			// 不要在这里初始化FactoryBeans:我们需要让所有常规bean保持未初始化状态,以便让bean factory后处理器应用于它们!
			// 在实现PriorityOrdered、Ordered和其他功能的BeanDefinitionRegistryPostProcessor之间进行分离。
			List currentRegistryProcessors = new ArrayList<>();
		
			// 首先,调用实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessors
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				// 判断是否实现了PriorityOrdered接口 ->优先调用
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					// beanFactory.getBean进行实例化
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			// (1)对PostProcessors进行排序
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			// (2)汇总PostProcessors
			registryProcessors.addAll(currentRegistryProcessors);
			// (3)调用PostProcessors
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// 接下来,调用实现了Ordered接口的BeanDefinitionRegistryPostProcessors
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				// 排除processedBeans中已经调用的PostProcessors
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// 最后,调用所有其他的BeanDefinitionRegistryPostProcessors
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					// 排除在之前两次processedBeans中已经调用的PostProcessors
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				currentRegistryProcessors.clear();
			}

			// 调用实现了BeanDefinitionRegistryPostProcessor的接口,同时也实现了BeanFactoryPostProcessor的方法
            // ConfigurationAnnotationProcessor 在这里会被再次调用
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			// 手动定义部分的BeanFactoryPostProcessors ->regularPostProcessors
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			// 2-当前的beanFactory没有实现BeanDefinitionRegistry 直接调用
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}
		// 省略大段代码...
	}
2、ConfigurationClassPostProcessor后置处理器解析

ConfigurationClassPostProcessor后置处理器会被优先加载,因为ConfigurationClassPostProcessor 同时实现了 BeanDefinitionRegistry 和 PriorityOrdered 两个接口,该类的继承关系图如下:

ConfigurationClassPostProcessor后置处理器加载流程图

 doProcessConfigurationClass()源码如下:

protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate filter)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			processMemberClasses(configClass, sourceClass, filter);
		}

		// 处理@propertySource注解
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// 处理@ComponentScan注解
		Set componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			// 循环解析AnnotationAttributes
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform(执行) the scan immediately(立即进行扫描)
				Set scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// 检查扫描的定义集是否有任何进一步的配置类,并在需要时进行递归解析
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// 处理 @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

		// 处理 @ImportResource annotations
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		// 处理 @Bean methods 获取到配置类中所有标注了@Bean的方法
		Set beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// 处理配置类接口
		processInterfaces(configClass, sourceClass);

		// 处理配置类的父类
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				return sourceClass.getSuperClass();
			}
		}
		return null;
	}

扫描和注册源码

protected Set doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		// 创建beanDefinitions用于保存扫描后生成的bean定义对象
		Set beanDefinitions = new LinkedHashSet<>();
		// 循环包路径集合
		for (String basePackage : basePackages) {
			// 找到候选的Components->真正的扫描和加载内容
			Set candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				// 处理@Autowire注解相关
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				// 把解析出来的组件bean定义注册到IOC容器中
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					// 注册
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

到此,整个ConfigurationClassPostProcessor后置处理器的大致流程就介绍完了,当中还有很多处理细节,可以参照整个流程再详细拆分和解读。

3、@Configuration注解加与不加的区别

在项目中,通常都会配置一个或者多个加了@Configuration注解的配置类,那么@Configuration这个注解有什么用呢?

public class MyConfig {
	@Bean("person")
	public Person getPersonInstance(){
		return new Person("XiaoHong", "女", getWoMenInstance());
	}

	@Bean("woMen")
	public WoMen getWoMenInstance(){
		return new WoMen();
	}
}

执行下边的代码,会发现当不加@Configuration注解时,Person、WoMen 两个类还是会被实例化,spring环境也可以正常运行,但是WoMen 被实例化了两次。

public class MainStat {
	public static void main(String[] args) {
		//加载配置文件,生产Bean
		ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
	}
}

 给MyConfig加上@Configuration注解后,查看执行结果

@Configuration // 如果不加@Configuration,WoMen会实例化两次
public class MyConfig {
	@Bean("person")
	public Person getPersonInstance(){
		return new Person("XiaoHong", "女", getWoMenInstance());
	}

	@Bean("woMen")
	public WoMen getWoMenInstance(){
		return new WoMen();
	}
}

总结:当不加@Configuration注解的时候,WoMen会被实例化两次,这违背了spring默认单例的设计原则,当加上@Configuration注解的时候,WoMen只被实例化了一次。 

源码分析:

当Spring解析MyConfig的时候,会给它的一个属性标识为Full,表明它是一个全注解类。

然后在我们调用ConfigurationClassPostProcessor.postProcessBeanFactory()方法的时候会去判断bean工厂当中是否有bean需要进行cglib代理。

在ConfigurationClassPostProcessor.enhanceConfigurationClasses()方法中

Cglib代理主要是对自定义的方法进行拦截增强;当执行MyConfig中的方法的时候会去执行Cglib代理类中的代理方法,主要就是CallBacks中的方法。

在 BeanMethodInterceptor.intercept()方法中

isCurrentlyInvokedFactoryMethod(beanMethod)) 会判断给定的方法和正在调用方法是否相同;如果相同就调用父类的方法进行new(当前Bean正是需要去创建的Bean);如果不同就调用beanFactory.getBean()获取(先从IOC容器中去获取,避免重复创建)。 

总结:加上@Configuration注解,Spring给类加上了Cglib代理。在执行配置类的方法时,会执行Cglib代理类中的方法,其中有一个非常重要的判断,当给定的方法和正在调用的方法是同一个方法时,会执行父类的方法new一个新的实例(Cglib代理基于继承);当给定的方法和正在调用的方法不是同一个方法时,会先调用beanFactory.getBean获取。

4、重复beanName的覆盖原则

(1)如果在同一个@ComponentScan下有相同名称的Bean,那么Spring会报错

如,把以下两个类都声明为"person",都是通过@ComponentScan来解析@Component注解,那么启动Spring时会报错

@Component("person")
@ComponentScan("com.swadian.task")
public class Person {
	private String name;
	private String sex;
}
@Component("person")
@ComponentScan("com.swadian.task")
public class WoMen {
	private String name;
	private int age;
}

启动Spring,会报如下错误

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'person' for bean class [com.swadian.task.WoMen] conflicts with existing, non-compatible bean definition of same name and class [com.swadian.task.Person]

(2)如果通过@Component注解定义一个Bean,然后通过Java配置类(@Configuration类)注解@Bean定义一个相同名称的Bean,那么@Bean定义的Bean最终会覆盖@Component注解定义的同名Bean。

@Component
public class Person {
	private String name;
	private String sex;
}

以上Bean定义最终会被@Configuration类中的同名Bean定义覆盖

@Configuration 
public class MyConfig {
	@Bean("person") // 最终覆盖@Component定义的同名Bean
	public Person getPersonInstance(){
		return new Person();
	}
}

原因:@ComponentScan注解先会被解析,@Bean注解后解析,所以后者会覆盖前者,在Spring中Bean定义是默认可以覆盖的

ConfigurationClassPostProcessor 解析流程

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/874387.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存