Use of annotations

public static void main(String[] args) {
   ApplicationContext context = new AnnotationConfigApplicationContext(
         "edu.demo.spring.bean"."edu.demo.spring.ext");
   Boy boy = context.getBean(Lad.class);
   boy.sayLove();
}
Copy the code

Here is the sample code. The main steps are as follows:

Need, the debug analysis under DefaultListableBeanFactory class, registerBeanDefinition interrupt point for debugging analysis method.


Load processing of annotations

Here is the detailed call stack information:

Step one: AnnotationConfigApplicationContext

/ * * * create a AnnotationConfigApplicationContext container, then scanning the components in the context of the given package * to these components are registered as bean definition information, automatically refresh the container and *@paramBasePackages scans packages of component classes. Multiple */ can be defined
public AnnotationConfigApplicationContext(String... basePackages) {
   this(a); scan(basePackages); refresh(); }Copy the code
/** * In this constructor, Build AnnotatedBeanDefinitionReader and ClassPathBeanDefinitionScanner * * AnnotatedBeanDefinitionReader used to unscramble annotation information objects ClassPathBeanDefinitionScanner is used to scan the package * /
public AnnotationConfigApplicationContext(a) {
   this.reader = new AnnotatedBeanDefinitionReader(this);
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}
Copy the code

AnnotationConfigApplicationContext class, the main work is in the constructor AnnotatedBeanDefinitionReader and ClassPathBeanDefinitionScanner object is constructed.

The second step: AnnotatedBeanDefinitionReader

/ * * * from the given Bean definition registered in the interface to create a AnnotatedBeanDefinitionReader * then initialize AnnotatedBeanDefinitionReader * /
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    this(registry, getOrCreateEnvironment(registry));
}

/** * Obtain Environment * from BeanDefinitionRegistry; if not, return StandardEnvironment */
private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    if (registry instanceof EnvironmentCapable) {
        return ((EnvironmentCapable) registry).getEnvironment();
    }
    return new StandardEnvironment();
}

 public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
     // Non-null judgment
     Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
     Assert.notNull(environment, "Environment must not be null");
     this.registry = registry;
     this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
     AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
Copy the code

In AnnotatedBeanDefinitionReader class, mainly to do, is to initialize AnnotatedBeanDefinitionReader object.

Step 3: AnnotationConfigUtils

/** * register all processors related to annotation configuration with BeanFactory *@param registry the registry to operate on
    */
   public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
      registerAnnotationConfigProcessors(registry, null);
   }


 /** * register all processors related to annotation configuration, register with BeanFactory */
 public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
         BeanDefinitionRegistry registry, @Nullable Object source) {...// Register the various processors to be used as bean definitions, then inject them into the bean factory and use them as beans
     Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

     // @configuration annotates the class post processor
     if(! registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition(ConfigurationClassPostProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
     }

     // @autoWired annotates the class post processor
     if(! registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
     }

     // Check whether jSR-250 is supported
     if(jsr250Present && ! registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
     }

     // Check whether JPA is supported
     if(jpaPresent && ! registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition();
         try {
             def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                     AnnotationConfigUtils.class.getClassLoader()));
         }
         catch (ClassNotFoundException ex) {
             throw new IllegalStateException(
                     "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
         }
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
     }

     if(! registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition(EventListenerMethodProcessor.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
     }

     if(! registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition(DefaultEventListenerFactory.class);
         def.setSource(source);
         beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
     }

     return beanDefs;
 }
 

private static BeanDefinitionHolder registerPostProcessor( BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

   definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
   registry.registerBeanDefinition(beanName, definition);
   return new BeanDefinitionHolder(definition, beanName);
}
Copy the code

This step registers the Processor configured with annotations into the internal BeanFactory. What does this Processor do?

In addition to loading and registering its own beans during annotation loading, Spring also internally injects various beans into the factory to handle the logic. For example, in the code above, processing objects related to annotation Bean definitions are injected into the factory through Bean definitions.

Step 4:

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

   this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
Copy the code

Register the handler’s Bean definition information with the BeanFactory.

Looking at the call stack above, we do not register our own Bean definition information, but some processors. And I didn’t see it do the scanning.

See from the first step in the code, in the constructor of AnnotationConfigApplicationContext here is, the second step is to perform scan method, the third step is the refresh method. Annotations are made in the form of various initialization preparations in the constructor, whereas XML is made in the form of Bean definitions registered in the refresh method.

RegisterAnnotationConfigProcessors, understanding from the method name, is the registered some annotations configuration of the processor, from ConfigurationClassPostProcessor see below, What exactly are these processors used for?

/ * * * {@link BeanFactoryPostProcessor} used for bootstrapping processing of
 * {@link Configuration @Configuration} classes.
 *
 * <p>Registered by default when using {@code <context:annotation-config/>} or
 * {@code<context:component-scan/>}. Otherwise, may be declared manually as * with any other BeanFactoryPostProcessor. * * <p>This post processor is priority-ordered as  it is important that any * {@link Bean} methods declared in {@code @Configuration} classes have
 * their corresponding bean definitions registered before any other
 * {@link BeanFactoryPostProcessor} executes.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @author Phillip Webb
 * @since3.0 * /
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor.PriorityOrdered.ResourceLoaderAware.BeanClassLoaderAware.EnvironmentAware {}Copy the code

As you can see from the comments, this is the BeanFactoryPostProcessor used to process the @Configuration annotation at startup, but you don’t see BeanFactoryPostProcessor here, But there is an interface BeanDefinitionRegistryPostProcessor, point in you can see, the parent is spring BeanFactoryPostProcessor.

ConfigurationClassPostProcessor inheritance system is as follows:

See below BeanDefinitionRegistryPostProcessor:

/**
 * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
 * the registration of further bean definitions <i>before</i> regular
 * BeanFactoryPostProcessor detection kicks in. In particular,
 * BeanDefinitionRegistryPostProcessor may register further bean definitions
 * which in turn define BeanFactoryPostProcessor instances.
 *
 * @author Juergen Hoeller
 * @since 3.0.1
 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor
 */
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

   /**
    * Modify the application context's internal bean definition registry after its
    * standard initialization. All regular bean definitions will have been loaded,
    * but no beans will have been instantiated yet. This allows for adding further
    * bean definitions before the next post-processing phase kicks in.
    * @param registry the bean definition registry used by the application context
    * @throws org.springframework.beans.BeansException in case of errors
    */
   void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
Copy the code

BeanDefinitionRegistryPostProcessor expanded the spring BeanFactoryPostProcessor, increased processing BeanDefinitionRegistry position, This means that it can pre-process the registered BeanDefinitionRegistry

From the picture above you can see, in the process of building a bean, the arrow points to place, can be extended, so it is not hard to see BeanDefinitionRegistryPostProcessor role

Take another look at BeanFactoryPostProcessor:

@FunctionalInterface
public interface BeanFactoryPostProcessor {

   /**
    * Modify the application context's internal bean factory after its standard
    * initialization. All bean definitions will have been loaded, but no beans
    * will have been instantiated yet. This allows for overriding or adding
    * properties even to eager-initializing beans.
    * @param beanFactory the bean factory used by the application context
    * @throws org.springframework.beans.BeansException in case of errors
    */
   void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}
Copy the code

As you can see from the comment information above, all you’re doing here is doing what you want to do with the bean definition information in the BeanFactory before all the bean definitions have been loaded, but not instantiated.

This is one of the extension points provided by Spring to do some processing on the bean definition information in the BeanFactory before the BeanFactory starts creating bean instances

To load an external configuration file:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
   <property name="locations" value="classpath:application.properties"/>
</bean>
Copy the code

Here’s a simple implementation example:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      System.out.println(this + "Spring BeanFactoryPostProcessor work..."); }}Copy the code

In the test class, add a scan of the package where the above class resides:

ApplicationContext context = new AnnotationConfigApplicationContext(
      "edu.demo.spring");
Copy the code

Here is its call stack:

In PostProcessorRegistrationDelegate. InvokeBeanFactoryPostProcessors create and execute the MyBeanFactoryPostProcessor.

The output is as follows:

The relationship between the IOC container and BeanFactoryPostProcessor


The scanning process of annotations

In the above position to set breakpoints, and then release, finally to DefaultListableBeanFactory. RegisterBeanDefinition breakpoints can get the call stack.

The first step:

/** * scan within the specified package * <p>Note that {@link #refresh()} must be called in order for the context
 * to fully process the new classes.
 * @param basePackages the packages to scan for component classes
 * @see #register(Class...)
 * @see #refresh()
 */
@Override
public void scan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   this.scanner.scan(basePackages);
}
Copy the code
/ * * * in the specified package scanning operation on * construct and initialize ClassPathBeanDefinitionScanner scanner object, start scanning *@param basePackages the packages to check for annotated classes
 * @return number of beans registered
 */
public int scan(String... basePackages) {
   // Get the number of bean definitions scanned
   int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

   doScan(basePackages);

   // Register annotation config processors, if necessary.
   if (this.includeAnnotationConfig) {
      AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
   }

   return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
Copy the code

The second step:

/**
 * Perform a scan within the specified base packages,
 * returning the registered bean definitions.
 * <p>This method does <i>not</i> register an annotation config processor
 * but rather leaves this up to the caller.
 * @param basePackages the packages to check for annotated classes
 * @return set of beans registered if any for tooling registration purposes (never {@code null})
 */
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {}Copy the code

Completes the scan of the bean definitions under the package name and returns the collection of registered bean definitions.

Step 3:

// Complete the registration of the bean definition to the bean factory
registerBeanDefinition(String, BeanDefinition):929, DefaultListableBeanFactory

(org.springframework.beans.factory.support)

registerBeanDefinition(String, BeanDefinition):323, GenericApplicationContext

(org.springframework.context.support)

registerBeanDefinition(BeanDefinitionHolder, BeanDefinitionRegistry):164,

BeanDefinitionReaderUtils (org.springframework.beans.factory.support)

registerBeanDefinition(BeanDefinitionHolder, BeanDefinitionRegistry):320,

ClassPathBeanDefinitionScanner (org.springframework.context.annotation)
Copy the code

The important part is in the doScan method. Here’s what it does:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
   // Iterate over the packages to be scanned
   for (String basePackage : basePackages) {
      // Find all candidate components (configured beans) under the specified package
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
      // Scan all candidate components
      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);
            // Register the bean definition in the BeanFactory
            registerBeanDefinition(definitionHolder, this.registry); }}}return beanDefinitions;
}
Copy the code

To enter the findCandidateComponents method:

/** * Scan the specified path for candidate components *@param basePackage the package to check for annotated classes
 * @return a corresponding Set of autodetected bean definitions
 */
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
   // If there is a component index and the index supports contained filters, get the selected component from the component index
   if (this.componentsIndex ! =null && indexSupportsIncludeFilters()) {
      return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
   }
   else {
      // Otherwise, scan the specified package in the class directory
      returnscanCandidateComponents(basePackage); }}Copy the code

Component index please check the official document: docs. Spring. IO/spring/docs…

To use component indexes, you need to add the following Maven configuration:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-indexer</artifactId>
        <version>5.18..RELEASE</version>
        <optional>true</optional>
    </dependency>
</dependencies>
Copy the code

The scanCandidateComponents method is not used here, so the scanCandidateComponents method is entered:

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
   // A collection of all candidate components
   Set<BeanDefinition> candidates = new LinkedHashSet<>();
   try {
      // Build a path expression for the scan package, similar to the pointcut expression
      //classpath*:edu/demo/spring/ext/**/*.class
      String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
      // ResourcePatternResolver The scan package has obtained the. Class file
      // Scan logic: look for.class files under packages. Pattern matching is required here to specify packages flexibly
      // The default Ant Path pattern is used, such as the specified package edu.demo.**.service
      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 is a MetadataReader similar to an XML reader
               MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
               if (isCandidateComponent(metadataReader)) {
                  / / in the end by MetadataReader ScannedGenericBeanDefinition loaded annotation bean definition
                  ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                  sbd.setSource(resource);
                  // Must be an inheritable class, not an interface or a enclosing class. The abstract class must have a Lookup annotation
                  if (isCandidateComponent(sbd)) {
                     if (debugEnabled) {
                        logger.debug("Identified candidate component class: " + resource);
                     }
                     candidates.add(sbd);
                  }
                  else { // Ignore, not a top-level concrete class
                     if (debugEnabled) {
                        logger.debug("Ignored because not a concrete top-level class: "+ resource); }}}else { // Ignored, filter cannot be matched
                  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;
}
Copy the code

Enter the getResourcePatternResolver method:

private ResourcePatternResolver getResourcePatternResolver(a) {
   if (this.resourcePatternResolver == null) {
      this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
   }
   return this.resourcePatternResolver;
}
Copy the code

PathMatchingResourcePatternResolver classes: location path to the specified resource parsing of a resource required to service this for one or more of the match. This can be a one-to-one resource or a one-to-many matching pattern, with the Ant PATH format and clasSPath *: prefix

public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
    / /...

    // The default is AntPathMatcher
    private PathMatcher pathMatcher = new AntPathMatcher();

    / /...
}
Copy the code

Diagram of pattern matching:

Look at the below ScannedGenericBeanDefinition:

public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {

   private final AnnotationMetadata metadata;


   /**
    * Create a new ScannedGenericBeanDefinition for the class that the
    * given MetadataReader describes.
    * @param metadataReader the MetadataReader for the scanned target class
    */
   public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
      Assert.notNull(metadataReader, "MetadataReader must not be null");
      this.metadata = metadataReader.getAnnotationMetadata();
      setBeanClassName(this.metadata.getClassName());
      setResource(metadataReader.getResource());
   }


   @Override
   public final AnnotationMetadata getMetadata(a) {
      return this.metadata;
   }

   @Override
   @Nullable
   public MethodMetadata getFactoryMethodMetadata(a) {
      return null; }}Copy the code

AnnotatedBeanDefinition extends from the GenericBeanDefinition class, and supports annotation metadata based on the AnnotatedBeanDefinition implementation of ASM ClassReader.

Why do I use AnnotatedBeanDefinition here instead of GenericBeanDefinition?

Let’s look at the two methods provided by the AnnotatedBeanDefinition interface:

public interface AnnotatedBeanDefinition extends BeanDefinition {

   /** * Obtain the annotation metadata (as well as basic class metadata) * for this bean definition's bean class. *@return the annotation metadata object (never {@code null})
    */
   AnnotationMetadata getMetadata(a);

   /** * Obtain metadata for this bean definition's factory method, if any. *@return the factory method metadata, or {@code null} if none
    * @since4.4.1 * /
   @Nullable
   MethodMetadata getFactoryMethodMetadata(a);

}
Copy the code

Metadata information

Spring defines a scheme to describe the description interface of a class, an annotation on a class, a method, and so on, which defines some related operations. Such as:

  • Class: What is the name of the class and what modifiers are used
  • Annotations: the name of the annotation on the class, what is the meta-annotation information of the annotation, what is the annotation information of the annotation, what are the attributes in the annotation, etc.

MetadataReader interface:

/**
 * Simple facade for accessing class metadata,
 * as read by an ASM {@linkOrg. Springframework. Asm. ClassReader}. * by asm ClassReader reading class meta information, the model provides a simple appearance. * 1. Use ASM to implement this function; 2. This is a simple appearance pattern implementation * *@author Juergen Hoeller
 * @since2.5 * /
public interface MetadataReader {

   /** * Return the resource reference for the class file. * Return the resource reference for the class file
   Resource getResource(a);

   /** * Read basic class metadata for the underlying class. */
   ClassMetadata getClassMetadata(a);

   /** * Read full annotation metadata for the underlying class, * Including metadata for annotated methods. * Return annotated metadata information */
   AnnotationMetadata getAnnotationMetadata(a);

}
Copy the code

Implementation class: SimpleMetadataReader

final class SimpleMetadataReader implements MetadataReader {
       SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader)
    throws IOException {
    // Build the annotation metadata to read the visitor
    SimpleAnnotationMetadataReadingVisitor visitor = new
    SimpleAnnotationMetadataReadingVisitor(classLoader);
    // Create an ASM ClassReader object for the resource and use that visitor to access the ClassReader object
    getClassReader(resource).accept(visitor, PARSING_OPTIONS);
    // The annotated class that was scanned
    this.resource = resource;
    // Get the annotation metadata information
    this.annotationMetadata = visitor.getMetadata(); }}Copy the code

Asm.ow2.io/is a low-level bytecode manipulation library

Spring uses ASM bytecode manipulation library to read class information, annotation information, their class diagram is as follows:

Sweep filter

/**
 * Determine whether the given class does not match any exclude filter
 * and does match at least one include filter.
 * @param metadataReader the ASM ClassReader for the class
 * @return whether the class qualifies as a candidate component
 */
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
   for (TypeFilter tf : this.excludeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
         return false; }}for (TypeFilter tf : this.includeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
         returnisConditionMatch(metadataReader); }}return false;
}
Copy the code
<context:component-scan base-package="edu.demo.spring.web" >
   <context:exclude-filter type="annotation" expression="@Service"/>
   <context:include-filter type="annotation" expression="@Controller"/>
</context:component-scan>
Copy the code

A filter can be configured in an XML file using the above method, excluding the components and including the components.

@service, @controller, and so on. The default filter is:

protected void registerDefaultFilters(a) {
   this.includeFilters.add(new AnnotationTypeFilter(Component.class));
   ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
   try {
      this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
      logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
   }
   catch (ClassNotFoundException ex) {
      // JSR-250 1.1 API (as included in Java EE 6) not available simply skip.
   }
   try {
      this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
      logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
   }
   catch (ClassNotFoundException ex) {
      // JSR-330 API not available - simply skip.}}Copy the code

AnnotationTypeFilter parent AbstractTypeHierarchyTraversingFilter# match (MetadataReader MetadataReaderFactory) method, And then you’re going to annotationTypeFiler #matchSelf method:

@Override
protected boolean matchSelf(MetadataReader metadataReader) {
   AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
   @componet (Componet (Componet (Componet (Componet (Componet))) @service (Componet (Componet))
   return metadata.hasAnnotation(this.annotationType.getName()) ||
         (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}
Copy the code

Custom implementation of TypeFilter:

public class MyTypeFilter implements TypeFilter {
   @Override
   public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
         throws IOException {
      // Use the class information and annotation information in metadataReader to filter your logic
      returnmetadataReader.getClassMetadata().getClassName().equals(Lad.class.getName()); }}Copy the code

Bean definition registration

/** * Register the given bean definition with the given bean Factory. *@param definitionHolder the bean definition including name and aliases
 * @param registry the bean factory to register with
 * @throws BeanDefinitionStoreException if registration failed
 */
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   / / get beanName
   String beanName = definitionHolder.getBeanName();
   // Register the bean definition information through the bean factory
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.
   // Bind beanName to an alias and register the alias if it exists
   String[] aliases = definitionHolder.getAliases();
   if(aliases ! =null) {
      for(String alias : aliases) { registry.registerAlias(beanName, alias); }}}Copy the code

The core part in DefaultListableBeanFactory# registerBeanDefinition method:

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

   // Check whether beanName and beanDefinition are null
   Assert.hasText(beanName, "Bean name must not be empty");
   Assert.notNull(beanDefinition, "BeanDefinition must not be null");

   // If there is a bean definition inherited from AbstractBeanDefinition
   // Then check the bean
   if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Validation of bean definition failed", ex); }}// Whether the related bean definition already exists
   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
   // If the bean definition already exists
   if(existingDefinition ! =null) {
      // If overrides are not allowed, an exception is thrown
      if(! isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
      }
      // Run the override process and print some log information to inform the process
      else if (existingDefinition.getRole() < beanDefinition.getRole()) {
         // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
         if (logger.isInfoEnabled()) {
            logger.info("Overriding user-defined bean definition for bean '" + beanName +
                  "' with a framework-generated bean definition: replacing [" +
                  existingDefinition + "] with [" + beanDefinition + "]"); }}else if(! beanDefinition.equals(existingDefinition)) {if (logger.isDebugEnabled()) {
            logger.debug("Overriding bean definition for bean '" + beanName +
                  "' with a different definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]"); }}else {
         if (logger.isTraceEnabled()) {
            logger.trace("Overriding bean definition for bean '" + beanName +
                  "' with an equivalent definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]"); }}// Overwrite the original bean definition
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   // The bean definition of beanName does not exist
   else {
      // Whether the current bean object is being created
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         // During startup, synchronous processing prevents iteration exceptions from collections elsewhere
         synchronized (this.beanDefinitionMap) {
            // Use ConcurrentHashMap for storage
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions; removeManualSingletonName(beanName); }}else {
         // Still in startup registration phase
         // Put the current bean before it is created
         this.beanDefinitionMap.put(beanName, beanDefinition);
         this.beanDefinitionNames.add(beanName);
         removeManualSingletonName(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

   // If the corresponding singleton bean exists, reset the bean
   if(existingDefinition ! =null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
   // To freeze the configuration, clear the type mapping cache
   else if(isConfigurationFrozen()) { clearByTypeCache(); }}Copy the code

The alias is used as a Key and the beanName is used as a Value for map storage

@Override
public void registerAlias(String name, String alias) {
   Assert.hasText(name, "'name' must not be empty");
   Assert.hasText(alias, "'alias' must not be empty");
   synchronized (this.aliasMap) {
      if (alias.equals(name)) {
         this.aliasMap.remove(alias);
         if (logger.isDebugEnabled()) {
            logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); }}else {
         String registeredName = this.aliasMap.get(alias);
         if(registeredName ! =null) {
            if (registeredName.equals(name)) {
               // An existing alias - no need to re-register
               return;
            }
            if(! allowAliasOverriding()) {throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
                     name + "': It is already registered for name '" + registeredName + "'.");
            }
            if (logger.isDebugEnabled()) {
               logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
                     registeredName + "' with new target name '" + name + "'");
            }
         }
         checkForAliasCircle(name, alias);
         this.aliasMap.put(alias, name);
         if (logger.isTraceEnabled()) {
            logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); }}}}Copy the code