spring扫描原理ClassPathBeanDefinitionScanner以及配置类的区别

spring中的扫描流程

spring扫描流程源码解析

  • spring在容器启动时调用invokeBeanFactoryPostProcessors方法完成了spring的扫描;主要调用 ConfigurationClassPostProcessor类完成扫描和full类型配置类通过cglib转换成代理类。先执行postProcessBeanDefinitionRegistry方法完成了配置类的扫描,在调用postProcessBeanFactory方法完成配置类的代理类的转换
#### 在processConfigBeanDefinitions方法中完成配置类BeanDefintion的标识(full或lite类型)

* 1.遍历BeanFactory的BeanDefinitionMap,调用 ConfigurationClassUtils.checkConfigurationClassCandidate方法标志配置类类型(会过滤spring内置的BeanDefition)
* 2.配置类按@Order的顺序进行排序,获取当前容器中(单例池中的BeanNameGenerator名称生成器)
* 3.创建ConfigurationClassParser配置类解析器,并在构造方法中生成ComponentScanAnnotationParser注解扫描器(是用来解析@ComponentScan注解)
scss 复制代码
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
   List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
   String[] candidateNames = registry.getBeanDefinitionNames();
   //遍历beanFactory中的beanDefinitionMap-主要是spring内置的和api手动注册的BeanDefinition
   for (String beanName : candidateNames) {

      BeanDefinition beanDef = registry.getBeanDefinition(beanName);

      //判断当前BeanDefinition是个全配置类(被@Configuration注解修饰过)是否被解析过。
      //1.当前BeanDefinition是否是个全配置类
      //2.该全配置类BeanDefinition是否已经被处理过
      if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
         if (logger.isDebugEnabled()) {
            logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
         }
      }

      //对beanDefinition是否是个全配置类或半配置类的标志设置值(在此会过滤spring中内置的BeanDefinition)
      else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
         configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
      }
   }

   // Return immediately if no @Configuration classes were found
   if (configCandidates.isEmpty()) {
      return;
   }

   // Sort by previously determined @Order value, if applicable
   //对配置类按着@Order的顺序进行排序
   configCandidates.sort((bd1, bd2) -> {
      int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
      int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
      return Integer.compare(i1, i2);
   });

   // Detect any custom bean name generation strategy supplied through the enclosing application context
   SingletonBeanRegistry sbr = null;
   if (registry instanceof SingletonBeanRegistry) {
      sbr = (SingletonBeanRegistry) registry;
      if (!this.localBeanNameGeneratorSet) {
         //获取bean名称生成策略,获取容器中(单例池中是否存在BeanNameGenerator)
         BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
         //一般情况是false 除非通过api往单例池中手动添加了一个
         if (generator != null) {
            this.componentScanBeanNameGenerator = generator;
            this.importBeanNameGenerator = generator;
         }
      }
   }

   if (this.environment == null) {
      this.environment = new StandardEnvironment();
   }

   // Parse each @Configuration class
   //生成ConfigurationClassParser 配置类扫描器(用于解析配置类的),构造方法会生成ComponentScanAnnotationParser注解扫描器(是用来解析@ComponentScan注解)
   ConfigurationClassParser parser = new ConfigurationClassParser(
         this.metadataReaderFactory, this.problemReporter, this.environment,
         this.resourceLoader, this.componentScanBeanNameGenerator, registry);


   //遍历合格的配置类BeanDefinition---configCandidates
   Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
   Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
   do {
      StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
      parser.parse(candidates);
      parser.validate();

      Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
      configClasses.removeAll(alreadyParsed);

      // Read the model and create bean definitions based on its content
      if (this.reader == null) {
         this.reader = new ConfigurationClassBeanDefinitionReader(
               registry, this.sourceExtractor, this.resourceLoader, this.environment,
               this.importBeanNameGenerator, parser.getImportRegistry());
      }
      this.reader.loadBeanDefinitions(configClasses);
      alreadyParsed.addAll(configClasses);
      processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();

      candidates.clear();
      if (registry.getBeanDefinitionCount() > candidateNames.length) {
         String[] newCandidateNames = registry.getBeanDefinitionNames();
         Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
         Set<String> alreadyParsedClasses = new HashSet<>();
         for (ConfigurationClass configurationClass : alreadyParsed) {
            alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
         }
         for (String candidateName : newCandidateNames) {
            if (!oldCandidateNames.contains(candidateName)) {
               BeanDefinition bd = registry.getBeanDefinition(candidateName);
               if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                     !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                  candidates.add(new BeanDefinitionHolder(bd, candidateName));
               }
            }
         }
         candidateNames = newCandidateNames;
      }
   }
   while (!candidates.isEmpty());

   // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
   if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
      sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
   }

   if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
      // Clear cache in externally provided MetadataReaderFactory; this is a no-op
      // for a shared cache since it'll be cleared by the ApplicationContext.
      ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
   }
}
kotlin 复制代码
public static boolean checkConfigurationClassCandidate(
      BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

   String className = beanDef.getBeanClassName();
   if (className == null || beanDef.getFactoryMethodName() != null) {
      return false;
   }
   //BeanDefinition中注解的元数据信息,主要通过ASM字节码获取到的
   AnnotationMetadata metadata;
   if (beanDef instanceof AnnotatedBeanDefinition &&
         className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
      // Can reuse the pre-parsed metadata from the given BeanDefinition...
      metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
   }
   else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
      // Check already loaded Class if present...
      // since we possibly can't even load the class file for this Class.
      Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();

      //过滤spring中内置的那些BeanDefinition,因为内置的5个类(spring版本不同可能会有数量差异)都是实现了这四个接口
      if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
            BeanPostProcessor.class.isAssignableFrom(beanClass) ||
            AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
            EventListenerFactory.class.isAssignableFrom(beanClass)) {
         return false;
      }
      metadata = AnnotationMetadata.introspect(beanClass);
   }
   else {
      try {
         MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
         metadata = metadataReader.getAnnotationMetadata();
      }
      catch (IOException ex) {
         if (logger.isDebugEnabled()) {
            logger.debug("Could not find class file for introspecting configuration annotations: " +
                  className, ex);
         }
         return false;
      }
   }


   Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());

   //判断当前类是否加了@Configuration注解,并且proxyBeanMethods为true时,则该配置类就是一个全配置类,标志成full
   if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
      beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
   }

   //当该类没有加@Configuration注解,但加了@Component,@ComponentScan,@Import,@ImportResource这四个注解时,就标记为半配置类lite
   //或者这5个注解都没有加,但存在被@Bean修饰的方法,也是个半配置类
   else if (config != null || isConfigurationCandidate(metadata)) {
      beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
   }
   else {
      return false;
   }

   // It's a full or lite configuration candidate... Let's determine the order value, if any.
   Integer order = getOrder(metadata);
   //设置Order的顺序
   if (order != null) {
      beanDef.setAttribute(ORDER_ATTRIBUTE, order);
   }

   return true;
}
##### ConfigurationClassParser.processConfigurationClass去解析配置类

* 1.判断当前配置类是否已经完成解析,未解析循环调用doProcessConfigurationClass
* 2.判断当前配置类是否加了@ComponentScans或@ComponentScan标签,调用ComponentScanAnnotationParser解析器遍历解析ComponentScan注解信息
* 3.将扫描出来的BeanDefition集合进行配置类类型标识(full or lite)
kotlin 复制代码
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
   if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
      return;
   }

   //一个配置类如果被解析完成了,就会放入configurationClasses这个缓存当中
   ConfigurationClass existingClass = this.configurationClasses.get(configClass);
   if (existingClass != null) {
      if (configClass.isImported()) {
         if (existingClass.isImported()) {
            existingClass.mergeImportedBy(configClass);
         }
         // Otherwise ignore new imported config class; existing non-imported class overrides it.
         return;
      }
      else {
         // Explicit bean definition found, probably replacing an import.
         // Let's remove the old one and go with the new one.
         this.configurationClasses.remove(configClass);
         this.knownSuperclasses.values().removeIf(configClass::equals);
      }
   }

   // Recursively process the configuration class and its superclass hierarchy.
   SourceClass sourceClass = asSourceClass(configClass, filter);
   do {

      //循环调用,解析配置类
      sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
   }
   while (sourceClass != null);

   this.configurationClasses.put(configClass, configClass);
}

/**
 * Apply processing and build a complete {@link ConfigurationClass} by reading the
 * annotations, members and methods from the source class. This method can be called
 * multiple times as relevant sources are discovered.
 * @param configClass the configuration class being build
 * @param sourceClass a source class
 * @return the superclass, or {@code null} if none found or previously processed
 */
@Nullable
protected final SourceClass doProcessConfigurationClass(
      ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
      throws IOException {

   if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
      // Recursively process any member (nested) classes first
      //判断是否加@Component注解,加了就去处理内部类
      processMemberClasses(configClass, sourceClass, filter);
   }

   // Process any @PropertySource annotations
   //处理PropertySources注解信息
   for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
         sourceClass.getMetadata(), PropertySources.class,
         org.springframework.context.annotation.PropertySource.class)) {
      if (this.environment instanceof ConfigurableEnvironment) {
         processPropertySource(propertySource);
      }
      else {
         logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
               "]. Reason: Environment must implement ConfigurableEnvironment");
      }
   }

   // Process any @ComponentScan annotations
   Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
         sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
   if (!componentScans.isEmpty() &&
         !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {

      //遍历ComponentScans,ComponentScan中需要扫描的包路径,basePackages是个数组
      for (AnnotationAttributes componentScan : componentScans) {
         // The config class is annotated with @ComponentScan -> perform the scan immediately

         //采用ConfigurationClassParser构造方法中实例化的ComponentScanAnnotationParser组件解析@ComponentScans,@ComponentScan注解
         Set<BeanDefinitionHolder> scannedBeanDefinitions =
               this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
         // Check the set of scanned definitions for any further config classes and parse recursively if needed
         for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
            BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
            if (bdCand == null) {
               bdCand = holder.getBeanDefinition();
            }

            //判断扫描出来的配置类是否为全配置类或者是半配置类
            if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {

               //继续解析扫描出来的配置类
               parse(bdCand.getBeanClassName(), holder.getBeanName());
            }
         }
      }
   }

   // Process any @Import annotations
   processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

   // Process any @ImportResource annotations
   AnnotationAttributes importResource =
         AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
   if (importResource != null) {
      String[] resources = importResource.getStringArray("locations");
      Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
      for (String resource : resources) {
         String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
         configClass.addImportedResource(resolvedResource, readerClass);
      }
   }

   // Process individual @Bean methods
   Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
   for (MethodMetadata methodMetadata : beanMethods) {
      configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
   }

   // Process default methods on interfaces
   processInterfaces(configClass, sourceClass);

   // Process superclass, if any
   if (sourceClass.getMetadata().hasSuperClass()) {
      String superclass = sourceClass.getMetadata().getSuperClassName();
      if (superclass != null && !superclass.startsWith("java") &&
            !this.knownSuperclasses.containsKey(superclass)) {
         this.knownSuperclasses.put(superclass, configClass);
         // Superclass found, return its annotation metadata and recurse
         return sourceClass.getSuperClass();
      }
   }

   // No superclass -> processing is complete
   return null;
}
##### 调用ComponentScanAnnotationParser解析器的parse方法解析@ComponentScan注解

* 1.实例化扫描器ClassPathBeanDefinitionScanner,获取注解useDefaultFilters属性值,来判断是否需要采用spring默认的includeFilters列表(**内置了3个TypeFilter,new AnnotationTypeFilter(Component.class),以及spring对JSR支持的两个ManagedBean,Named**)
* 2.获取bean名称生成器BeanNameGenerator,**优先级(注解中配置的nameGenerator \> api注册提供的(单例池中存在的) \> spring默认名称生成器)**
* 将@ComponentScan注解中的配置信息设置给ComponentScanAnnotationParser,然后开始调用doScan方法对配置的basePackages进行解析完成扫描
typescript 复制代码
//解析@ComponentScans,@ComponentScan注解完成spring的扫描
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, String declaringClass) {

   //实例化扫描器--是否默认的Filter(默认true)
   ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
         componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

   //获取bean名称生成器 优先级(注解中配置的nameGenerator > api注册提供的(单例池中存在的) > spring默认名称生成器)
   Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
   boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
   scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
         BeanUtils.instantiateClass(generatorClass));

   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));
   }

   scanner.setResourcePattern(componentScan.getString("resourcePattern"));

   //过滤器分两种excludeFilters,includeFilters,Filter有三种种类型ANNOTATION,ASSIGNABLE_TYPE,CUSTOM

   //获取注解提供的includeFilters
   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);
      }
   }

   //获取注解提供的excludeFilters
   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);
   }

   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);
   }
   for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
      basePackages.add(ClassUtils.getPackageName(clazz));
   }
   if (basePackages.isEmpty()) {
      basePackages.add(ClassUtils.getPackageName(declaringClass));
   }

   //添加默认的excludeFilters-表示当前类是不需要进行扫描的,所以得排除
   scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
      @Override
      protected boolean matchClassName(String className) {
         return declaringClass.equals(className);
      }
   });

   //开始扫描-调用ClassPathBeanDefinitionScanner的doScan方法开始进行扫描
   return scanner.doScan(StringUtils.toStringArray(basePackages));
}
##### 调用ClassPathBeanDefinitionScanner的doScan方法开始对basePackages进行扫描

* 1.调用findCandidateComponents方法中的scanCandidateComponents方法开始进行扫描
* 2.获取basePackage下的所有类文件的Resource,主要通过io读取(并没有将Class类对象加载到jvm中)
* 3.**通过ASM字节码技术,获取类的元数据信息**,调用isCandidateComponent方法进行条件过滤 先遍历执行excludeFilters列表的TypeFilter.match方法过滤被排除的类;在遍历执行iincludeFilters列表的TypeFilter.match方筛选出合格的方法
* 将合格的类生成BeanDefition对象存到容器的BeanDefinitionMap中
scss 复制代码
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
   Set<BeanDefinition> candidates = new LinkedHashSet<>();
   try {
      //获取basePackage下的所有类文件Resource
      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);
         }
         try {
            //通过ASM字节码获取到类的元数据信息,为什么不是通过反射获取到class类对象信息?
            MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);

            //过滤符合要求的bean,并生成BeanDefinition(执行Filter进行过滤,是否添加了必要的注解等)
            if (isCandidateComponent(metadataReader)) {
               ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
               sbd.setSource(resource);

               //判断是否是接口,是否是抽象类
               if (isCandidateComponent(sbd)) {
                  if (debugEnabled) {
                     logger.debug("Identified candidate component class: " + resource);
                  }
                  //不是,则返回BeanDefinition
                  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 (FileNotFoundException ex) {
            if (traceEnabled) {
               logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
            }
         }
         catch (Throwable ex) {
            throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, ex);
         }
      }
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
   }
   return candidates;
}
##### TypeFilter中match方法进行筛选合格类

* spring扩展点-matchSelf方法
* spring扩展点-matchClassName方法
* 是否考虑considerInherited,是的话执行matchSuperClass
* 是否考虑considerInterfaces,是的话执行matchInterface
* matchSelf方法,matchClassName方法,matchSuperClass,matchInterface;spring的扩展点方法,子类可以重写完成自定义的过滤规则
kotlin 复制代码
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
      throws IOException {

   // This method optimizes avoiding unnecessary creation of ClassReaders
   // as well as visiting over those readers.
   //匹配自我-spring的扩展机制-默认为false则不会进if里面

   //spring内置默认的AnnotationTypeFilter重写方法-调用的子类的
   if (matchSelf(metadataReader)) {
      return true;
   }
   ClassMetadata metadata = metadataReader.getClassMetadata();

   //是否匹配类名称-spring的扩展机制-默认为false则不会进if里面
   if (matchClassName(metadata.getClassName())) {
      return true;
   }

   //considerInherited,considerInterfaces默认都为false

   //是否考虑扫描Inherited
   if (this.considerInherited) {
      String superClassName = metadata.getSuperClassName();
      if (superClassName != null) {
         // Optimization to avoid creating ClassReader for superclass.
         Boolean superClassMatch = matchSuperClass(superClassName);
         if (superClassMatch != null) {
            if (superClassMatch.booleanValue()) {
               return true;
            }
         }
         else {
            // Need to read superclass to determine a match...
            try {
               if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
                  return true;
               }
            }
            catch (IOException ex) {
               if (logger.isDebugEnabled()) {
                  logger.debug("Could not read superclass [" + metadata.getSuperClassName() +
                        "] of type-filtered class [" + metadata.getClassName() + "]");
               }
            }
         }
      }
   }
   //是否考虑扫描Interfaces
   if (this.considerInterfaces) {
      for (String ifc : metadata.getInterfaceNames()) {
         // Optimization to avoid creating ClassReader for superclass
         //考虑接口时,匹配规则
         Boolean interfaceMatch = matchInterface(ifc);
         if (interfaceMatch != null) {
            if (interfaceMatch.booleanValue()) {
               return true;
            }
         }
         else {
            // Need to read interface to determine a match...
            try {
               if (match(ifc, metadataReaderFactory)) {
                  return true;
               }
            }
            catch (IOException ex) {
               if (logger.isDebugEnabled()) {
                  logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
                        metadata.getClassName() + "]");
               }
            }
         }
      }
   }

   return false;
}

spring是怎么完成扫描的?

  • spring容器启动时会调用invokeBeanFactoryPostProcessors方法完成了扫描;其中是调用spring内置的ConfigurationClassBeanPostProcessor的postProcessBeanDefinitionRegistry完成了扫描
  • 首先会过滤spring内置的几个配置类的BeanDefinition后,创建ConfigurationClassParser配置类解析器去解析合格的配置类
  • 第二步判断配置类是否存在@ComponentScan注解,存在会调用ConfigurationClassParser配置类的ComponentScanAnnotationParser解析器去解析@ComponentScan注解
  • 第三步创建ClassPathBeanDefinitionScanner扫描器并将@ComponentScan注解配置信息设置给扫描器后,调用doscan方法完成basePackages的扫描
  • 第四步通过io获取到basePackages下所有的文件Resource,并通过ASM获取类的元数据信息,遍历执行excludeFilters和includeFilters列的TypeFilter的match筛选出合格的类,
  • 第5步实例化ScannedGenericBeanDefinition对象,判断是否接口是否抽象、是否加了LockUp注解等等,正常添加到列表,遍历扫描到的beanDefinition列表,标识配置类的类型(full or lite or null )后存到BeanFactory中的BeanDefinitionMap中;

spring扫描为何会有两个扫描器,区别是什么

  • spring会创建两个ClassPathBeanDefinitionScanner扫描器(构造方法和自动扫描创建),用户可以调用api手动完成扫描(context.scan方法)以及@Componnt注解的自动扫描
  • 手动调用可以完成动态化编程,是一定会执行的,而@Componnt注解的自动扫描是有加载时机的可能不会执行,也不能完成动态条件加载,但可以提供一些定制化的功能,过滤等功能;api手动扫描动态化编程功能比较少

spring扫描时为何采用ASM完成class类信息?

  • spring通过IO从磁盘上加载类文件的Resource到内存后,然后通过ASM获取类的元数据信息,并不会将类加载到jvm的元空间的中,而通过Class.forName加载类信息时,会将类对象加载jvm的元空间,会执行static代码块;这样在某些场景下出现某种错误,spring本着不打扰用户的程序的执行行为,所以采用ASM字节码去进行扫描
  • ASM字节码加载的效率是高于反射的

spring内置的三个TypeFilter以及一个AbstractTypeHierarchyTraversingFilter,以及TypeFilter的类型?

  • spring的默认includeFilters内置了三个TypeFilter,分别是AnnotationTypeFilter(Component.class),AnnotationTypeFilter(ManagedBean.class),AnnotationTypeFilter(Named.class)以及excludeFilters内置了一个AbstractTypeHierarchyTraversingFilter;
  • AbstractTypeHierarchyTraversingFilter重写matchClassName用来过滤排除当前配置类
  • AnnotationTypeFilter重写matchSelf方法来过滤当前是否加了该注解Named,ManagedBean是spring对JSR的支持,主要是解决在轻量型服务在不当不引入spring的依赖包,只引入轻量型的jar包,但该服务最终会被spring服务调用,所以spring支持这种可插拔式的配置;
###### spring的TypeFilter的类型有两种ANNOTATION:用于过滤被特定注解标记的候选者;ASSIGNABLE_TYPE:用于过滤可分配给特定类型的候选者。

spring full类型的配置类解析流程

#### spring在容器启动时调用invokeBeanFactoryPostProcessors方法完成了spring的扫描;主要调用ConfigurationClassPostProcessor的postProcessBeanFactory方法完成full类型的配置类的代理类的转换

* 1.调用enhanceConfigurationClasses方法完成full类型的配置类的解析
* 2.**向beanFactory容器添加ImportAwareBeanPostProcessor实例对象,主要是为了对full类的配置类的bean生命周期中进行属性填充阶段时,调用postProcessProperties方法对cglib增强的full类型的配置类(实现了EnhancedConfiguration接口)进行属性填充,调用setBeanFactory方法,通过动态代理调用代理对象的增强方法,通过反射将容器中的beanFactory赋值给代理类的$$beanFactory属性**;
scss 复制代码
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   int factoryId = System.identityHashCode(beanFactory);
   if (this.factoriesPostProcessed.contains(factoryId)) {
      throw new IllegalStateException(
            "postProcessBeanFactory already called on this post-processor against " + beanFactory);
   }
   this.factoriesPostProcessed.add(factoryId);
   if (!this.registriesPostProcessed.contains(factoryId)) {
      // BeanDefinitionRegistryPostProcessor hook apparently not supported...
      // Simply call processConfigurationClasses lazily at this point then.
      processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
   }

   //开始处理beanFactory中BeanDefinitionMap中被标记为full(全配置类的)BeanDefinition,完成增强生成代理类(未实例化),最后在bean的生命周期完成实例化
   enhanceConfigurationClasses(beanFactory);

   //添加ImportAwareBeanPostProcessor,主要是在完成扫描后,实例化bean时进行属性填充时
   //对全配置类(full类)时,为cglib生成的代理类设置后,将容器BeanFactory值赋值代理对象的$$BeanFactory
   beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
#### 调用enhanceConfigurationClasses创建full类型配置类的动态代理类

* 1.遍历容器中BeanDefinitionMap(spring已经完成扫描),获取full类型的BeanDefition
* 2.创建ConfigurationClassEnhancer配置类增强器,调用enhance方法生成cglib代理类
* 3.替换beanDefinition中的beanClass
scss 复制代码
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
   StartupStep enhanceConfigClasses = this.applicationStartup.start("spring.context.config-classes.enhance");
   Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();

   //此时spring已经完成了扫描,所以可能存在多个配置类(扫描出来的配置累)
   for (String beanName : beanFactory.getBeanDefinitionNames()) {
      BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);

      //获取当前BeanDefinition的配置类的类型
      Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);

      AnnotationMetadata annotationMetadata = null;
      MethodMetadata methodMetadata = null;

      //判断是否添加了注解(BeanDefinition可能手动添加的,可能是非扫描出来的)
      if (beanDef instanceof AnnotatedBeanDefinition) {
         AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDef;
         annotationMetadata = annotatedBeanDefinition.getMetadata();
         methodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
      }
      if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
         // Configuration class (full or lite) or a configuration-derived @Bean method
         // -> eagerly resolve bean class at this point, unless it's a 'lite' configuration
         // or component class without @Bean methods.
         AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
         if (!abd.hasBeanClass()) {
            boolean liteConfigurationCandidateWithoutBeanMethods =
                  (ConfigurationClassUtils.CONFIGURATION_CLASS_LITE.equals(configClassAttr) &&
                     annotationMetadata != null && !ConfigurationClassUtils.hasBeanMethods(annotationMetadata));
            if (!liteConfigurationCandidateWithoutBeanMethods) {
               try {
                  abd.resolveBeanClass(this.beanClassLoader);
               }
               catch (Throwable ex) {
                  throw new IllegalStateException(
                        "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
               }
            }
         }
      }

      //是否被标记为full(全配置类)
      if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
         if (!(beanDef instanceof AbstractBeanDefinition)) {
            throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                  beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
         }
         else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
            logger.info("Cannot enhance @Configuration bean definition '" + beanName +
                  "' since its singleton instance has been created too early. The typical cause " +
                  "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
                  "return type: Consider declaring such methods as 'static'.");
         }
         configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
      }
   }
   if (configBeanDefs.isEmpty() || NativeDetector.inNativeImage()) {
      // nothing to enhance -> return immediately
      enhanceConfigClasses.end();
      return;
   }

   ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
   for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
      AbstractBeanDefinition beanDef = entry.getValue();
      // If a @Configuration class gets proxied, always proxy the target class
      beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
      // Set enhanced subclass of the user-specified bean class
      Class<?> configClass = beanDef.getBeanClass();


      //完成full全配置类的类增强,cglib完成生成代理类
      Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
      if (configClass != enhancedClass) {
         if (logger.isTraceEnabled()) {
            logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                  "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
         }
         //替换beanDefinition的BeanClass
         beanDef.setBeanClass(enhancedClass);
      }
   }
   enhanceConfigClasses.tag("classCount", () -> String.valueOf(configBeanDefs.keySet().size())).end();
}
#### 通过cglib生成代理类

* 1.判断当前类是否已经被动态代理了
* 2.创建cglib动态代理中Enhancer增强器,配置代理类的属性,如设置父类类型,需要实现的EnhancedConfiguration接口,设置CallbackFilter,以及为代理类添加一个$$beanFactory属性字段
* 3.当调用enhancer.createClass()就会产生代理类
less 复制代码
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
   if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
      if (logger.isDebugEnabled()) {
         logger.debug(String.format("Ignoring request to enhance %s as it has " +
               "already been enhanced. This usually indicates that more than one " +
               "ConfigurationClassPostProcessor has been registered (e.g. via " +
               "<context:annotation-config>). This is harmless, but you may " +
               "want check your configuration and remove one CCPP if possible",
               configClass.getName()));
      }
      return configClass;
   }
   //完成cglib对类的增强,创建一个继承configClass实现了EnhancedConfiguration接口的代理类
   Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
   if (logger.isTraceEnabled()) {
      logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
            configClass.getName(), enhancedClass.getName()));
   }
   return enhancedClass;
}

/**
 * Creates a new CGLIB {@link Enhancer} instance.
 */
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {

   //cglib动态代理-主要是通过继承被代理类,生成子类实现cglib动态代理实现增强
   //生成增强器
   Enhancer enhancer = new Enhancer();

   //将配置类设置成代理类的父类
   enhancer.setSuperclass(configSuperClass);

   //设置代理类需要实现的接口,EnhancedConfiguration extends BeanFactoryAware 主要是完成bean作用域的完整性
   enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});



   enhancer.setUseFactory(false);
   //spring cglib中生成代理类的命名规则
   enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);

   //为代理类添加一个$$beanFactory属性字段,BeanFactoryAwareGeneratorStrategy是对CGLIB的DefaultGeneratorStrategy的扩展
   enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));

   //设置代理增强Filter,为某个方法的执行完成不同行为的增强
   //CallbackFilter会对方法进行过滤,调用accept()方法来实现对不同的方法,完成不同的行为增强
   enhancer.setCallbackFilter(CALLBACK_FILTER);

   //enhancer.setCallbacks();  setCallbacks必须要和setCallbackFilter两个搭配使用,完成对不同的方法实现不同的行为增强
   //enhancer.setCallback(); setCallback默认会对所有方法进行增强

   enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
   return enhancer;
}
#### 设置Enhancer的CallbackFilter为ConditionalCallbackFilter

* 1.spring通过ConditionalCallbackFilter完成了对不同方法的调用,实现了不同方法行为的增强(**spring主要对加了@Bean注解的方法,以及setFactory方法进行增强**),主要是通过accept方法,返回不同的Callback然后执行intercept方法实现增强。
* **@Bean注解的方法采用的是BeanMethodInterceptor的类型Callback进行增强**
* **setFactory方法采用的是BeanFactoryAwareMethodInterceptor的类型Callback进行增强**
java 复制代码
private static class ConditionalCallbackFilter implements CallbackFilter {


   //new BeanMethodInterceptor(),
   //new BeanFactoryAwareMethodInterceptor(),
   //NoOp.INSTANCE
   //设置了3种Callback的增强,BeanMethodInterceptor用于增强@bean修饰的方法,BeanFactoryAwareMethodInterceptor用于增强setBeanFactory方法
   private final Callback[] callbacks;

   private final Class<?>[] callbackTypes;

   public ConditionalCallbackFilter(Callback[] callbacks) {
      this.callbacks = callbacks;
      this.callbackTypes = new Class<?>[callbacks.length];
      for (int i = 0; i < callbacks.length; i++) {
         this.callbackTypes[i] = callbacks[i].getClass();
      }
   }


   //对不同行为方法,返回不同的callback去完成方法的增强
   //返回匹配上数组的索引下标,完成cglib对方法的增强

   //cglib可以传入多个callbacks增强,但使用时会调用accept来确认使用哪一个去进行行为方法的增强
   @Override
   public int accept(Method method) {
      for (int i = 0; i < this.callbacks.length; i++) {
         Callback callback = this.callbacks[i];
         //采用哪个Interceptor去进行增强委托给将callback.isMatch去过滤(完成控制反转),实现了接口单一原则

         //判断代理类增强的方法是否为setBeanFactory方法,是的话则使用BeanFactoryAwareMethodInterceptor
         //判断代理类增强的方法加了@Bean注解且方法名称 不为setBeanFactory是的话则使用BeanMethodInterceptor
         //全部是则使用NoOp.INSTANCE去进行增强(什么都不做,即不进行增强)
         if (!(callback instanceof ConditionalCallback) || ((ConditionalCallback) callback).isMatch(method)) {
            return i;
         }
      }
      throw new IllegalStateException("No callback available for method " + method.getName());
   }

   public Class<?>[] getCallbackTypes() {
      return this.callbackTypes;
   }
}
  • spring是如何处理full类型的配置类?

  • mybatis整合spring是如何完成Mapper的扫描的,整合springboot是如何完成扫描的

什么是full,lite类型的配置类,二者有什么区别?

  • full类型的配置类是一个被cglib增强-转换成动态代理的类,并保证了了@bean产生的bean对象的作用域的完整性,而lite类型的配置类不会被cglib增强代理且不能保证bean对象的作用域的完整性

怎么查看cglib动态生成的类

java 复制代码
public static void saveGeneratedCGlibProxyFiles(String dir) throws Exception {

Field field = System.class.getDeclaredField("props");

field.setAccessible(true);

Properties props = (Properties) field.get(null);

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, dir);//dir为

保存文件路径

props.put("net.sf.cglib.core.DebuggingClassWriter.traceEnabled", "true");

}
相关推荐
coderWangbuer1 小时前
基于springboot的高校招生系统(含源码+sql+视频导入教程+文档+PPT)
spring boot·后端·sql
攸攸太上1 小时前
JMeter学习
java·后端·学习·jmeter·微服务
Kenny.志1 小时前
2、Spring Boot 3.x 集成 Feign
java·spring boot·后端
sky丶Mamba1 小时前
Spring Boot中获取application.yml中属性的几种方式
java·spring boot·后端
千里码aicood2 小时前
【2025】springboot教学评价管理系统(源码+文档+调试+答疑)
java·spring boot·后端·教学管理系统
程序员-珍3 小时前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
liuxin334455663 小时前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
数字扫地僧3 小时前
HBase与Hive、Spark的集成应用案例
后端
架构师吕师傅3 小时前
性能优化实战(三):缓存为王-面向缓存的设计
后端·微服务·架构
bug菌4 小时前
Java GUI编程进阶:多线程与并发处理的实战指南
java·后端·java ee