文章结构

阅读本篇文章之前建议您首先查看上方两篇文章,因为本篇主要是描述了基于注解的方式和基于xml配置文件方式的异同点:

  1. 源码阅读环境的搭建
  2. 首先简单描述了bean容器AnnotationConfigApplicationContext
  3. 然后源码执行的第一步就是关于包扫描一块的东西,也就是我们比较熟悉的注解@ComponentScan
  4. 扫描到了各个带有注解的类之后就是读取类呀、反射呀什么的来加载类
  5. bean已经加载完后就是bean的注册逻辑了
    相比较与之前两篇文章的长篇大论,这篇文章的篇幅要少很多,这主要得益于Spring的设计精妙和代码之优雅

    准备工作

本文会基于注解的方向分析SpringIOC模块的整体流程,在阅读本篇文章之前建议您先阅读基于XML分析的两篇文章: SpringIOC源码解析(上)SpringIOC源码解析(下)

Demo工程

本次源码分析的demo工程我已经准备好了,大家可自行前往以下地址下载

  1. https://github.com/shiyujun/spring-framework

本次工程复用了之前工程的包cn.shiyujun.service中的接口和实现类,同时新增了一个基于注解的配置类,此类在cn.shiyujun.config包下

  1. @Configuration
  2. public class AnnotationConfig {
  3. @Bean
  4. public IOCService iocService(){
  5. return new IOCServiceImpl();
  6. }
  7. }

然后就是启动类了,启动类在cn.shiyujun.demo包下

  1. public class AnnotationIOCDemo {
  2. public static void main (String args[]){
  3. ApplicationContext context = new AnnotationConfigApplicationContext("cn.shiyujun.config");
  4. IOCService iocService=context.getBean(IOCService.class);
  5. System.out.println(iocService.hollo());
  6. }
  7. }

AnnotationConfigApplicationContext继承关系

SpringIOC源码解析(基于注解) - 图1

再次拿出之前的一张图片,可以看到相较于ClassPathXmlApplicationContextFileSystemXmlApplicationContext来说AnnotationConfigApplicationContext这个类的辈分好像更高一些

SpringIOC源码解析(基于注解) - 图2

接着我们看一下它的方法

我们会发现除了register注册bean的方法以外,有一个scan方法,有没有感觉很熟悉。@CompantScan用过没,他们之间什么关系,在启动类中new AnnotationConfigApplicationContext的时候传的一个包名是不是跟这个有关系?带着疑问往下看吧

源码分析

构造方法

源码分析第一站就是进入如下构造方法

  1. public AnnotationConfigApplicationContext(String... basePackages) {
  2. this();
  3. scan(basePackages);
  4. refresh();
  5. }

千万不要小瞧上方简简单单的三行代码,我们整篇文章都会基于这三行代码来展开

首先看this

  1. public AnnotationConfigApplicationContext() {
  2. //注解bean读取器
  3. this.reader = new AnnotatedBeanDefinitionReader(this);
  4. //注解bean扫描器
  5. this.scanner = new ClassPathBeanDefinitionScanner(this);
  6. }

同时子类的构造方法执行之前肯定会先执行父类的构造方法,所以还有父类
GenericApplicationContext的构造方法

  1. public GenericApplicationContext() {
  2. //这个bean的相关知识请参考之前的文章
  3. this.beanFactory = new DefaultListableBeanFactory();
  4. }

注册bean

接着看scan方法

  1. public void scan(String... basePackages) {
  2. Assert.notEmpty(basePackages, "At least one base package must be specified");
  3. this.scanner.scan(basePackages);
  4. }

可以看到这里调用的是bean扫描器ClassPathBeanDefinitionScannerscan方法

  1. public int scan(String... basePackages) {
  2. //获取当前注册bean的数量
  3. int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
  4. //往下看
  5. doScan(basePackages);
  6. if (this.includeAnnotationConfig) {
  7. //注册配置处理器
  8. AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
  9. }
  10. //返回此次注册的数量
  11. return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
  12. }

接着往下看doScan方法

  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. //先跟进去看,下面的方法先忽略
  7. Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
  8. for (BeanDefinition candidate : candidates) {
  9. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
  10. candidate.setScope(scopeMetadata.getScopeName());
  11. String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
  12. if (candidate instanceof AbstractBeanDefinition) {
  13. postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
  14. }
  15. if (candidate instanceof AnnotatedBeanDefinition) {
  16. AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
  17. }
  18. if (checkCandidate(beanName, candidate)) {
  19. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
  20. definitionHolder =
  21. AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  22. beanDefinitions.add(definitionHolder);
  23. registerBeanDefinition(definitionHolder, this.registry);
  24. }
  25. }
  26. }
  27. return beanDefinitions;
  28. }

扫描包

  1. public Set<BeanDefinition> findCandidateComponents(String basePackage) {
  2. //判断是否使用Filter指定忽略包不扫描,@Component注解里可以以传入filter数组,xml中也可以传入标签
  3. if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
  4. return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
  5. }
  6. else {
  7. //扫描包
  8. return scanCandidateComponents(basePackage);
  9. }

在接着往下看之前,我们有必要先认识一个东东,MetadataReader。这个接口有三个方法

  1. public interface MetadataReader {
  2. Resource getResource();
  3. ClassMetadata getClassMetadata();
  4. AnnotationMetadata getAnnotationMetadata();
  5. }

第一个返回Resource就不必多说了,就是配置类的资源对象。第二个第三个根据名字我们可以猜到是类的元数据和注解的元数据
可以看一下它们两个的方法

SpringIOC源码解析(基于注解) - 图3

SpringIOC源码解析(基于注解) - 图4

接着往下看

  1. private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
  2. Set<BeanDefinition> candidates = new LinkedHashSet<>();
  3. try {
  4. //组装扫描路径(组装完成后是这种格式:classpath*:cn/shiyujun/config/**/*.class)
  5. String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
  6. resolveBasePackage(basePackage) + '/' + this.resourcePattern;
  7. //根据路径获取资源对象
  8. Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
  9. boolean traceEnabled = logger.isTraceEnabled();
  10. boolean debugEnabled = logger.isDebugEnabled();
  11. for (Resource resource : resources) {
  12. if (traceEnabled) {
  13. logger.trace("Scanning " + resource);
  14. }
  15. if (resource.isReadable()) {
  16. try {
  17. //根据资源对象通过反射获取资源对象的MetadataReader,具体就不展开说了
  18. MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
  19. //查看配置类是否有@Conditional一系列的注解,然后是否满足注册Bean的条件,关于这个知识点可以参考我之前的文章:https://mp.weixin.qq.com/s/RXYIh_g5iU1e3liK-8n5zA
  20. if (isCandidateComponent(metadataReader)) {
  21. ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
  22. sbd.setResource(resource);
  23. sbd.setSource(resource);
  24. if (isCandidateComponent(sbd)) {
  25. if (debugEnabled) {
  26. logger.debug("Identified candidate component class: " + resource);
  27. }
  28. candidates.add(sbd);
  29. }
  30. else {
  31. if (debugEnabled) {
  32. logger.debug("Ignored because not a concrete top-level class: " + resource);
  33. }
  34. }
  35. }
  36. else {
  37. if (traceEnabled) {
  38. logger.trace("Ignored because not matching any filter: " + resource);
  39. }
  40. }
  41. }
  42. catch (Throwable ex) {
  43. throw new BeanDefinitionStoreException(
  44. "Failed to read candidate component class: " + resource, ex);
  45. }
  46. }
  47. else {
  48. if (traceEnabled) {
  49. logger.trace("Ignored because not readable: " + resource);
  50. }
  51. }
  52. }
  53. }
  54. catch (IOException ex) {
  55. throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
  56. }
  57. return candidates;
  58. }

创建BeanDefinition

现在回到开始的doScan方法

  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. //获取所有符合条件的BeanDefinition
  7. Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
  8. for (BeanDefinition candidate : candidates) {
  9. //绑定BeanDefinition与Scope
  10. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
  11. candidate.setScope(scopeMetadata.getScopeName());
  12. //查看是否配置类是否指定bean的名称,如没指定则使用类名首字母小写
  13. String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
  14. //下面两个if是处理lazy、Autowire、DependencyOn、initMethod、enforceInitMethod、destroyMethod、enforceDestroyMethod、Primary、Role、Description这些逻辑的
  15. if (candidate instanceof AbstractBeanDefinition) {
  16. postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
  17. }
  18. if (candidate instanceof AnnotatedBeanDefinition) {
  19. AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
  20. }
  21. //检查bean是否存在
  22. if (checkCandidate(beanName, candidate)) {
  23. //又包装了一层
  24. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
  25. //检查scope是否创建,如未创建则进行创建
  26. definitionHolder =
  27. AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  28. beanDefinitions.add(definitionHolder);
  29. //重点来了,往下看
  30. registerBeanDefinition(definitionHolder, this.registry);
  31. }
  32. }
  33. }
  34. return beanDefinitions;
  35. }

注册bean

到了一个比较重要的节点了,跟着上文的registerBeanDefinition方法走

  1. protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
  2. BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
  3. }
  4. public static void registerBeanDefinition(
  5. BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
  6. throws BeanDefinitionStoreException {
  7. String beanName = definitionHolder.getBeanName();
  8. // 注册bean,往下看,这里的registry来自AnnotationConfigApplicationContext构造的时候构造的 ClassPathBeanDefinitionScanner传入的 this
  9. registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
  10. //如果存在别名则循环注册别名,逻辑跟上方差不多,就不展开了
  11. String[] aliases = definitionHolder.getAliases();
  12. if (aliases != null) {
  13. for (String alias: aliases) {
  14. registry.registerAlias(beanName, alias);
  15. }
  16. }
  17. }

其实这个注册bean的方法是DefaultListableBeanFactory的方法,之前的文章已经解析过了,大体就是下面这么个流程

  1. @Override
  2. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  3. throws BeanDefinitionStoreException {
  4. Assert.hasText(beanName, "Bean name must not be empty");
  5. Assert.notNull(beanDefinition, "BeanDefinition must not be null");
  6. if (beanDefinition instanceof AbstractBeanDefinition) {
  7. try {
  8. ((AbstractBeanDefinition) beanDefinition).validate();
  9. }
  10. catch (BeanDefinitionValidationException ex) {
  11. throw new BeanDefinitionStoreException(...);
  12. }
  13. }
  14. BeanDefinition oldBeanDefinition;
  15. // 所有的 Bean 注册后都会被放入到这个beanDefinitionMap 中,查看是否已存在这个bean
  16. oldBeanDefinition = this.beanDefinitionMap.get(beanName);
  17. // 处理重复名称的 Bean 定义的情况
  18. if (oldBeanDefinition != null) {
  19. if (!isAllowBeanDefinitionOverriding()) {
  20. // 如果不允许覆盖的话,抛异常
  21. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
  22. "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
  23. "': There is already [" + oldBeanDefinition + "] bound.");
  24. }
  25. else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
  26. // 用框架定义的 Bean 覆盖用户自定义的 Bean
  27. if (this.logger.isWarnEnabled()) {
  28. this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
  29. "' with a framework-generated bean definition: replacing [" +
  30. oldBeanDefinition + "] with [" + beanDefinition + "]");
  31. }
  32. }
  33. else if (!beanDefinition.equals(oldBeanDefinition)) {
  34. // 用新的 Bean 覆盖旧的 Bean
  35. if (this.logger.isWarnEnabled()) {
  36. this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
  37. "' with a framework-generated bean definition: replacing [" +
  38. oldBeanDefinition + "] with [" + beanDefinition + "]");
  39. }
  40. }
  41. else {
  42. // log...用同等的 Bean 覆盖旧的 Bean
  43. if (this.logger.isInfoEnabled()) {
  44. this.logger.info("Overriding bean definition for bean '" + beanName +
  45. "' with a different definition: replacing [" + oldBeanDefinition +
  46. "] with [" + beanDefinition + "]");
  47. }
  48. }
  49. // 覆盖
  50. this.beanDefinitionMap.put(beanName, beanDefinition);
  51. }
  52. else {
  53. // 判断是否已经有其他的 Bean 开始初始化了.注意,"注册Bean" 这个动作结束,Bean 依然还没有初始化 在 Spring 容器启动的最后,会 预初始化 所有的 singleton beans
  54. if (hasBeanCreationStarted()) {
  55. // Cannot modify startup-time collection elements anymore (for stable iteration)
  56. synchronized (this.beanDefinitionMap) {
  57. this.beanDefinitionMap.put(beanName, beanDefinition);
  58. List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
  59. updatedDefinitions.addAll(this.beanDefinitionNames);
  60. updatedDefinitions.add(beanName);
  61. this.beanDefinitionNames = updatedDefinitions;
  62. if (this.manualSingletonNames.contains(beanName)) {
  63. Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
  64. updatedSingletons.remove(beanName);
  65. this.manualSingletonNames = updatedSingletons;
  66. }
  67. }
  68. }
  69. else {
  70. // 将 BeanDefinition 放到这个 map 中,这个 map 保存了所有的 BeanDefinition
  71. this.beanDefinitionMap.put(beanName, beanDefinition);
  72. // 这是个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
  73. this.beanDefinitionNames.add(beanName);
  74. // 这是个 LinkedHashSet,代表的是手动注册的 singleton bean,
  75. this.manualSingletonNames.remove(beanName);
  76. }
  77. this.frozenBeanDefinitionNames = null;
  78. }
  79. if (oldBeanDefinition != null || containsSingleton(beanName)) {
  80. resetBeanDefinition(beanName);
  81. }
  82. }

现在回到文章开始的三句代码

  1. public AnnotationConfigApplicationContext(String... basePackages) {
  2. this();
  3. scan(basePackages);
  4. refresh();
  5. }

可以看到,只剩最后一个refresh()方法了,如果看过之前文章的同学可能都已经知道这里面是什么东西了

refresh()

首先整个方法进来以后跟使用XML的时候是一样的

  1. public void refresh() throws BeansException, IllegalStateException {
  2. synchronized (this.startupShutdownMonitor) {
  3. // 记录容器的启动时间、标记“已启动”状态、检查环境变量
  4. prepareRefresh();
  5. // 初始化BeanFactory容器、注册BeanDefinition
  6. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  7. // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
  8. prepareBeanFactory(beanFactory);
  9. try {
  10. // 扩展点
  11. postProcessBeanFactory(beanFactory);
  12. // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
  13. invokeBeanFactoryPostProcessors(beanFactory);
  14. // 注册 BeanPostProcessor 的实现类
  15. registerBeanPostProcessors(beanFactory);
  16. // 初始化MessageSource
  17. initMessageSource();
  18. // 初始化事件广播器
  19. initApplicationEventMulticaster();
  20. // 扩展点
  21. onRefresh();
  22. // 注册事件监听器
  23. registerListeners();
  24. // 初始化所有的 singleton beans
  25. finishBeanFactoryInitialization(beanFactory);
  26. // 广播事件
  27. finishRefresh();
  28. }
  29. catch (BeansException ex) {
  30. if (logger.isWarnEnabled()) {
  31. logger.warn("Exception encountered during context initialization - " +
  32. "cancelling refresh attempt: " + ex);
  33. }
  34. // 销毁已经初始化的的Bean
  35. destroyBeans();
  36. // 设置 'active' 状态
  37. cancelRefresh(ex);
  38. throw ex;
  39. }
  40. finally {
  41. // 清除缓存
  42. resetCommonCaches();
  43. }
  44. }
  45. }

与XML的不同点

obtainFreshBeanFactory()方法
还记得在之前的文章中列出了好几万行代码来解析这个方法,但是回忆一个这个方法是干啥的来着,创建bean容器,但是呢,bean容器在scan方法里就已经创建好了,所以这里就没必要再进行额外的逻辑了,你看现在它的代码现在多简单

  1. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  2. refreshBeanFactory();
  3. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  4. if (logger.isDebugEnabled()) {
  5. logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
  6. }
  7. return beanFactory;
  8. }
  9. protected final void refreshBeanFactory() throws IllegalStateException {
  10. if (!this.refreshed.compareAndSet(false, true)) {
  11. throw new IllegalStateException(
  12. "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
  13. }
  14. this.beanFactory.setSerializationId(getId());
  15. }

再接下来,其实就没了,有一个重点就是初始化,但是初始化逻辑是放在这个Spring家族的超级富二代DefaultListableBeanFactory身上的。

心得体会

源码阅读入门很难,面对几十兆几百兆的代码不是一时半会就能看明白的,也不是一遍两遍debug就能搞懂的。阅读源码,一定要静下心来花上几个小时甚至几天的时间来钻研。

一通百通,当你研究明白一部分以后,再去看另外的部分,就好像有人推着你走一样,无比的顺利