SpringIOC源码解析(三)基于注解

SpringIOC源码解析(三)基于注解

 

 

 

1、简介 

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

 

2、案例 

2.1、新增了一个基于注解的配置类:

@Configuration
public class AnnotationConfig {
    @Bean
    public IOCService iocService(){
        return new IOCServiceImpl();
    }
}

 

2.2、新增测试类

public class AnnotationIOCTest {

    public static void main (String args[]){
        ApplicationContext context = new AnnotationConfigApplicationContext("com.dw.study");
        IOCService iocService=context.getBean(IOCService.class);
        System.out.println(iocService.hello());
    }
}

接着我们看一下它的方法

 AnnotationConfigApplicationContextpng

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

 

3、源码分析 

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

// 创建一个新的AnnotationConfigApplicationContext,扫描给定包中的bean定义并自动刷新上下文。
    public AnnotationConfigApplicationContext(String... basePackages) {
        this();
        scan(basePackages);
        refresh();
    }

 

3.1、首先看this

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

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

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

 

3.2、注册bean 接着看scan方法

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

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

public int scan(String... basePackages) {
       // 获取当前注册bean的数量
        int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
        // 扫描包,往下看
        doScan(basePackages);

        if (this.includeAnnotationConfig) {
           // 注册配置处理器
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }
        // 返回此次注册的数量
        return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
    }

接着往下看doScan方法

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
        //遍历需要扫描的包路径
        for (String basePackage : basePackages) {
            //先跟进去看,下面的方法先忽略
            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);
                if (candidate instanceof AbstractBeanDefinition) {
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                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;
    }

扫描包

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
       //判断是否使用Filter指定忽略包不扫描
        if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
            return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
        }
        else {
            //扫描包
            return scanCandidateComponents(basePackage);
        }
}

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

public interface MetadataReader {

    Resource getResource();
    
    ClassMetadata getClassMetadata();
    
    AnnotationMetadata getAnnotationMetadata();

}

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

接着往下看

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            // 组装扫描路径(组装完成后是这种格式:classpath*:cn/shiyujun/config/**/*.class)
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + '/' + this.resourcePattern;
           // 根据路径获取资源对象
            Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
            boolean traceEnabled = logger.isTraceEnabled();
            boolean debugEnabled = logger.isDebugEnabled();
            for (Resource resource : resources) {
                if (traceEnabled) {
                    logger.trace("Scanning " + resource);
                }
                if (resource.isReadable()) {
                    try {
                         //根据资源对象通过反射获取资源对象的MetadataReader,具体就不展开说了
                        MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                       //查看配置类是否有@Conditional一系列的注解,然后是否满足注册Bean的条件
                        if (isCandidateComponent(metadataReader)) {
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            sbd.setResource(resource);
                            sbd.setSource(resource);
                            if (isCandidateComponent(sbd)) {
                                if (debugEnabled) {
                                    logger.debug("Identified candidate component class: " + resource);
                                }
                                candidates.add(sbd);
                            }
                            else {
                                if (debugEnabled) {
                                    logger.debug("Ignored because not a concrete top-level class: " + resource);
                                }
                            }
                        }
                        else {
                            if (traceEnabled) {
                                logger.trace("Ignored because not matching any filter: " + resource);
                            }
                        }
                    }
                    catch (Throwable ex) {
                        throw new BeanDefinitionStoreException(
                                "Failed to read candidate component class: " + resource, ex);
                    }
                }
                else {
                    if (traceEnabled) {
                        logger.trace("Ignored because not readable: " + resource);
                    }
                }
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
        }
        return candidates;
    }

创建BeanDefinition 现在回到开始的doScan方法

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
        //遍历需要扫描的包路径
        for (String basePackage : basePackages) {
            //获取所有符合条件的BeanDefinition
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
             //绑定BeanDefinition与Scope
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                //查看是否配置类是否指定bean的名称,如没指定则使用类名首字母小写
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                //下面两个if是处理lazy、Autowire、DependencyOn、initMethod、enforceInitMethod、destroyMethod、
// enforceDestroyMethod、Primary、Role、Description这些逻辑的
if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } //检查bean是否存在 if (checkCandidate(beanName, candidate)) { //又包装了一层 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); //检查scope是否创建,如未创建则进行创建 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); //重点来了,往下看 registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }

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

protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}

public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {


    String beanName = definitionHolder.getBeanName();
    // 注册bean,往下看
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    //如果存在别名则循环注册别名,逻辑跟上方差不多,就不展开了
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias: aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

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

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

   Assert.hasText(beanName, "Bean name must not be empty");
   Assert.notNull(beanDefinition, "BeanDefinition must not be null");

   if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(...);
      }
   }

   BeanDefinition oldBeanDefinition;

   // 所有的 Bean 注册后都会被放入到这个beanDefinitionMap 中,查看是否已存在这个bean
   oldBeanDefinition = this.beanDefinitionMap.get(beanName);

   // 处理重复名称的 Bean 定义的情况
   if (oldBeanDefinition != null) {
      if (!isAllowBeanDefinitionOverriding()) {
         // 如果不允许覆盖的话,抛异常
        throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                        "': There is already [" + oldBeanDefinition + "] bound.");
      }
      else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
         // 用框架定义的 Bean 覆盖用户自定义的 Bean
        if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
      }
      else if (!beanDefinition.equals(oldBeanDefinition)) {
         // 用新的 Bean 覆盖旧的 Bean
        if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
      }
      else {
         // log...用同等的 Bean 覆盖旧的 Bean
        if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
      }
      // 覆盖
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
      // 判断是否已经有其他的 Bean 开始初始化了.注意,"注册Bean" 这个动作结束,Bean 依然还没有初始化 在 Spring 容器启动的最后,会 预初始化 所有的 singleton beans
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            if (this.manualSingletonNames.contains(beanName)) {
               Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
               updatedSingletons.remove(beanName);
               this.manualSingletonNames = updatedSingletons;
            }
         }
      }
      else {
        

         // 将 BeanDefinition 放到这个 map 中,这个 map 保存了所有的 BeanDefinition
         this.beanDefinitionMap.put(beanName, beanDefinition);
         // 这是个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
         this.beanDefinitionNames.add(beanName);
         // 这是个 LinkedHashSet,代表的是手动注册的 singleton bean,
         this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

   if (oldBeanDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
}

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

public AnnotationConfigApplicationContext(String... basePackages) {
        this();
        scan(basePackages);
        refresh();
    }

可以看到,只剩最后一个refresh()方法了,如果看过之前文章的同学可能都已经知道这里面是什么东西了 refresh() 首先整个方法进来以后跟使用XML的时候是一样的

public void refresh() throws BeansException, IllegalStateException {
 
   synchronized (this.startupShutdownMonitor) {

      // 记录容器的启动时间、标记“已启动”状态、检查环境变量
      prepareRefresh();

      // 初始化BeanFactory容器、注册BeanDefinition
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
      prepareBeanFactory(beanFactory);

      try {
         // 扩展点
         postProcessBeanFactory(beanFactory);
         // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
         invokeBeanFactoryPostProcessors(beanFactory);

         // 注册 BeanPostProcessor 的实现类
         registerBeanPostProcessors(beanFactory);

         // 初始化MessageSource
         initMessageSource();

         // 初始化事件广播器
         initApplicationEventMulticaster();

         // 扩展点
         onRefresh();

         // 注册事件监听器
         registerListeners();


         // 初始化所有的 singleton beans
         finishBeanFactoryInitialization(beanFactory);

         // 广播事件
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // 销毁已经初始化的的Bean
         destroyBeans();

         // 设置 'active' 状态
         cancelRefresh(ex);

         throw ex;
      }

      finally {
         // 清除缓存
         resetCommonCaches();
      }
   }
}

与XML的不同点 obtainFreshBeanFactory()方法 这个方法是创建bean容器,但是呢,bean容器在scan方法里就已经创建好了 ,所以这里就没必要再进行额外的逻辑了,你看现在它的代码现在多简单

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }
protected final void refreshBeanFactory() throws IllegalStateException {
        if (!this.refreshed.compareAndSet(false, true)) {
            throw new IllegalStateException(
                    "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
        }
        this.beanFactory.setSerializationId(getId());
    }

 

再接下来,其实就没了。

 

posted @ 2023-07-09 16:47  邓维-java  阅读(58)  评论(0)    收藏  举报