SpringBoot (annotation)

1. Analyze the main class—annotation

import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = "com.wangxing.springboot")
public class Springbootdemo1Application {
    
    
    public static void main(String[] args) {
    
    
  	SpringApplication.run(Springbootdemo1Application.class, args);
    }
}

@SpringBootApplication
source code:

@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 {
    
    
........
}

1. @SpringBootApplication is actually a composite annotation.
Although its definition uses multiple annotations, in fact, for SpringBoot applications, there are only three important annotations, these three annotations:

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

Therefore, if we use the above three annotations on the main class, the entire SpringBoot application can still be functionally equivalent to the previous startup class.

package com.wangxing.springboot.springbootdemo2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
    
     @ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public class Springbootdemo2Application {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(Springbootdemo2Application.class, args);
    }
}

But writing three annotations every time is obviously too cumbersome, so it is obviously more convenient to write a one-stop composite annotation like @SpringBootApplication.
@SpringBootConfiguration annotation [create configuration class to replace configuration file]
@SpringBootConfiguration annotation includes @Configuration.
@Configuration – is the annotation used by the configuration class of the Spring IoC container in the form of Spring JavaConfig. Since the SpringBoot application is a Spring application at its core, it is naturally necessary to load the configuration of a certain IoC container, and the SpringBoot community recommends the use of a JavaConfig-based configuration form. Therefore, it is obvious that the startup class here is annotated with @Configuration. It is also a configuration class for an IoC container. Configuration method
of Spring IoC container in the form of Spring JavaConfig 1. XML-based configuration method.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
<!-- bean定义 -->

</beans>

2. Configuration method based on JavaConfig

@Configuration
public class MyConfiguration{
// bean定义
} 

Any Java class definition marked with @Configuration is a JavaConfig configuration class.
Registration bean definition
1. XML-based registration bean definition method.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
<!-- bean定义 -->
<bean id=””  class=””></bean>
</beans>

2. The registered bean definition method based on JavaConfig.

@Configuration
public class MyConfiguration{
    
    
// bean定义
 	@Bean
    public StudentService  studentService() {
    
    
        return new StudentServiceImpl();
    }
} 

Any method annotated with @Bean, its return value will be registered as a bean definition in Spring's IoC container, and the method name will be the id of the bean definition by default.
Configuration method
of dependency injection 1. XML-based dependency injection method

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
<!-- bean定义 -->
<bean id=””  class=””>
<property name="studentDao" ref="studentDao" />
</bean>
</beans>

2. Dependency injection method based on JavaConfig.

@Configuration
public class MyConfiguration{
    
    
// bean定义
 	@Bean
    public StudentService  studentService() {
    
    
        return new StudentServiceImpl(studentDao() );
}

	@Bean
    public  StudentDao  studentDao() {
    
    
        return new StudentDaoImpl();
	}
} 

If the definition of a bean depends on other beans, just call the creation method of the dependent bean in the corresponding JavaConfig class directly.

@SpringBootApplication contains @SpringBootConfiguration annotation, @SpringBootConfiguration annotation contains @Configuration annotation, which java class the @Configuration annotation is marked on, then this java class is a JavaConfig configuration class, this JavaConfig configuration class can replace the Spring configuration file [ApplicationContext.xml], when we annotate @SpringBootApplication on the main class, it means that the main class is a JavaConfig configuration class, so we don’t need to write the Spring configuration file [applicationContext.xml] when creating the SptingBoot project.

@EnableAutoConfiguration ["smart" complete automatic configuration]
1. @EnableAutoConfiguration contains the @Import annotation
@Import annotation to register the bean object in the javaConfig configuration class.
@EnableAutoConfiguration annotation uses @Import annotation to collect and register bean definitions related to specific modules.
Source code:

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

@Import(AutoConfigurationImportSelector.class). With the help of EnableAutoConfigurationImportSelector, @EnableAutoConfiguration can help SpringBoot applications load all eligible @Configuration configurations into the current IoC container created and used by SpringBoot.
Insert picture description here

With the support of an original tool class of the Spring framework: SpringFactoriesLoader, @EnableAutoConfiguration can automatically configure the function "intelligently" to be successful!

In the AutoConfigurationImportSelector.class of **@Import(AutoConfigurationImportSelector.class)**

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
   List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
         getBeanClassLoader());
   Assert.notEmpty(configurations, "No auto configuration classes found in METAINF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");
   return configurations;
}

SpringFactoriesLoader类

public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
    
    
   Assert.notNull(factoryType, "'factoryType' must not be null");
   ClassLoader classLoaderToUse = classLoader;
   if (classLoaderToUse == null) {
    
    
      classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
   }
   List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
   if (logger.isTraceEnabled()) {
    
    
      logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
   }
   List<T> result = new ArrayList<>(factoryImplementationNames.size());
   for (String factoryImplementationName : factoryImplementationNames) {
    
    
      result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
   }
   AnnotationAwareOrderComparator.sort(result);
   return result;
}
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    
    
   ClassLoader classLoaderToUse = classLoader;
   if (classLoaderToUse == null) {
    
    
      classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
   }
   String factoryTypeName = factoryType.getName();
   return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

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

   result = new HashMap<>();
   try {
    
    
      Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
      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();
            String[] factoryImplementationNames =
                  StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
            for (String factoryImplementationName : factoryImplementationNames) {
    
    
               result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
                     .add(factoryImplementationName.trim());
            }
         }
      }
      // Replace all lists with unmodifiable lists containing unique elements
      result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
            .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
      cache.put(classLoader, result);
   }
   catch (IOException ex) {
    
    
      throw new IllegalArgumentException("Unable to load factories from location [" +
            FACTORIES_RESOURCE_LOCATION + "]", ex);
   }
   return result;
}


public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
spring-boot-autoconfigure-2.4.0.jar/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
...........

SpringBoot core automatic configuration principle
1). When SpringBoot starts, the main configuration class is loaded and the automatic configuration function is turned on. @EnableAutoConfiguration
main class adds @SpringBootConfiguration annotation, @SpringBootConfiguration annotation includes @EnableAutoConfiguration annotation
2). @EnableAutoConfiguration annotation uses @Import( The parameter EnableAutoConfigurationImporttSelector in AutoConfigurationImportSelector.class) imports some components into
the SpringIOC container; find AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); find the
getAutoConfigurationEntry( ) method, List configurations = getCandidate configurations = getCandidate attributes);
getCandidateConfigurations() to get
List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader()); Get the SpringFactoriesLoader class, and find loadSpringFactories() through the loadFactoryNames method in the SpringFactoriesLoader class. There is a sentence Properties properties = PropertiesLoaderUtils.loadProperties(resource);
get public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring. "factories";
Scan all jar package class paths, META-INF/spring.factories packages
the scanned content of these files into properties objects
to obtain the values ​​corresponding to the EnableAutoConfiguration.class class (class name) from properties, and then put them Add to the container, add all the values ​​of EnableAutoConfiguration configured in META-INF/spring.factories under the class path to the container
3). Each auto-configuration class performs auto-configuration function;
4). Judging according to different current conditions, Decide whether this configuration class takes effect? Once the configuration class into effect, this configuration will be added to the class container various components, these properties of the component is obtained from the corresponding properties of the class, each of these classes which property is binding and profile.
In HttpEncodingAutoConfiguration (Http encoding automatic configuration) is an example to explain the principle of automatic configuration;
//It means that this is a configuration class. It is not the same as the configuration file written before, and components can also be added to the container.

@Configuration(proxyBeanMethods = false)
//启动指定类的ConfigurationProperties功能,将配置文件中对应的值和HttpEncodingAutoConfigurationProperties绑定起来;
@EnableConfigurationProperties(ServerProperties.class)
//Spring底层@Conditional注解,根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效(即判断当前应用是否是web应用)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
//判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码处理的过滤器
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

   private final Encoding properties;

   public HttpEncodingAutoConfiguration(ServerProperties properties) {
      this.properties = properties.getServlet().getEncoding();
   }

   @Bean
   @ConditionalOnMissingBean
   public CharacterEncodingFilter characterEncodingFilter() {
      CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
      filter.setEncoding(this.properties.getCharset().name());
      filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
      filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
      return filter;
   }

   @Bean
   public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
      return new LocaleCharsetMappingsCustomizer(this.properties);
   }

   static class LocaleCharsetMappingsCustomizer
         implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {

      private final Encoding properties;

      LocaleCharsetMappingsCustomizer(Encoding properties) {
         this.properties = properties;
      }

      @Override
      public void customize(ConfigurableServletWebServerFactory factory) {
         if (this.properties.getMapping() != null) {
            factory.setLocaleCharsetMappings(this.properties.getMapping());
         }
      }

      @Override
      public int getOrder() {
         return 0;
      }
   }
}

5. All the properties that can be configured in the configuration file are encapsulated in the xxxxPropertites class. What can be configured in the configuration file can refer to the property class corresponding to a certain function;
@ComponentScan
[Configure the automatic scanning package, you can let the class Objects created by java classes with @Component and @Repository, @Service annotations]
@ComponentScan corresponds to the <context:component-scan> element in the XML configuration form, which is used to cooperate with some meta-information annotations, such as @Component and @Repository, etc. , Collect the bean definition classes marked with these meta-information annotations into Spring's IoC container in batches. We can fine-grainly customize the scope of @ComponentScan automatic scanning through attributes such as basePackages. If not specified, the default Spring framework implementation will scan from the package where the @ComponentScan class is declared.
If our current application does not have any bean definitions that need to be loaded into the IoC container used by the current SpringBoot application through @ComponentScan, then, removing the @ComponentScan declaration, the current SpringBoot application can still run as usual with equivalent functions.


Insert picture description here
The META-INF files of the key components of SpringBoot automatic configuration mybatis-spring-boot-starter, spring-boot-starter-web and other components all contain the spring.factories file. In the automatic configuration module, the full name of the class collected in the file by SpringFactoriesLoader and Return an array of the full name of the class. The full name of the returned class is instantiated through reflection to form a specific factory instance. The factory instance generates the beans that the component specifically needs .

Guess you like

Origin blog.csdn.net/guoguo0717/article/details/110622303