个人随笔
目录
Spring源码分析:SpringIOC初始化过程源码分析-基于注解方式(四)
2020-09-28 22:28:03

在上一篇文章中,我们分析了SpringIOC基于配置文件方式的启动源码分析,以及单例bean的初始化过程,这一片文章我们来看看SpringIOC基于注解方式的启动过程,其实主要区别就是一个解析配置文件获得BeanDefinition一个是按注解扫描包获得BeanDefinition,后面的实例化过程是一样的了,所以这篇文章也只是分析到获得BeanDefinition.

SpringIOC 初始化过程–Bean容器的创建过程(基于AnnotationConfigApplicationContext方式)

这里写一个启动Spring容器的例子

IndexDao

  1. public interface IndexDao {
  2. String testSource();
  3. }

IndexDaoImpl

  1. @Service
  2. public class IndexDaoImpl implements IndexDao {
  3. public IndexDaoImpl() {
  4. System.out.println("constructor");
  5. }
  6. public String testSource(){
  7. return "test \n test2";
  8. }
  9. }

AppConfig

  1. @Configuration
  2. @ComponentScan("cn.haoxy")
  3. public class AppConfig {
  4. }

TestBean

  1. public class TestBean {
  2. public static void main(String[] args) {
  3. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  4. applicationContext.register(AppConfig.class);
  5. applicationContext.refresh();
  6. IndexDao bean = applicationContext.getBean(IndexDao.class);
  7. System.out.println(bean.testSource());
  8. applicationContext.close();
  9. }
  10. }

在Maven构建项目时引入的

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-context</artifactId>
  4. <version>5.0.11.RELEASE</version>
  5. </dependency>

在看关于spring源码的文章时很多都是基于 ClassPathXmlApplicationContext(…) 现在都基于springboot项目很少再使用xml的方式去配置,现在很多都是基于注解的方式; 所以本文我们使用AnnotationConfigApplicationContext();来进行讲解;

当然,除了这两个以外我们也还有其他构建 ApplicationContext 的方案可供选择:

FileSystemXmlApplicationContext: 的构造函数需要一个 xml 配置文件在系统中的路径,其他和 ClassPathXmlApplicationContext 基本上一样。

对于上面的类我们先混个眼熟就行;后面我们会再说到的;

启动过程分析

AnnotationConfigApplicationContext();方法介绍
第一步: 我们肯定要从AnnotationConfigApplicationContext的构造方法开始说起;

AnnotationConfigApplicationContext有父类,故先要执行父类的构造方法;父类的构造方法实例化一个工厂DefaultListableBeanFactory

  1. public GenericApplicationContext() {
  2. this.beanFactory = new DefaultListableBeanFactory();
  3. }

到这里我们再来看一个类图:主要是BeanFactory介绍:

ApplicationContext 继承了 ListableBeanFactory,这个 Listable 的意思就是,通过这个接口,我们可以获取多个 Bean,大家看源码会发现,最顶层 BeanFactory 接口的方法都是获取单个 Bean 的。

ApplicationContext 继承了 HierarchicalBeanFactory,Hierarchical 单词本身已经能说明问题了,也就是说我们可以在应用中起多个 BeanFactory,然后可以将各个 BeanFactory 设置为父子关系。

AutowireCapableBeanFactory 这个名字中的 Autowire 大家都非常熟悉,它就是用来自动装配 Bean 用的,但是仔细看上图,ApplicationContext 并没有继承它,不过不用担心,不使用继承,不代表不可以使用组合,如果你看到 ApplicationContext 接口定义中的最后一个方法 getAutowireCapableBeanFactory() 就知道了。

ConfigurableListableBeanFactory 也是一个特殊的接口,看图,特殊之处在于它继承了第二层所有的三个接口,而 ApplicationContext 没有。这点之后会用到。

然后,请读者打开编辑器,翻一下 BeanFactory、ListableBeanFactory、HierarchicalBeanFactory、AutowireCapableBeanFactory、ApplicationContext 这几个接口的代码,

下面我们着重介绍一下DefaultListableBeanFactory,我们可以看到 ConfigurableListableBeanFactory 只有一个实现类 DefaultListableBeanFactory,而且实现类 DefaultListableBeanFactory 还通过实现右边的 AbstractAutowireCapableBeanFactory 通吃了右路。所以结论就是,最底下这个家伙 DefaultListableBeanFactory 基本上是最牛的 BeanFactory 了,这也是为什么这边会使用这个类来实例化的原因。上面在的构造方法中实例化了DefaultListableBeanFactory,DefaultListableBeanFactory类中定义了

  1. private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

  1. private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

至于这两个东西是做什么的,我们需要先了解一下BeanDefinition;

BeanDefinition介绍

我们来看下 BeanDefinition 的接口定义:

  1. public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
  2. // 我们可以看到,默认只提供 sington 和 prototype 两种,
  3. // 很多读者可能知道还有 request, session, globalSession, application, websocket 这几种,
  4. // 不过,它们属于基于 web 的扩展。
  5. String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
  6. String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
  7. // 比较不重要,直接跳过吧
  8. int ROLE_APPLICATION = 0;
  9. int ROLE_SUPPORT = 1;
  10. int ROLE_INFRASTRUCTURE = 2;
  11. // 设置父 Bean,这里涉及到 bean 继承,不是 java 继承。请参见附录的详细介绍
  12. // 一句话就是:继承父 Bean 的配置信息而已
  13. void setParentName(String parentName);
  14. // 获取父 Bean
  15. String getParentName();
  16. // 设置 Bean 的类名称,将来是要通过反射来生成实例的
  17. void setBeanClassName(String beanClassName);
  18. // 获取 Bean 的类名称
  19. String getBeanClassName();
  20. // 设置 bean 的 scope
  21. void setScope(String scope);
  22. String getScope();
  23. // 设置是否懒加载
  24. void setLazyInit(boolean lazyInit);
  25. boolean isLazyInit();
  26. // 设置该 Bean 依赖的所有的 Bean,注意,这里的依赖不是指属性依赖(如 @Autowire 标记的),
  27. // 是 depends-on="" 属性设置的值。
  28. void setDependsOn(String... dependsOn);
  29. // 返回该 Bean 的所有依赖
  30. String[] getDependsOn();
  31. // 设置该 Bean 是否可以注入到其他 Bean 中,只对根据类型注入有效,
  32. // 如果根据名称注入,即使这边设置了 false,也是可以的
  33. void setAutowireCandidate(boolean autowireCandidate);
  34. // 该 Bean 是否可以注入到其他 Bean 中
  35. boolean isAutowireCandidate();
  36. // 主要的。同一接口的多个实现,如果不指定名字的话,Spring 会优先选择设置 primary 为 true 的 bean
  37. void setPrimary(boolean primary);
  38. // 是否是 primary 的
  39. boolean isPrimary();
  40. // 如果该 Bean 采用工厂方法生成,指定工厂名称;
  41. // 一句话就是:有些实例不是用反射生成的,而是用工厂模式生成的
  42. void setFactoryBeanName(String factoryBeanName);
  43. // 获取工厂名称
  44. String getFactoryBeanName();
  45. // 指定工厂类中的 工厂方法名称
  46. void setFactoryMethodName(String factoryMethodName);
  47. // 获取工厂类中的 工厂方法名称
  48. String getFactoryMethodName();
  49. // 构造器参数
  50. ConstructorArgumentValues getConstructorArgumentValues();
  51. // Bean 中的属性值,后面给 bean 注入属性值的时候会说到
  52. MutablePropertyValues getPropertyValues();
  53. // 是否 singleton
  54. boolean isSingleton();
  55. // 是否 prototype
  56. boolean isPrototype();
  57. // 如果这个 Bean 是被设置为 abstract,那么不能实例化,
  58. // 常用于作为 父bean 用于继承,其实也很少用......
  59. boolean isAbstract();
  60. int getRole();
  61. String getDescription();
  62. String getResourceDescription();
  63. BeanDefinition getOriginatingBeanDefinition();
  64. }

在Java中,一切皆对象。在JDK中使用java.lang.Class来描述类这个对象。

在Spring中,存在bean这样一个概念,那Spring又是怎么抽象bean这个概念,用什么类来描述bean这个对象呢?Spring使用BeanDefinition来描述bean。

BeanDefinition有很多子类例如:

我们继续往下看

  1. public AnnotationConfigApplicationContext() {
  2. /**
  3. * 创建一个读取注解的Bean定义读取器
  4. */
  5. this.reader = new AnnotatedBeanDefinitionReader(this);
  6. //可以用来扫描包或者类,继而转换成BeanDefinition
  7. //但是实际上我们扫描包工作不是scanner这个对象来完成的而是
  8. //spring自己new的一个ClassPathBeanDefinitionScanner
  9. //这里的scanner仅仅是为了程序员能够在外部调用AnnotationConfigApplicationContext对象的scan方法
  10. this.scanner = new ClassPathBeanDefinitionScanner(this);
  11. }

上面代码首先在AnnotationConfigApplicationContext构造方法中实例化了一个读取器和扫描器;重点看上面的注释;

紧接着看下AnnotatedBeanDefinitionReader(this);里面做了什么事情

  1. org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment)
  2. org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source)
  3. public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
  4. BeanDefinitionRegistry registry, @Nullable Object source) {
  5. DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
  6. if (beanFactory != null) {
  7. if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
  8. //AnnotationAwareOrderComparator主要能解析@Order注解和@Priority
  9. beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
  10. }
  11. if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
  12. //ContextAnnotationAutowireCandidateResolver提供处理延迟加载的功能
  13. beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
  14. }
  15. }
  16. Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
  17. //BeanDefinitio的注册,这里很重要,需要理解注册每个bean的类型
  18. if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  19. //需要注意的是ConfigurationClassPostProcessor的类型是BeanDefinitionRegistryPostProcessor
  20. //而 BeanDefinitionRegistryPostProcessor 最终实现BeanFactoryPostProcessor这个接口
  21. RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
  22. def.setSource(source)
  23. beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
  24. }
  25. if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  26. //AutowiredAnnotationBeanPostProcessor 实现了 MergedBeanDefinitionPostProcessor
  27. //MergedBeanDefinitionPostProcessor 最终实现了 BeanPostProcessor
  28. RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
  29. def.setSource(source);
  30. beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
  31. }
  32. if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  33. RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
  34. def.setSource(source);
  35. beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
  36. }
  37. //省略
  38. ........
  39. return beanDefs;
  40. }

上面代码主要做了以下几件事:

拿到上面在父类构造方法中实例化的一个工厂DefaultListableBeanFactory

向DefaultListableBeanFactory工厂中添加AnnotationAwareOrderComparator主要解析@Order注解和@Priority处理优先级;

向DefaultListableBeanFactory工厂中添加ContextAnnotationAutowireCandidateResolver提供处理延迟加载的功能

注册spring内部自己定义的bean;并放入到beanDefinitionMap和beanDefinitionNames中,这里着重看一下

org.springframework.context.annotation.internalConfigurationAnnotationProcessor=ConfigurationClassPostProcessor这里有个印象后面会再次说到;

例如:

这个方法到这里就结束了,这就是 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();所做的事情;

register()方法介绍

我们接着看下面applicationContext.register(AppConfig.class);

  1. public void register(Class<?>... annotatedClasses) {
  2. for (Class<?> annotatedClass : annotatedClasses) {
  3. registerBean(annotatedClass);
  4. }
  5. }
  6. public void registerBean(Class<?> annotatedClass) {
  7. doRegisterBean(annotatedClass, null, null, null);
  8. }
  1. ```

void doRegisterBean(Class annotatedClass, @Nullable Supplier instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer… definitionCustomizers) {
/**

  1. * 根据指定的bean创建一个BeanDefinition的子类AnnotatedGenericBeanDefinition
  2. * 这个AnnotatedGenericBeanDefinition可以理解为一个数据结构
  3. * AnnotatedGenericBeanDefinition包含了类的其他信息,比如一些元信息
  4. * scopelazy等等
  5. *
  6. */
  7. AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
  8. /**
  9. * 判断这个类是否需要跳过解析
  10. * 通过代码可以知道spring判断是否跳过解析,主要判断类有没有加注解
  11. */
  12. if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
  13. return;
  14. }
  15. abd.setInstanceSupplier(instanceSupplier);
  16. /**
  17. * 得到类的作用域
  18. */
  19. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
  20. /**
  21. * 把类的作用域添加到数据结构结构中
  22. */
  23. abd.setScope(scopeMetadata.getScopeName());
  24. /**
  25. * 生成类的名字通过beanNameGenerator
  26. */
  27. String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
  28. /**
  29. * 处理类当中的通用注解
  30. * 分析源码可以知道他主要处理
  31. * Lazy DependsOn Primary Role等等注解
  32. * 处理完成之后processCommonDefinitionAnnotations中依然是把他添加到数据结构当中
  33. *
  34. */
  35. AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
  36. /**
  37. * 如果传参中带了这些注解类就会为true, 否则qualifiers一直为空
  38. * 因为这里传如的是null(doRegisterBean(annotatedClass, null, null, null);)
  39. */
  40. if (qualifiers != null) {
  41. for (Class<? extends Annotation> qualifier : qualifiers) {
  42. ////如果配置了@Primary注解,如果加了则作为首选
  43. if (Primary.class == qualifier) {
  44. abd.setPrimary(true);
  45. }
  46. //懒加载
  47. else if (Lazy.class == qualifier) {
  48. abd.setLazyInit(true);
  49. }
  50. else {
  51. //如果使用了除@Primary和@Lazy以外的其他注解,则为该Bean添加一个根据名字自动装配的限定符
  52. //这里难以理解,后面会详细介绍
  53. abd.addQualifier(new AutowireCandidateQualifier(qualifier));
  54. }
  55. }
  56. }
  57. //这里也为null
  58. for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
  59. customizer.customize(abd);
  60. }
  61. /**
  62. * 这个BeanDefinitionHolder也是一个数据结构
  63. */
  64. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
  65. /**
  66. * ScopedProxyMode 跳过
  67. */
  68. definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  69. /**
  70. * 把上述的这个数据结构注册给registry
  71. * registry就是AnnotationConfigApplicationContext
  72. * AnnotationConfigApplicationContext在初始化的時候通過調用父類的構造方法
  73. * 实例化了一个DefaultListableBeanFactory
  74. * registerBeanDefinition里面就是把definitionHolder这个数据结构包含的信息注册到
  75. * DefaultListableBeanFactory这个工厂
  76. */
  77. BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
  78. }
  79. ```

总结一下这个方法所做的事情:

根据指定的bean创建一个BeanDefinition的子类AnnotatedGenericBeanDefinition

得到当前类的作用域,当前传入的是AppConfig.class(默认是singleton);把类的作用域添加到AnnotatedGenericBeanDefinition中

生成bean的名字并放入BeanDefinitionHolder中

处理当前类使用的通用注解,详细看代码上的注释

实例化一个BeanDefinitionHolder,相当于一个中间媒介;来存放BeanDefinition和beanName然后注册给registry,这里的registry就是AnnotationConfigApplicationContext,在AnnotationConfigApplicationContext的父类中实例化了一个DefaultListableBeanFactory;DefaultListableBeanFactory 中有个Map集合
private final Map bdMap = new ConcurrentHashMap<>(256);
就是在这个方法中将AppConfig.class放入到beanDefinitionMap 中的;那现在beanDefinitionMap 的size大小就是7个;到
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);方法中看下;最终走了
org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition方法中的

  1. else {
  2. // Still in startup registration phase
  3. this.beanDefinitionMap.put(beanName, beanDefinition);
  4. this.beanDefinitionNames.add(beanName);
  5. this.manualSingletonNames.remove(beanName);
  6. }

applicationContext.register(AppConfig.class);方法到这里也就结束了;

下面我们进入今天的重要部分:

refresh()方法

  1. org.springframework.context.support.AbstractApplicationContext#refresh
  2. @Override
  3. public void refresh() throws BeansException, IllegalStateException {
  4. synchronized (this.startupShutdownMonitor) {
  5. // Prepare this context for refreshing.
  6. //准备工作包括设置启动时间,是否激活标识位,
  7. // 初始化属性源(property source)配置
  8. prepareRefresh();
  9. // Tell the subclass to refresh the internal bean factory.
  10. //返回一个factory 为什么需要返回一个工厂
  11. //因为要对工厂进行初始化
  12. /** 这里说明一下:如果你使用是的xml配置的方式就会执行 AbstractRefreshableApplicationContext的refreshBeanFactory方法去加载xml配置信息;因为ClassPathXmlApplicationContext是它的子类;现在我们使用的是注解配置的方式所以会执行GenericApplicationContext的refreshBeanFactory方法,这个方法就是只返回了一个beanFactory**/
  13. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  14. // Prepare the bean factory for use in this context.
  15. //准备工厂
  16. prepareBeanFactory(beanFactory);
  17. try {
  18. // Allows post-processing of the bean factory in context subclasses.
  19. //这个方法在当前版本的spring是没用任何代码的
  20. //可能spring期待在后面的版本中去扩展吧
  21. postProcessBeanFactory(beanFactory);
  22. // Invoke factory processors registered as beans in the context.
  23. //在spring的环境中去执行已经被注册的 factory processors
  24. //设置执行自定义的ProcessBeanFactory 和spring内部自己定义的
  25. invokeBeanFactoryPostProcessors(beanFactory);
  26. // Register bean processors that intercept bean creation.
  27. //注册beanPostProcessor
  28. registerBeanPostProcessors(beanFactory);
  29. // Initialize message source for this context.
  30. // 初始化当前 ApplicationContext 的 MessageSource,国际化这里就不展开说了
  31. initMessageSource();
  32. // Initialize event multicaster for this context.
  33. //初始化应用事件广播器
  34. initApplicationEventMulticaster();
  35. // Initialize other special beans in specific context subclasses.
  36. // 从方法名就可以知道,典型的模板方法(钩子方法),
  37. // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
  38. onRefresh();
  39. // Check for listener beans and register them.
  40. // 注册事件监听器,监听器需要实现 ApplicationListener 接口。这也不是我们的重点,过
  41. registerListeners();
  42. // Instantiate all remaining (non-lazy-init) singletons.
  43. // 重点,重点,重点
  44. // 初始化所有的 singleton beans
  45. //(lazy-init 的除外)
  46. finishBeanFactoryInitialization(beanFactory);
  47. // Last step: publish corresponding event.
  48. // 最后,广播事件,ApplicationContext 初始化完成
  49. finishRefresh();
  50. }
  51. //.......

像prepareRefresh();,obtainFreshBeanFactory();都没有什么好说的看上面的注释就可以,这里我们简单介绍一下prepareBeanFactory(beanFactory);方法;

prepareBeanFactory()

  1. protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  2. // 设置 BeanFactory 的类加载器,我们知道 BeanFactory 需要加载类,也就需要类加载器,
  3. // 这里设置为加载当前 ApplicationContext 类的类加载器
  4. beanFactory.setBeanClassLoader(getClassLoader());
  5. //bean表达式解释器, 为了能够让我们的beanFactory去解析bean表达式
  6. beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
  7. //对象与string类型的转换 <property red="dao">
  8. //想深入了解参考 https://blog.csdn.net/pentiumchen/article/details/44026575
  9. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
  10. //添加一个后置管理器ApplicationContextAwareProcessor
  11. // 能够在bean中获得到各种*Aware(*Aware都有其作用)
  12. // 这个我们很常用,如我们会为了获取 ApplicationContext 而 implement ApplicationContextAware
  13. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
  14. // 下面几行的意思就是,如果某个 bean 依赖于以下几个接口的实现类,在自动装配的时候忽略它们,
  15. // Spring 会通过其他方式来处理这些依赖。
  16. beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
  17. beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
  18. beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
  19. beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
  20. beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
  21. beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
  22. // 下面几行就是为特殊的几个 bean 赋值,如果有 bean 依赖了以下几个,会注入这边相应的值,
  23. //MessageSource 被注册成为了一个普通的 bean
  24. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
  25. beanFactory.registerResolvableDependency(ResourceLoader.class, this);
  26. beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
  27. beanFactory.registerResolvableDependency(ApplicationContext.class, this);
  28. // 这个 BeanPostProcessor 也很简单,在 bean 实例化后,如果是 ApplicationListener 的子类,
  29. // 那么将其添加到 listener 列表中,可以理解成:注册 事件监听器
  30. beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
  31. // 这里涉及到特殊的 bean,名为:loadTimeWeaver,这不是我们的重点,忽略它
  32. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
  33. beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
  34. // Set a temporary ClassLoader for type matching.
  35. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
  36. }
  37. //意思是如果自定义的Bean中没有名为"systemProperties"和"systemEnvironment"的Bean,
  38. // 则注册两个Bena,Key为"systemProperties"和"systemEnvironment",Value为Map,
  39. // 这两个Bean就是一些系统配置和系统环境信息
  40. // Register default environment beans.
  41. if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
  42. beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
  43. }
  44. if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
  45. beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
  46. }
  47. if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
  48. beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
  49. }
  50. }

上面prepareBeanFactory方法只是给beanFactory增加一些特殊的东西例如:表达式解析器,后置处理器,忽略一些特定的类;至此beanFactory中的beanDefinitionMap 的size大小依然还是7个;

postProcessBeanFactory(beanFactory);是一个空方法;

下面重点介绍一下invokeBeanFactoryPostProcessors(beanFactory);

invokeBeanFactoryPostProcessors()

  1. protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
  2. //这里的getBeanFactoryPostProcessors()是获取手动给spring的BeanFactoryPostProcessors()
  3. //何为手动给spring --> 手动调用AnnotationConfigApplicationContext.addBeanFactoryPostProcessor();
  4. //所以说自定义的BeanFactoryPostProcessors并非只有implements BeanFactoryPostProcessors才叫自定义
  5. //我们并没有手动去调用所以getBeanFactoryPostProcessors()的size = 0
  6. //这里问: 那如果我们自己去implements BeanFactoryPostProcessors 那getBeanFactoryPostProcessors()的size还会不会是0?
  7. //回答: 还是0! 因为我们自己implements BeanFactoryPostProcessors必须要加@Component,但是直到现在为止spring并没有开始扫描@Component
  8. //所以还是0
  9. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
  10. // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
  11. // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
  12. if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
  13. beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
  14. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
  15. }
  16. }

进入invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());方法

下面的信息量比较大,我们先看一下下面代码中需要的类图,先熟悉一下,有助于理解;

  1. public static void invokeBeanFactoryPostProcessors(
  2. //List<BeanFactoryPostProcessor> beanFactoryPostProcessors 这个是我们手动传过来的
  3. ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
  4. // Invoke BeanDefinitionRegistryPostProcessors first, if any.
  5. Set<String> processedBeans = new HashSet<>();
  6. //这里肯定是会进的,当前的beanFactory 一直都是 DefaultListableBeanFactory,而DefaultListableBeanFactory是BeanDefinitionRegistry的子类
  7. if (beanFactory instanceof BeanDefinitionRegistry) {
  8. BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
  9. //BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor
  10. //BeanDefinitionRegistryPostProcessor功能比BeanFactoryPostProcessor更强大
  11. //我们自己要是想扩展有两种方式;1:实现BeanFactoryPostProcessor,2,BeanDefinitionRegistryPostProcessor,所以定义了两个来存放,
  12. //这里之所以实例化两个list的目的是:进行区分,spring对这两个有不同的处理方式
  13. List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
  14. List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
  15. //这里是size=0;上面的代码注释中解释过
  16. for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
  17. if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
  18. BeanDefinitionRegistryPostProcessor registryProcessor =
  19. (BeanDefinitionRegistryPostProcessor) postProcessor;
  20. //如我们自己implements BeanDefinitionRegistryPostProcessor并且没有加@Component而是我们自己手动添加的ApplicationContext.addBeanFactoryPostProcessor(new TestBeanDefinitionRegistryPostProcessor());那么在下面这句话就会执行重写的方法;
  21. registryProcessor.postProcessBeanDefinitionRegistry(registry);
  22. registryProcessors.add(registryProcessor);
  23. } else {
  24. regularPostProcessors.add(postProcessor);
  25. }
  26. }
  27. //这里又定义了一个,和上面的区别是,这个currentRegistryProcessors 放的是spring内部自己实现了BeanDefinitionRegistryPostProcessor接口的对象
  28. List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
  29. //BeanDefinitionRegistryPostProcessor 等于 BeanFactoryPostProcessor
  30. //getBeanNamesForType 根据bean的类型获取bean的名字 ConfigurationClassPostProcessor
  31. //这里的getBeanNamesForType代码就不展开了大致说下 就是拿到beanDefinitionNames中的7个值去对和BeanDefinitionRegistryPostProcessor对比看是否是他的子类
  32. //这里7个中只有一个ConfigurationClassPostProcessor是它的子类,所以值取到了一个ConfigurationClassPostProcessor
  33. String[] postProcessorNames =
  34. beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  35. //ConfigurationClassPostProcessor我们在最开始介绍注册spring内部自己定义的bean时,向beanDefinitionMap添加了6个(AppConfig.calss之外)中,其中一个就是它;
  36. //这里解释一下为什么要在最开始注册这个呢?因为spring的工厂需要去解析,扫描等等功能
  37. //而这些功能都是需要在spring工厂初始化完成之前执行
  38. //要么在工厂最开始的时候、要么在工厂初始化之中,反正不能再之后
  39. //因为如果在之后就没有意义,因为那个时候已经需要使用工厂了
  40. //所以这里Spring在一开始就注册了一个BeanFactoryPostProcessor,用来插手SpringFactory的实例化过程
  41. //而这个类叫做ConfigurationClassPostProcessor
  42. for (String ppName : postProcessorNames) {
  43. if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
  44. //添加到集合currentRegistryProcessors中
  45. currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
  46. //添加到processedBeans的Set集合中
  47. processedBeans.add(ppName);
  48. }
  49. }
  50. //排序不重要,况且currentRegistryProcessors这里也只有一个数据
  51. sortPostProcessors(currentRegistryProcessors, beanFactory);
  52. //合并list,不重要(为什么要合并,因为有我们自定义个还有spring自己内部实现的)
  53. registryProcessors.addAll(currentRegistryProcessors);
  54. /**
  55. * //最重要。注意这里是方法调用
  56. * //调用这个方法
  57. * //循环所有的BeanDefinitionRegistryPostProcessor
  58. * //该方法内部postProcessor.postProcessBeanDefinitionRegistry
  59. */
  60. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
  61. //这个list只是一个临时变量,故而要清除
  62. currentRegistryProcessors.clear();
  63. // 下面的代码先不看,等invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);执行完之后我们回头再看....
  64. }

这里就不总结了,看上面的代码注释就很清楚了,下面

  1. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

是重点,我们进去看看做了什么事?

  1. private static void invokeBeanDefinitionRegistryPostProcessors(
  2. Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
  3. //只有一条数据
  4. for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
  5. postProcessor.postProcessBeanDefinitionRegistry(registry);
  6. }
  7. }

然后执行了

  1. org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

之后执行了

  1. org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

我们着重看下这个方法!

  1. public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
  2. //定义一个list 存放 applicationContext 提供的bd
  3. List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
  4. //获取容器中注册的所有bd名字 这里会有7个
  5. String[] candidateNames = registry.getBeanDefinitionNames();
  6. /**
  7. * Full : 加了Configuration注解的类会被Sping标记为Full
  8. * Lite : 其他注解标记为Lite
  9. */
  10. //遍历beanName 拿出的所有bd(BeanDefinition),然后判断bd时候包含了@Configuration、@Import,@Compent。。。注解
  11. //这里循环7,但是有个6个我们都不需要看,我们只看AppConfig
  12. for (String beanName : candidateNames) {
  13. //根据bean名称得到具体的BeanDefinition
  14. BeanDefinition beanDef = registry.getBeanDefinition(beanName);
  15. //检查是否被处理过
  16. //如果BeanDefinition中的configurationClass属性为full或者lite,则意味着已经处理过了,直接跳过
  17. //进去下面checkConfigurationClassCandidate方法就会明白这句话的意思
  18. if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
  19. ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
  20. if (logger.isDebugEnabled()) {
  21. logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
  22. }
  23. }
  24. //判断是否是Configuration类,如果加了Configuration注解下面的这几个注解就不再判断了
  25. /**
  26. * candidateIndicators.add(Component.class.getName());
  27. * candidateIndicators.add(ComponentScan.class.getName());
  28. * candidateIndicators.add(Import.class.getName());
  29. * candidateIndicators.add(ImportResource.class.getName());
  30. */
  31. else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
  32. //BeanDefinitionHolder 也可以看成一个数据结构,将BeanDefinitionHolder添加到上面实例化的一个configCandidates集合中;
  33. configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
  34. }
  35. }
  36. // Return immediately if no @Configuration classes were found
  37. if (configCandidates.isEmpty()) {
  38. return;
  39. }
  40. // 排序,根据order,不重要
  41. configCandidates.sort((bd1, bd2) -> {
  42. int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
  43. int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
  44. return Integer.compare(i1, i2);
  45. });
  46. //如果BeanDefinitionRegistry是SingletonBeanRegistry子类的话,
  47. // 由于我们当前传入的是DefaultListableBeanFactory,是SingletonBeanRegistry 的子类
  48. // 因此会将registry强转为SingletonBeanRegistry
  49. SingletonBeanRegistry sbr = null;
  50. if (registry instanceof SingletonBeanRegistry) {
  51. sbr = (SingletonBeanRegistry) registry;
  52. if (!this.localBeanNameGeneratorSet) {
  53. BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
  54. if (generator != null) {
  55. this.componentScanBeanNameGenerator = generator;
  56. this.importBeanNameGenerator = generator;
  57. }
  58. }
  59. }
  60. if (this.environment == null) {
  61. this.environment = new StandardEnvironment();
  62. }
  63. // 实例化ConfigurationClassParser 为了解析各个配置类
  64. ConfigurationClassParser parser = new ConfigurationClassParser(
  65. this.metadataReaderFactory, this.problemReporter, this.environment,
  66. this.resourceLoader, this.componentScanBeanNameGenerator, registry);
  67. //实例化2个set,candidates用于将之前加入的configCandidates进行去重
  68. //因为可能有多个配置类重复了
  69. //alreadyParsed用于判断是否处理过
  70. Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
  71. Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
  72. do {
  73. //扫描包,将去重后的candidates集合传入;里面只有一个appConfig
  74. parser.parse(candidates);
  75. parser.validate();
  76. Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
  77. configClasses.removeAll(alreadyParsed);
  78. // Read the model and create bean definitions based on its content
  79. if (this.reader == null) {
  80. this.reader = new ConfigurationClassBeanDefinitionReader(
  81. registry, this.sourceExtractor, this.resourceLoader, this.environment,
  82. this.importBeanNameGenerator, parser.getImportRegistry());
  83. }
  84. /**
  85. *
  86. * 这里值得注意的是扫描出来的bean当中可能包含了特殊类
  87. * 比如ImportBeanDefinitionRegistrar那么也在这个方法里面处理
  88. * 但是并不是包含在configClasses当中
  89. * configClasses当中主要包含的是importSelector
  90. * 因为ImportBeanDefinitionRegistrar在扫描出来的时候已经被添加到一个list当中去了
  91. *
  92. */
  93. //bd 到 map
  94. this.reader.loadBeanDefinitions(configClasses);
  95. alreadyParsed.addAll(configClasses);
  96. candidates.clear();
  97. if (registry.getBeanDefinitionCount() > candidateNames.length) {
  98. String[] newCandidateNames = registry.getBeanDefinitionNames();
  99. Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
  100. Set<String> alreadyParsedClasses = new HashSet<>();
  101. for (ConfigurationClass configurationClass : alreadyParsed) {
  102. alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
  103. }
  104. for (String candidateName : newCandidateNames) {
  105. if (!oldCandidateNames.contains(candidateName)) {
  106. BeanDefinition bd = registry.getBeanDefinition(candidateName);
  107. if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
  108. !alreadyParsedClasses.contains(bd.getBeanClassName())) {
  109. candidates.add(new BeanDefinitionHolder(bd, candidateName));
  110. }
  111. }
  112. }
  113. candidateNames = newCandidateNames;
  114. }
  115. }
  116. while (!candidates.isEmpty());
  117. // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
  118. if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
  119. sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
  120. }
  121. if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
  122. // Clear cache in externally provided MetadataReaderFactory; this is a no-op
  123. // for a shared cache since it'll be cleared by the ApplicationContext.
  124. ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
  125. }
  126. }

这个方法有点长,而且很重要,需要慢慢看;在这个方法中我们只需要针对AppConfig这个类看就可以了其他6个可以跳过;

我们先进入一下checkConfigurationClassCandidate方法,看看是怎么检查注解又怎么标识Full和Lite的;

  1. public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
  2. String className = beanDef.getBeanClassName();
  3. if (className == null || beanDef.getFactoryMethodName() != null) {
  4. return false;
  5. }
  6. AnnotationMetadata metadata;
  7. //......由于篇幅原因,省略一些代码,用一句话来说明一下;这个metadata是怎么来的
  8. /**
  9. 1,如果BeanDefinition 是 AnnotatedBeanDefinition的实例,并且className 和 BeanDefinition中的元 数据的类名相同,则直接从BeanDefinition 获得Metadata
  10. 2,如果BeanDefinition 是 AbstractBeanDefinition的实例,并且beanDef 有 beanClass 属性存在
  11. 则实例化StandardAnnotationMetadata
  12. **/
  13. //判断当前这个bd中存在的类是不是加了@Configruation注解
  14. //如果存在则spring认为他是一个全注解的类
  15. if (isFullConfigurationCandidate(metadata)) {
  16. //如果存在Configuration 注解,则为BeanDefinition 设置configurationClass属性为full
  17. beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
  18. }
  19. //判断是否加了以下注解,摘录isLiteConfigurationCandidate的源码
  20. // candidateIndicators.add(Component.class.getName());
  21. // candidateIndicators.add(ComponentScan.class.getName());
  22. // candidateIndicators.add(Import.class.getName());
  23. // candidateIndicators.add(ImportResource.class.getName());
  24. //如果不存在Configuration注解,spring则认为是一个部分注解类
  25. else if (isLiteConfigurationCandidate(metadata)) {
  26. beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
  27. }
  28. else {
  29. return false;
  30. }
  31. // It's a full or lite configuration candidate... Let's determine the order value, if any.
  32. Integer order = getOrder(metadata);
  33. if (order != null) {
  34. beanDef.setAttribute(ORDER_ATTRIBUTE, order);
  35. }
  36. return true;
  37. }

isFullConfigurationCandidate();

  1. public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
  2. return metadata.isAnnotated(Configuration.class.getName());
  3. }

isLiteConfigurationCandidate();

  1. static {
  2. candidateIndicators.add(Component.class.getName());
  3. candidateIndicators.add(ComponentScan.class.getName());
  4. candidateIndicators.add(Import.class.getName());
  5. candidateIndicators.add(ImportResource.class.getName());
  6. }

下面我们重点分析parse方法

  1. public void parse(Set<BeanDefinitionHolder> configCandidates) {
  2. this.deferredImportSelectors = new LinkedList<>();
  3. //根据BeanDefinition 的类型 做不同的处理,一般都会调用ConfigurationClassParser#parse 进行解析
  4. //遍历configCandidates中的BeanDefinitionHolder取出BeanDefinition
  5. //BeanDefinition中包含了AppConfig的一些属性信息
  6. for (BeanDefinitionHolder holder : configCandidates) {
  7. BeanDefinition bd = holder.getBeanDefinition();
  8. try {
  9. //当前bd类型就是AnnotatedBeanDefinition --> true
  10. if (bd instanceof AnnotatedBeanDefinition) {
  11. //解析注解对象,并且把解析出来的bd放到map,但是这里的bd指的是普通的
  12. //何谓不普通的呢?比如@Bean 和各种beanFactoryPostProcessor得到的bean不在这里put
  13. //但是这里解析,只是put而已
  14. //Metadata中主要包含的是解析出来的注解,当前AppConfig 解析出来的注解是@Configuration,@ComponentScan
  15. //注解何时被解析出来的呢? 就是一开始将AppConfig 加载到BeanDefinitionMap中时;
  16. parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
  17. }
  18. else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
  19. parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
  20. }
  21. else {
  22. parse(bd.getBeanClassName(), holder.getBeanName());
  23. }
  24. }
  25. catch (BeanDefinitionStoreException ex) {
  26. throw ex;
  27. }
  28. catch (Throwable ex) {
  29. throw new BeanDefinitionStoreException(
  30. "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
  31. }
  32. }
  33. //处理延迟加载的importSelect
  34. processDeferredImportSelectors();
  35. }

然后进入真正的解析方法:

  1. org.springframework.context.annotation.ConfigurationClassParser#parse(AnnotationMetadata, String)

在这个方法中又调用了:

  1. org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass方法;
  1. protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
  2. if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
  3. return;
  4. }
  5. // 处理Imported 的情况
  6. //就是当前这个注解类有没有被别的类import
  7. ConfigurationClass existingClass = this.configurationClasses.get(configClass);
  8. if (existingClass != null) {
  9. if (configClass.isImported()) {
  10. if (existingClass.isImported()) {
  11. existingClass.mergeImportedBy(configClass);
  12. }
  13. // Otherwise ignore new imported config class; existing non-imported class overrides it.
  14. return;
  15. }
  16. else {
  17. // Explicit bean definition found, probably replacing an imports.
  18. // Let's remove the old one and go with the new one.
  19. this.configurationClasses.remove(configClass);
  20. this.knownSuperclasses.values().removeIf(configClass::equals);
  21. }
  22. }
  23. // 递归地处理配置类及其超类层次结构。
  24. SourceClass sourceClass = asSourceClass(configClass);
  25. do {
  26. //解析注解并扫描
  27. sourceClass = doProcessConfigurationClass(configClass, sourceClass);
  28. }
  29. while (sourceClass != null);
  30. //一个map,用来存放扫描出来的bean(注意这里的bean不是对象,仅仅bean的信息,因为还没到实例化这一步)
  31. this.configurationClasses.put(configClass, configClass);
  32. }

然后进入doProcessConfigurationClass()方法,下面不重要的代码我就不贴了;

  1. protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
  2. throws IOException {
  3. //处理内部类 一般不会写内部类
  4. processMemberClasses(configClass, sourceClass);
  5. // 处理@PropertySource注释
  6. for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
  7. sourceClass.getMetadata(), PropertySources.class,
  8. org.springframework.context.annotation.PropertySource.class)) {
  9. if (this.environment instanceof ConfigurableEnvironment) {
  10. processPropertySource(propertySource);
  11. }
  12. else {
  13. logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
  14. "]. Reason: Environment must implement ConfigurableEnvironment");
  15. }
  16. }
  17. // 处理@ComponentScan注释
  18. Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
  19. sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
  20. if (!componentScans.isEmpty() &&
  21. !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
  22. for (AnnotationAttributes componentScan : componentScans) {
  23. // The config class is annotated with @ComponentScan -> perform the scan immediately
  24. //解析扫描的一些基本信息,比如是否过滤,比如是否加入新的包。。。。。includeFilters,excludeFilters等等都是ComponentScan中的属性
  25. //扫描普通类-->componentScan ---> com.haoxy
  26. //这里扫描出来所有@Component
  27. //并且把扫描的出来的普通bean放到map当中
  28. Set<BeanDefinitionHolder> scannedBeanDefinitions =
  29. this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
  30. // Check the set of scanned definitions for any further config classes and parse recursively if needed
  31. for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
  32. BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
  33. if (bdCand == null) {
  34. bdCand = holder.getBeanDefinition();
  35. }
  36. //检查扫描出来的类当中是否还有@Configuration
  37. if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
  38. parse(bdCand.getBeanClassName(), holder.getBeanName());
  39. }
  40. }
  41. }
  42. }
  43. //下面是处理@Import imports 3种情况
  44. //ImportSelector
  45. //普通类
  46. //ImportBeanDefinitionRegistrar
  47. //这里和内部地柜调用时候的情况不同
  48. /**
  49. * 这里处理的import是需要判断我们的类当中时候有@Import注解
  50. * 如果有这把@Import当中的值拿出来,是一个类
  51. * 比如@Import(xxxxx.class),那么这里便把xxxxx传进去进行解析
  52. * 在解析的过程中如果发觉是一个importSelector那么就回调selector的方法
  53. * 返回一个字符串(类名),通过这个字符串得到一个类
  54. * 继而在递归调用本方法来处理这个类
  55. *
  56. * 判断一组类是不是imports(3种import)
  57. *
  58. *代码就不贴了,不是咱们这次研究的重点
  59. */
  60. processImports(configClass, sourceClass, getImports(sourceClass), true);
  61. //..........
  62. }

上面的代码就是扫描普通类—-@Component,包括@Component子类: @Repository @Controller @service;并且放到了BeanDefinitionMap当中;

进入

org.springframework.context.annotation.ComponentScanAnnotationParser#parse
方法;这里就是处理ComponentScan注解中的一些属性;例如scopedProxy,scopeResolver,includeFilters,excludeFilters,lazyInit,basePackages,basePackageClasses,等…我们直接进入parse方法的org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan方法;这个方法把@ComponentScan中的值传了过去;

  1. protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
  2. Assert.notEmpty(basePackages, "At least one base package must be specified");
  3. Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
  4. //获取到包名
  5. for (String basePackage : basePackages) {
  6. //扫描basePackage路径下的java文件
  7. //符合条件的并把它转成BeanDefinition类型
  8. Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
  9. for (BeanDefinition candidate : candidates) {
  10. //解析scope属性
  11. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
  12. candidate.setScope(scopeMetadata.getScopeName());
  13. //生成bean名称
  14. String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
  15. if (candidate instanceof AbstractBeanDefinition) {
  16. //如果这个类是AbstractBeanDefinition的子类
  17. //则为他设置默认值,比如lazy,init destory
  18. postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
  19. }
  20. if (candidate instanceof AnnotatedBeanDefinition) {
  21. //检查并且处理常用的注解
  22. //这里的处理主要是指把常用注解的值设置到AnnotatedBeanDefinition当中
  23. //当前前提是这个类必须是AnnotatedBeanDefinition类型的,说白了就是加了注解的类
  24. AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
  25. }
  26. if (checkCandidate(beanName, candidate)) {
  27. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
  28. definitionHolder =
  29. AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  30. beanDefinitions.add(definitionHolder);
  31. //根据包名扫描到的类加载到beanDefinition map 中
  32. registerBeanDefinition(definitionHolder, this.registry);
  33. }
  34. }
  35. }
  36. return beanDefinitions;
  37. }

扫描候选组件的类路径方法:
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#findCandidateComponents

  1. public Set<BeanDefinition> findCandidateComponents(String basePackage) {
  2. if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
  3. //根据索引获得bean定义,配合spring-context-indexer使用,有兴趣得自己去了解一下,这里不做具体得解析
  4. return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
  5. }
  6. else {
  7. //扫描获得bean定义
  8. return scanCandidateComponents(basePackage);
  9. }
  10. }
  1. private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
  2. Set<BeanDefinition> candidates = new LinkedHashSet<>();
  3. try {
  4. //classpath*:cn/haoxy/**/*.class ant path模式串
  5. String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
  6. resolveBasePackage(basePackage) + '/' + this.resourcePattern;
  7. //这里resources有四个;分别是 TestBean.class,AppConfig.class,IndexDao.class,IndexDaoImpl.class
  8. Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
  9. boolean traceEnabled = logger.isTraceEnabled();
  10. boolean debugEnabled = logger.isDebugEnabled();
  11. //遍历resources;
  12. for (Resource resource : resources) {
  13. if (traceEnabled) {
  14. logger.trace("Scanning " + resource);
  15. }
  16. if (resource.isReadable()) {
  17. try {
  18. MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
  19. //判断是否是我们需要的资源
  20. /**
  21. * 通过isCandidateComponent(MetadataReader metadataReader)来根据excludeFilters和includeFilters判断是否可以进行下一步的操作,
  22. * 如果这个资源被排除的filter匹配上,就返回false,代表不是我们所需要的。
  23. * 如果被包含的filter匹配上,并且他还要通过条件判断isConditionMatch的话,返回true,代表是我们需要的资源,可以进行下一步的操作。
  24. * 这里我们插一句Spring有默认的includ类型的filter实现,如果上层传入的话,就是用上层传入的,否则就使用默认的,
  25. * 默认的是扫描@Component注解以及他的子类@Repository @Controller @service
  26. */
  27. //显然这里只会匹配一个IndexDaoImpl.class
  28. if (isCandidateComponent(metadataReader)) {
  29. ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
  30. sbd.setResource(resource);
  31. sbd.setSource(resource);
  32. if (isCandidateComponent(sbd)) {
  33. if (debugEnabled) {
  34. logger.debug("Identified candidate component class: " + resource);
  35. }
  36. candidates.add(sbd);
  37. }
  38. //........省
  39. }
  40. catch (IOException ex) {
  41. throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
  42. }
  43. return candidates;
  44. }

这里只会有一个IndexDaoImpl符合我们的要求,放到candidates集合中并返回到doScan方法中;然后解析此类的作用域scope,生成bean名称等,然后调用registerBeanDefinition(definitionHolder, this.registry);方法把它加入到beanDefinitionMap集合中;

下面我们看看registerBeanDefinition(definitionHolder, this.registry)方法

从org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition
方法转来转去最后转到了
org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition方法;

  1. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  2. throws BeanDefinitionStoreException {
  3. Assert.hasText(beanName, "Bean name must not be empty");
  4. Assert.notNull(beanDefinition, "BeanDefinition must not be null");
  5. if (beanDefinition instanceof AbstractBeanDefinition) {
  6. try {
  7. ((AbstractBeanDefinition) beanDefinition).validate();
  8. }
  9. catch (BeanDefinitionValidationException ex) {
  10. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanNam)....
  11. }
  12. }
  13. //所有的 Bean 注册后会放入这个 beanDefinitionMap 中
  14. //判断beanDefinitionMap中是否存在当前bean;之所以判断是因为我们可以配置允许bean覆盖
  15. BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
  16. //显然这里是不成立的,我们并没有配置允许bean覆盖,existingDefinition中也不会存在我们当前bean
  17. if (existingDefinition != null) {
  18. //如果进到这里说明我们允许了bean的覆盖
  19. if (!isAllowBeanDefinitionOverriding()) {
  20. // 如果不允许覆盖的话,抛异常
  21. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName)....
  22. }
  23. else if (existingDefinition.getRole() < beanDefinition.getRole()) {
  24. //这里的代码都是打印日志 log....
  25. //日志内容: 用框架定义的 Bean 覆盖用户自定义的 Bean
  26. //.....
  27. else if (!beanDefinition.equals(existingDefinition)) {
  28. //log....
  29. //日志内容: 用新的 Bean 覆盖旧的 Bean
  30. }
  31. else {
  32. //log....
  33. //日志内容: 用同等的 Bean 覆盖旧的 Bean,这里指的是 equals 方法返回 true 的 Bean
  34. }
  35. //覆盖bean
  36. this.beanDefinitionMap.put(beanName, beanDefinition);
  37. }
  38. else {
  39. //上面的if不成立就来到了这里;如果是普通bean(IndexDaoImpl等),这里返回是true,
  40. // 如果是AppConfig等特殊bean,Spring一开始就加载的会走下面的else
  41. if (hasBeanCreationStarted()) {
  42. // Cannot modify startup-time collection elements anymore (for stable iteration)
  43. synchronized (this.beanDefinitionMap) {
  44. //以beanName为key,beanDefinition为value put 到 beanDefinitionMap中;
  45. //注意,"注册Bean" 这个动作结束,Bean 依然还没有初始化,我们后面会有大篇幅说初始化过程,
  46. this.beanDefinitionMap.put(beanName, beanDefinition);
  47. List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
  48. updatedDefinitions.addAll(this.beanDefinitionNames);
  49. updatedDefinitions.add(beanName);
  50. //将beanName 添加到 beanDefinitionNames集合中
  51. this.beanDefinitionNames = updatedDefinitions;
  52. if (this.manualSingletonNames.contains(beanName)) {
  53. Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
  54. updatedSingletons.remove(beanName);
  55. this.manualSingletonNames = updatedSingletons;
  56. }
  57. }
  58. }
  59. //特殊bean
  60. else {
  61. // Still in startup registration phase
  62. //同样是以beanName为key,beanDefinition为value put 到 beanDefinitionMap中;
  63. this.beanDefinitionMap.put(beanName, beanDefinition);
  64. //将beanName 添加到 beanDefinitionNames集合中
  65. this.beanDefinitionNames.add(beanName);
  66. //这LinkedHashSet存放的是:environment,systemProperties,systemEnvironment
  67. //都是一些系统环境,系统属性,这里对我们不重要
  68. this.manualSingletonNames.remove(beanName);
  69. }
  70. // 这个不重要,在预初始化的时候会用到,不必管它。
  71. this.frozenBeanDefinitionNames = null;
  72. }
  73. if (existingDefinition != null || containsSingleton(beanName)) {
  74. resetBeanDefinition(beanName);
  75. }
  76. }

这时候beanDefinitionMap的size大小就是8个了;然后放到beanDefinitions集合中返回;这里只是把它加入到beanDefinitionMap集合中还没有进行初始化;上面就是@ComponentScan注解作用的扫描BeanDefination的全部过程了。这一篇文章终于结束了,好累,自己总结了一遍印象更深刻一些;

bean的创建及初始化就参考:Spring源码分析:SpringIOC初始化过程源码分析-基于配置文件模式(三)文章的后面部分就可以了!

参考:https://www.haoxiaoyong.cn/2019/12/01/2019/2019-12-01-spring1/

 850

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2