Java-第十五部分-源码解读-Spring注解配置类的扫描过程

206 阅读7分钟

源码解读全文

Spring扫描

  • @ComponentScan注解
  • 构造扫描器,并配置 ClassPathBeanDefinitionScanner
  • 开始扫描
  • 拼接扫描路径,获取所有的class资源
  • ASM技术读取类元数据,判定是否能成为一个Bean,并经过过滤器处理,加入候选集
  • 去重,生成BeanDefinition,注册到容器中

入口

  • 初始化Spring时,调用AbstractApplicationContext中的refresh,其中会进行各种初始化
  • BeanFactory进行注册中心的后置增强时,其中的ConfigurationClassPostProcessor,会进行@Component扫描,得到BeanDefinition,注册到beanFactory image.png
  • 解析配置类,解析发现@ComponentScan,会扫描对应的路径下的类,获得对应的BeanDefinition

ConfigurationClassPostProcessor

  • 通过调用postProcessBeanDefinitionRegistry,遍历所有的BeanNamescheckConfigurationClassCandidate检查是否为配置类
  • 创建一个解析器,进行遍历parse, 最终调用doProcessConfigurationClass,进行配置类解析,解析配置类的注解 image.png
  • 处理配置类上的ComponentScan,获取其各个属性,获取需要解析的路径 image.png
  • 单个处理ComponentScan
if (!componentScans.isEmpty() &&
      !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
   for (AnnotationAttributes componentScan : componentScans) {
      // 对该注解的路径进行扫描,将`BeanDefinition`加入集合
      Set<BeanDefinitionHolder> scannedBeanDefinitions =
            this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
      for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
         BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
         if (bdCand == null) {
            bdCand = holder.getBeanDefinition();
         }
         // 检查扫描出来的`BeanDefinition`是否有配置类
         if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
             //需要进一步解析,相当于递归解析,又是通过`doProcessConfigurationClass`进行解析
            parse(bdCand.getBeanClassName(), holder.getBeanName());
         }
      }
   }
}
  • 还会处理@Import/@ImportResource/@Bean,AOP的处理就是通过@Import导入后置处理器

checkConfigurationClassCandidate

  • 检查是否是配置类
  1. full模式,有注解@Configuration,配置类的Bean为cglib代理对象,在类中@Bean发生依赖时,保证只有一个,会先从IOC容器中获取
  2. lite模式,在类中@Bean发生依赖时,如果是通过方法调用,会进行多次生成
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
// 存在@Configuration 且 proxyBeanMethods 不为 false,是FULL配置类
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
   beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
//存在 @Configuration 且 proxyBeanMethods 为 false
//不存在 @Configuration 存在 @Component @ComponentScan @Import @ImportREsource
//不存在 @Configuration 存在 @Bean
else if (config != null || isConfigurationCandidate(metadata)) {
   beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
   return false;
}
  • isConfigurationCandidate image.png image.png

ComponentScanAnnotationParser

  • parse解析配置类
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, String declaringClass) {
    //扫描器,传入Spring容器注册中心
    //`useDefaultFilters`属性值,默认为true,使用默认的`include`过滤器
   ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
         componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
    //获取`nameGenerator`,`BeanName`生成器,可以通过实现`BeanNameGenerator`,自定义`BeanName`生成规则
   Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
   //如果没有修改当前属性,就使用默认的生成器
   boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
   scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
         BeanUtils.instantiateClass(generatorClass));
    //读取不能直接注入Bean时,代理生成的模式
   ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
   if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
      scanner.setScopedProxyMode(scopedProxyMode);
   }
   else {
      Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
      scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
   }
    //设置资源扫描的格式,"**/*.class" 默认为当前目录下的.class文件
   scanner.setResourcePattern(componentScan.getString("resourcePattern"));
    //设置include过滤器
   for (AnnotationAttributes includeFilterAttributes : componentScan.getAnnotationArray("includeFilters")) {
      List<TypeFilter> typeFilters = TypeFilterUtils.createTypeFiltersFor(includeFilterAttributes, this.environment,
            this.resourceLoader, this.registry);
      for (TypeFilter typeFilter : typeFilters) {
         scanner.addIncludeFilter(typeFilter);
      }
   }
   //设置排除过滤器,过滤掉不需要的类
   for (AnnotationAttributes excludeFilterAttributes : componentScan.getAnnotationArray("excludeFilters")) {
      List<TypeFilter> typeFilters = TypeFilterUtils.createTypeFiltersFor(excludeFilterAttributes, this.environment,
         this.resourceLoader, this.registry);
      for (TypeFilter typeFilter : typeFilters) {
         scanner.addExcludeFilter(typeFilter);
      }
   }
   //是否配置懒加载,默认是非懒加载的
   boolean lazyInit = componentScan.getBoolean("lazyInit");
   if (lazyInit) {
      scanner.getBeanDefinitionDefaults().setLazyInit(true);
   }
    //设置扫描路径 basePackages 等价于 value
   Set<String> basePackages = new LinkedHashSet<>();
   String[] basePackagesArray = componentScan.getStringArray("basePackages");
   for (String pkg : basePackagesArray) {
       //按照规则拆分
      String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
            ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
      Collections.addAll(basePackages, tokenized);
   }
   // 获取 basePackageClasses 所处的包名,作为扫描路径
   for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
      basePackages.add(ClassUtils.getPackageName(clazz));
   }
   //如果为空,扫描路径为被注解类的包
   if (basePackages.isEmpty()) {
      basePackages.add(ClassUtils.getPackageName(declaringClass));
   }
    //增加一个排除器,如果扫描到当前的配置类,且当前的配置类直接被传给容器,已被注册,那就不用处理
   scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
      @Override
      protected boolean matchClassName(String className) {
         return declaringClass.equals(className);
      }
   });
   // 最终进行扫描
   return scanner.doScan(StringUtils.toStringArray(basePackages));
}

默认BeanName生成器

  • AnnotationBeanNameGenerator为默认的BeanName生成器
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
   if (definition instanceof AnnotatedBeanDefinition) {
      String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
      if (StringUtils.hasText(beanName)) {
         // Explicit bean name found.
         return beanName;
      }
   }
   // Fallback: generate a unique default bean name.
   return buildDefaultBeanName(definition, registry);
}
  • 获取自定义BeanName image.png
  • 没有自定义BeanName的处理
protected String buildDefaultBeanName(BeanDefinition definition) {
   String beanClassName = definition.getBeanClassName();
   Assert.state(beanClassName != null, "No bean class name set");
   //获取短名
   String shortClassName = ClassUtils.getShortName(beanClassName);
   return Introspector.decapitalize(shortClassName);
}
  • 调用JDK方法decapitalize,首字母小写返回,如果前两个字母大写直接返回
public static String decapitalize(String name) {
    if (name == null || name.length() == 0) {
        return name;
    }
    //前两个大写
    if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                    Character.isUpperCase(name.charAt(0))){
        return name;
    }
    char[] chars = name.toCharArray();
    //第一个变小写
    chars[0] = Character.toLowerCase(chars[0]);
    return new String(chars);
}

ScopedProxy

  • 当一个类被注解为@Scope(WebApplicationContext.SCOPE_REQUEST),只有接收到请求后,才会生成Bean,而又被需要被注入到另一个Bean

Spring会先创建一个代理对象进行注入,当接收到请求时,真正创建一个Bean

  • Scope注解的另一个属性,为这个代理对象以什么方式生成,JDK动态代理/CGLIB
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
  • 如果Scope没有指定代理模式,会根据ComponentScanscopedProxy的模式,那么就能解决当需要注入,但是又不能生成注入Bean,通过对代理对象进行注入的情况

useDefaultFilters

  • 默认为true,由Spring添加三个include过滤器
  1. @Component
  2. @ManagedBean
  3. @Named image.png

addExcludeFilter

  • 排除扫描的资源
// 排除过滤方式,ASSIGNABLE_TYPE为指定的类
excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UserService.class)}
  • 以注解的形式排除,被该注解修饰的类被排除
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = InitExclude.class)}

doScan

  • ClassPathBeanDefinitionScanner下,执行扫描逻辑
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) {
          //设置 Scope
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
         candidate.setScope(scopeMetadata.getScopeName());
         //生成 beanName
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         if (candidate instanceof AbstractBeanDefinition) {
            postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
         }
         if (candidate instanceof AnnotatedBeanDefinition) {
          //解析各类注解
          //`Lazy/Primary/DependsOn/Role/Description` 
            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;
}
  • findCandidateComponents真正扫描
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
   if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
       //优化机制扫描,在META-INF包下创建spring.components
       //告诉spring指定扫描的类
      return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
   }
   else {
      return scanCandidateComponents(basePackage);
   }
}

scanCandidateComponents

  • 扫描资源
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
   Set<BeanDefinition> candidates = new LinkedHashSet<>();
   try {
      //拼接包路径 "classpath*:" - CLASSPATH_ALL_URL_PREFIX
      String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
       //拿到所有的资源,其实就是.class
      Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
      boolean traceEnabled = logger.isTraceEnabled();
      boolean debugEnabled = logger.isDebugEnabled();
      for (Resource resource : resources) {
         if (traceEnabled) {
            logger.trace("Scanning " + resource);
         }
         try {
             //类元数据信息读取器 ASM技术生成,不涉及类的加载
            MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
            //过滤器处理
            if (isCandidateComponent(metadataReader)) {
               ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
               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 {
            ...处理异常
   }
   return candidates;
}
  • isCandidateComponent,处理过滤器逻辑
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
   for (TypeFilter tf : this.excludeFilters) {
       //是否跟某个排除器匹配,就会被排除
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
         return false;
      }
   }
   //没有被排除,有可能是Bean,需要被一个`include`匹配,才能成为Bean
   for (TypeFilter tf : this.includeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
          //处理条件注解
         return isConditionMatch(metadataReader);
      }
   }
   return false;
}
  • isCandidateComponent
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
   AnnotationMetadata metadata = beanDefinition.getMetadata();
   // isIndependent 独立类,非内部类,内部类不能成为Bean,静态内部类可以成为Bean,不依赖外部的对象
   // isConcrete 具体类,非抽象和接口,抽象和接口不能生成实例化对象
   // 是抽象类,且有`@LookUp`注解修饰的方法
   return (metadata.isIndependent() && (metadata.isConcrete() ||
         (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}

checkCandidate

  • 去重,key-value形式保存beanDefinition
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
    //不包含这个 beanName的 BeanDefinition 才会保存
   if (!this.registry.containsBeanDefinition(beanName)) {
      return true;
   }
   //已存在的 BeanDefinition
   BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
   BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
   if (originatingDef != null) {
      existingDef = originatingDef;
   }
   // 现在的 BeanDefinition 不会存到容器中,不影响接下来的流程
   // 检查 两个 BeanDefinition BeanName名字和包类 是否一样
   // 是同一个,重复扫描,不需要抛异常
   // 两个 BeanName相同,但是类型不同,名称冲突,抛异常
   if (isCompatible(beanDefinition, existingDef)) {
      return false;
   }
   throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
         "' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
         "non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}

LookUp

  • 拥有@LookUp修饰的方法的抽象类,会生成代理对象
  • 负责找Bean,不管方法内部怎么执行,最终返回属性中的Bean
@Lookup("orderService")
public OrderService init() {
   //System.out.println("init...");
   //查数据库 初始化 admin
   return null;
}
  • 当希望对于一个单例Bean中,每次调用其中的某个Bean是多例的,用@LookUp修饰方法,获取该Bean
  • 对于在配置类中@Bean,导入的Bean是使用@Lookup方法是无效的

ASM机制

  • 通过反射获取类信息,包中类太多,启动时需要加载很多类,需要确定该类是否是一个Bean
  • ASM机制不需要加载类,通过字节码规范进行类信息读取
InputStream inputStream = new FileInputStream("/Users/mzx/Desktop/java/spring-source/spring-framework/spring-source-learning/build/classes/java/main/com/java/service/UserService.class");
ClassReader classReader = new ClassReader(inputStream);
System.out.println(classReader.getClassName());
System.out.println(classReader.getSuperName());