Spring加载BeanDefinition的过程分析

     分析的类: AnnotationConfigWebApplicationContext.class Springboot启动的时候没有采用这个,具体Springboot的启动方式见后边的文章。
      加载BeanDefinition的过程:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
   //获取reader
   AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
    //初始化扫描工具类
   ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
    //初始化Bean名字生产器
   BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
   if (beanNameGenerator != null) {
      reader.setBeanNameGenerator(beanNameGenerator);
      scanner.setBeanNameGenerator(beanNameGenerator);
      beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
   }
   ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
   if (scopeMetadataResolver != null) {
      reader.setScopeMetadataResolver(scopeMetadataResolver);
      scanner.setScopeMetadataResolver(scopeMetadataResolver);
   }
   if (!this.annotatedClasses.isEmpty()) {
      reader.register(ClassUtils.toClassArray(this.annotatedClasses));
   }
   if (!this.basePackages.isEmpty()) {
      scanner.scan(StringUtils.toStringArray(this.basePackages));
   }
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {
      for (String configLocation : configLocations) {
         try {
            Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
            if (logger.isTraceEnabled()) {
               logger.trace("Registering [" + configLocation + "]");
            }
            //注解类加入到容器当中
            //此过程已经分析过,详见: AnnotationConfigApplicationContext初始化过程中的 详解 2
            reader.register(clazz); 
         }catch (ClassNotFoundException ex) {
            if (logger.isTraceEnabled()) {
               logger.trace("Could not load class for config location [" + configLocation +
                     "] - trying package scan. " + ex);
            }
            //开始扫描此路径下的Bean
            int count = scanner.scan(configLocation);详见 下面介绍
            if (count == 0 && logger.isDebugEnabled()) {
               logger.debug("No annotated classes found for specified class/package [" + configLocation + "]");
            }
         }
      }
   }
}

 

 scanner.scan(configLocation); // 扫描basePackge路径下的BeanDefinition,并注册到容器当中

public int scan(String... basePackages) {
   int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
    //扫描并且将BeanDefinition注册到容器当中
   doScan(basePackages);
   // Register annotation config processors, if necessary.
   if (this.includeAnnotationConfig) {
      AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
   }
   return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

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) {
        // 此方法会把该包下面所有的Bean都扫描进去
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
      for (BeanDefinition candidate : candidates) {
        //获取元数据信息
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
        //解析作用域
         candidate.setScope(scopeMetadata.getScopeName());
        //生存Bean的名字
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         if (candidate instanceof AbstractBeanDefinition) {
            //只是添加些默认的Bean定义信息,并不是执行后置处理器
            postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); 
         }
         if (candidate instanceof AnnotatedBeanDefinition) {
            //完善比如Bean上的一些注解信息:比如@Lazy、@Primary、@DependsOn、@Role、@Description @Role注解用于Bean的分类分组
            AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
         }
            //检测传入的Bean的名字和Definition是否与原来的冲突
         if (checkCandidate(beanName, candidate)) {
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
            definitionHolder =
                  AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder);
            //将Bean的定义信息注册到容器当中去。
            registerBeanDefinition(definitionHolder, this.registry);
         }
      }
   }
   return beanDefinitions;
}

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
   if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
    //Spring5做的优化,暂时没有用到
      return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
   }
   else {
      return scanCandidateComponents(basePackage);
   }
}

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
   Set<BeanDefinition> candidates = new LinkedHashSet<>();
   try {
      //生成包搜索路径
      String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
       //资源加载器 加载搜索路径下的 所有class 转换为 Resource[] 详见下边 图片1
       //注意:这里会拿到类路径下(不包含jar包内的)的所有的.class文件 可能有上百个,然后后面再交给后面进行筛选~~~~~~~~~~~~~~~~(这个方法,其实我们也可以使用) 
       // 真正干事的为:PathMatchingResourcePatternResolver#getResources方法
      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);
            // 根据TypeFilter过滤排除组件。因为AppConfig没有标准@Component或者子注解,所以肯定不属于候选组件  返回false
            // 注意:这里一般(默认处理的情况下)标注了默认注解的才会true,什么叫默认注解呢?主要就是@Component 
               if (isCandidateComponent(metadataReader)) {
                 //把符合条件的 类转换成 BeanDefinition
                  ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                  sbd.setResource(resource);
                  sbd.setSource(resource);
                  //@Lookup:主要解决单例Bean和原型Bean相互依赖的问题,比如一个单例的Bean依赖一个非单例的原生的Bean。因为注入的时候没发变化,采用这个注解可以解决,就等于每次用的时候getBean一次。  
                 // 再次判断 如果是实体类 返回true,如果是抽象类,但是抽象方法 被 @Lookup 注解注释返回true (注意 这个和上面那个是重载的方法)
                 // 这和上面是个重载方法 个人觉得旨在处理循环引用以及@Lookup上
                  if (isCandidateComponent(sbd)) {
                     candidates.add(sbd);
                  }
            }
            catch (Throwable ex) {
            }
         }
      }
   }  
   catch (IOException ex) {
      throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
   }
   return candidates;
}

                                                                  图片一

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值