Write an article on the plant in the spring post processor (ConfigurationClassPostProcessor) do:

Factory rear Spring source 】 【 ConfigurationClassPostProcessor processor

One said to the @ Import annotations, it can introduce three kinds, the first is a common class, the second is realized ImportSelector interface class, the third is to realize the ImportBeanDefinitionRegistrar interface classes. I’m going to write two articles to explain them separately. It’s easier to introduce common classes, so I’m going to mix them up in this article.

This annotation is also used in Mybatis framework and SpringBoot automatic assembly technology, today we will briefly talk about the @import annotation in SpringBoot application.


1. The ordinary class

@Import({Car.class, Person.class})
public class Test {}Copy the code

Import the classes will be added to the spring container, ConfigurationClassPostProcessor as ordinary classes to deal with it.

2.ImportSelector

Take a look at the ImportSelector interface:

public interface ImportSelector {

   /**
    * Select and return the names of which class(es) should be imported based on
    * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
    * @return the class names, or an empty array if none
    */
   String[] selectImports(AnnotationMetadata importingClassMetadata);

}
Copy the code
  • AnnotationMetadata, annotated information, gets annotated information at @import
  • Return value: String[], which returns an array of strings. String needs to be the full path name of the class

What does this interface really do? To see the spring ConfigurationClassPostProcessor is how to deal with?

processImports(configClass, sourceClass, getImports(sourceClass), true);

To get into this method, look at the code for handling ImportSelector:

if (candidate.isAssignable(ImportSelector.class)) {
   // Candidate class is an ImportSelector -> delegate to it to determine importsClass<? > candidateClass = candidate.loadClass(); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); ParserStrategyUtils.invokeAwareMethods( selector,this.environment, this.resourceLoader, this.registry);
   if (selector instanceof DeferredImportSelector) {
      this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
   }
   else {
     // Get the array of strings returned by the method in ImportSelector
      String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
     // Return SourceClass reflectively via the class's full pathname
      Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
      /** ** recursively called, possibly in classes introduced in annotations@ImportNote * if it's not in there@Import, enter the else perform processConfigurationClass (candidate. AsConfigClass (configClass)); * /
      processImports(configClass, currentSourceClass, importSourceClasses, false); }}Copy the code
  • Get the array of strings (class full pathnames) returned by the ImportSelector method.

  • SourceClass is then returned as a reflection of the class’s full pathname:

  • SourceClass asSourceClass(@Nullable String className) throws IOException {
       if (className == null) {
          return new SourceClass(Object.class);
       }
       if (className.startsWith("java")) {
          // Never use ASM for core java types
          try {
             return new SourceClass(ClassUtils.forName(className, this.resourceLoader.getClassLoader()));
          }
          catch (ClassNotFoundException ex) {
             throw new NestedIOException("Failed to load class [" + className + "]", ex); }}return new SourceClass(this.metadataReaderFactory.getMetadataReader(className));
    }
    Copy the code
  • Finally, the interface returns the class full path array, generates the corresponding beanDefinition, instantiates the bean, and places it in the Spring container.

Application of 3.@Import in SpringBoot automatic assembly technology

In SpringBoot projects, we often use starter packages to integrate tools, such as spring-boot-starter-data-ElasticSearch, and these starter packages use auto-assembly technology. Here’s a look at SpringBoot’s automated assembly technology.

The @SpringBootApplication annotation is the core annotation of SpringBoot. Click on the @SpringBootApplication annotation and you can see the following:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
		/ /...
}
Copy the code

EnableAutoConfiguration is obviously associated with autowiring. So go to @enableAutoConfiguration again:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
		/ /...
}
Copy the code

The @import annotation is used here.

Look at AutoConfigurationImportSelector this class, this is the realization of the ImportSelector interface classes, so look at its selectImports method directly:

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
   if(! isEnabled(annotationMetadata)) {return NO_IMPORTS;
   }
   AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
         .loadMetadata(this.beanClassLoader);
   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
         annotationMetadata);
   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
Copy the code

⊙﹏⊙ This what ah? Let’s go straight to the code snippet, which looks like this:

#getAutoConfigurationEntry()-->#getCandidateConfigurations()-->SpringFactoriesLoader.loadFactoryNames()-->#loadSpringFac tories()

This is the core code block:

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
   MultiValueMap<String, String> result = cache.get(classLoader);
   if(result ! =null) {
      return result;
   }

   try{ Enumeration<URL> urls = (classLoader ! =null ?
            classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
            ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
      result = new LinkedMultiValueMap<>();
      while (urls.hasMoreElements()) {
         URL url = urls.nextElement();
         UrlResource resource = new UrlResource(url);
         Properties properties = PropertiesLoaderUtils.loadProperties(resource);
         for(Map.Entry<? ,? > entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim();for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
               result.add(factoryTypeName, factoryImplementationName.trim());
            }
         }
      }
      cache.put(classLoader, result);
      return result;
   }
   catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load factories from location [" +
            FACTORIES_RESOURCE_LOCATION + "]", ex); }}Copy the code

The FACTORIES_RESOURCE_LOCATION in the above code block is defined as follows:

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

Spring scans and loads the meta-INF /spring.factories file. If you don’t know the “Spring. factories” file, you can still use the “spring.factories” file.

The yellow part is the Map

> Key, and the green part is the Map value. These values are the full path of the class.
,>

The full path of these classes is scanned, returned by the selectImports method of the ImportSelector interface, and then reflected by Spring to generate a beanDefinition, instantiated during subsequent bean instantiations, and placed into the Spring container.


This article not only introduces the principle of @import introducing the ImportSelector class, but also introduces the principle of SpringBoot automatic assembly, I think it is still quite clear

So read the Spring source code, the basic back of the SpringBoot source code will come naturally to understand.

This article has not yet been written @ ImportBeanDefinitionRegistrar class and its application in Mybatis, introduced the Import, because the article’s too long looking at also have no patience, so next article to write, will write a Mybatis Demo ~ simulation