赞
踩
目录
2、ConfigurationClassPostProcessor后置处理器解析
后置处理器在 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<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
-
- Set<String> processedBeans = new HashSet<>();
- // 1-首先调用BeanDefinitionRegistryPostProcessor的后置处理器
- if (beanFactory instanceof BeanDefinitionRegistry) {
- BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
- List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
- List<BeanDefinitionRegistryPostProcessor> 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<BeanDefinitionRegistryPostProcessor> 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);
- }
- // 省略大段代码...
- }
ConfigurationClassPostProcessor后置处理器会被优先加载,因为ConfigurationClassPostProcessor 同时实现了 BeanDefinitionRegistry 和 PriorityOrdered 两个接口,该类的继承关系图如下:
ConfigurationClassPostProcessor后置处理器加载流程图
doProcessConfigurationClass()源码如下:
- protected final SourceClass doProcessConfigurationClass(
- ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> 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<AnnotationAttributes> 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<BeanDefinitionHolder> 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<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
- for (String resource : resources) {
- String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
- configClass.addImportedResource(resolvedResource, readerClass);
- }
- }
-
- // 处理 @Bean methods 获取到配置类中所有标注了@Bean的方法
- Set<MethodMetadata> 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<BeanDefinitionHolder> doScan(String... basePackages) {
- Assert.notEmpty(basePackages, "At least one base package must be specified");
- // 创建beanDefinitions用于保存扫描后生成的bean定义对象
- Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
- // 循环包路径集合
- for (String basePackage : basePackages) {
- // 找到候选的Components->真正的扫描和加载内容
- Set<BeanDefinition> 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后置处理器的大致流程就介绍完了,当中还有很多处理细节,可以参照整个流程再详细拆分和解读。
在项目中,通常都会配置一个或者多个加了@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获取。
(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 解析流程
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。