当前位置:   article > 正文

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

postprrocess

目录 

1、后置PostProcess的调用

2、ConfigurationClassPostProcessor后置处理器解析

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

4、重复beanName的覆盖原则


1、后置PostProcess的调用

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

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

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

其过程图如下:

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

  1. public static void invokeBeanFactoryPostProcessors(
  2. ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
  3. Set<String> processedBeans = new HashSet<>();
  4. // 1-首先调用BeanDefinitionRegistryPostProcessor的后置处理器
  5. if (beanFactory instanceof BeanDefinitionRegistry) {
  6. BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
  7. List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
  8. List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
  9. // beanFactoryPostProcessors ->内容需要手动添加,一般为空
  10. for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
  11. if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
  12. BeanDefinitionRegistryPostProcessor registryProcessor =
  13. (BeanDefinitionRegistryPostProcessor) postProcessor;
  14. registryProcessor.postProcessBeanDefinitionRegistry(registry);
  15. registryProcessors.add(registryProcessor);
  16. }
  17. else {
  18. regularPostProcessors.add(postProcessor);
  19. }
  20. }
  21. // 不要在这里初始化FactoryBeans:我们需要让所有常规bean保持未初始化状态,以便让bean factory后处理器应用于它们!
  22. // 在实现PriorityOrdered、Ordered和其他功能的BeanDefinitionRegistryPostProcessor之间进行分离。
  23. List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
  24. // 首先,调用实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessors
  25. String[] postProcessorNames =
  26. beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  27. for (String ppName : postProcessorNames) {
  28. // 判断是否实现了PriorityOrdered接口 ->优先调用
  29. if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
  30. // beanFactory.getBean进行实例化
  31. currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
  32. processedBeans.add(ppName);
  33. }
  34. }
  35. //1)对PostProcessors进行排序
  36. sortPostProcessors(currentRegistryProcessors, beanFactory);
  37. //2)汇总PostProcessors
  38. registryProcessors.addAll(currentRegistryProcessors);
  39. //3)调用PostProcessors
  40. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
  41. currentRegistryProcessors.clear();
  42. // 接下来,调用实现了Ordered接口的BeanDefinitionRegistryPostProcessors
  43. postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  44. for (String ppName : postProcessorNames) {
  45. // 排除processedBeans中已经调用的PostProcessors
  46. if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
  47. currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
  48. processedBeans.add(ppName);
  49. }
  50. }
  51. sortPostProcessors(currentRegistryProcessors, beanFactory);
  52. registryProcessors.addAll(currentRegistryProcessors);
  53. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
  54. currentRegistryProcessors.clear();
  55. // 最后,调用所有其他的BeanDefinitionRegistryPostProcessors
  56. boolean reiterate = true;
  57. while (reiterate) {
  58. reiterate = false;
  59. postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  60. for (String ppName : postProcessorNames) {
  61. // 排除在之前两次processedBeans中已经调用的PostProcessors
  62. if (!processedBeans.contains(ppName)) {
  63. currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
  64. processedBeans.add(ppName);
  65. reiterate = true;
  66. }
  67. }
  68. sortPostProcessors(currentRegistryProcessors, beanFactory);
  69. registryProcessors.addAll(currentRegistryProcessors);
  70. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
  71. currentRegistryProcessors.clear();
  72. }
  73. // 调用实现了BeanDefinitionRegistryPostProcessor的接口,同时也实现了BeanFactoryPostProcessor的方法
  74. // ConfigurationAnnotationProcessor 在这里会被再次调用
  75. invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
  76. // 手动定义部分的BeanFactoryPostProcessors ->regularPostProcessors
  77. invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
  78. }
  79. else {
  80. // Invoke factory processors registered with the context instance.
  81. // 2-当前的beanFactory没有实现BeanDefinitionRegistry 直接调用
  82. invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
  83. }
  84. // 省略大段代码...
  85. }

2、ConfigurationClassPostProcessor后置处理器解析

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

ConfigurationClassPostProcessor后置处理器加载流程图

 doProcessConfigurationClass()源码如下:

  1. protected final SourceClass doProcessConfigurationClass(
  2. ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
  3. throws IOException {
  4. if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
  5. processMemberClasses(configClass, sourceClass, filter);
  6. }
  7. // 处理@propertySource注解
  8. for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
  9. sourceClass.getMetadata(), PropertySources.class,
  10. org.springframework.context.annotation.PropertySource.class)) {
  11. if (this.environment instanceof ConfigurableEnvironment) {
  12. processPropertySource(propertySource);
  13. }
  14. else {
  15. logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
  16. "]. Reason: Environment must implement ConfigurableEnvironment");
  17. }
  18. }
  19. // 处理@ComponentScan注解
  20. Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
  21. sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
  22. if (!componentScans.isEmpty() &&
  23. !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
  24. // 循环解析AnnotationAttributes
  25. for (AnnotationAttributes componentScan : componentScans) {
  26. // The config class is annotated with @ComponentScan -> perform(执行) the scan immediately(立即进行扫描)
  27. Set<BeanDefinitionHolder> scannedBeanDefinitions =
  28. this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
  29. // 检查扫描的定义集是否有任何进一步的配置类,并在需要时进行递归解析
  30. for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
  31. BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
  32. if (bdCand == null) {
  33. bdCand = holder.getBeanDefinition();
  34. }
  35. if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
  36. parse(bdCand.getBeanClassName(), holder.getBeanName());
  37. }
  38. }
  39. }
  40. }
  41. // 处理 @Import annotations
  42. processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
  43. // 处理 @ImportResource annotations
  44. AnnotationAttributes importResource =
  45. AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
  46. if (importResource != null) {
  47. String[] resources = importResource.getStringArray("locations");
  48. Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
  49. for (String resource : resources) {
  50. String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
  51. configClass.addImportedResource(resolvedResource, readerClass);
  52. }
  53. }
  54. // 处理 @Bean methods 获取到配置类中所有标注了@Bean的方法
  55. Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
  56. for (MethodMetadata methodMetadata : beanMethods) {
  57. configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
  58. }
  59. // 处理配置类接口
  60. processInterfaces(configClass, sourceClass);
  61. // 处理配置类的父类
  62. if (sourceClass.getMetadata().hasSuperClass()) {
  63. String superclass = sourceClass.getMetadata().getSuperClassName();
  64. if (superclass != null && !superclass.startsWith("java") &&
  65. !this.knownSuperclasses.containsKey(superclass)) {
  66. this.knownSuperclasses.put(superclass, configClass);
  67. return sourceClass.getSuperClass();
  68. }
  69. }
  70. return null;
  71. }

扫描和注册源码

  1. protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
  2. Assert.notEmpty(basePackages, "At least one base package must be specified");
  3. // 创建beanDefinitions用于保存扫描后生成的bean定义对象
  4. Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
  5. // 循环包路径集合
  6. for (String basePackage : basePackages) {
  7. // 找到候选的Components->真正的扫描和加载内容
  8. Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
  9. for (BeanDefinition candidate : candidates) {
  10. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
  11. candidate.setScope(scopeMetadata.getScopeName());
  12. String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
  13. // 处理@Autowire注解相关
  14. if (candidate instanceof AbstractBeanDefinition) {
  15. postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
  16. }
  17. if (candidate instanceof AnnotatedBeanDefinition) {
  18. AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
  19. }
  20. // 把解析出来的组件bean定义注册到IOC容器中
  21. if (checkCandidate(beanName, candidate)) {
  22. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
  23. definitionHolder =
  24. AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  25. beanDefinitions.add(definitionHolder);
  26. // 注册
  27. registerBeanDefinition(definitionHolder, this.registry);
  28. }
  29. }
  30. }
  31. return beanDefinitions;
  32. }

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

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

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

  1. public class MyConfig {
  2. @Bean("person")
  3. public Person getPersonInstance(){
  4. return new Person("XiaoHong", "女", getWoMenInstance());
  5. }
  6. @Bean("woMen")
  7. public WoMen getWoMenInstance(){
  8. return new WoMen();
  9. }
  10. }

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

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

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

  1. @Configuration // 如果不加@Configuration,WoMen会实例化两次
  2. public class MyConfig {
  3. @Bean("person")
  4. public Person getPersonInstance(){
  5. return new Person("XiaoHong", "女", getWoMenInstance());
  6. }
  7. @Bean("woMen")
  8. public WoMen getWoMenInstance(){
  9. return new WoMen();
  10. }
  11. }

总结:当不加@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时会报错

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

启动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。

  1. @Component
  2. public class Person {
  3. private String name;
  4. private String sex;
  5. }

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

  1. @Configuration
  2. public class MyConfig {
  3. @Bean("person") // 最终覆盖@Component定义的同名Bean
  4. public Person getPersonInstance(){
  5. return new Person();
  6. }
  7. }

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

ConfigurationClassPostProcessor 解析流程

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/101926
推荐阅读
相关标签
  

闽ICP备14008679号