@EnableAutoConfiguration automatic configuration Principle Analysis

@EnableAutoConfiguration Principle Analysis

@SpringBootApplication contains @EnableAutoConfiguration annotations, @ EnableAutoConfiguration role is to enable Spring's auto-load the configuration.

SpringBoot a core view is that the agreement is greater than the configuration, this seemingly reduces the flexibility of the method, but SpringBoot greatly simplifies the development process. This convention is SpringBoot in achieving perspective provides a number of default configuration parameters, then the question is, SpringBoot store these default configuration parameters of where and how to automatically configure the default parameters?

In fact, SpringBoot a lot of Starter have @Enable notes at the beginning of the implementation principle is very similar, where the first look at The principle of this annotation.

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

Here we can see @EnableAutoConfiguration use @Import added a AutoConfigurationImportSelector class, Spring configuration is automatically injected into the core functions would depend on the object.

In this class, there is provided a getCandidateConfigurations()method for loading a configuration file. With tools SpringFactories Spring provided loadFactoryNames () method to load the configuration file. The default scan path is located META-INF/spring.factoriesin.

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# 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,\
...

Only the top part of the configuration information. Corresponding to the left side of the equal sign is the interface configuration, and on right class. We specifically look at how to load these classes.

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

    try {
        // 从META-INF/spring.factories中加载urls。
        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 factoryClassName = ((String) entry.getKey()).trim();
                for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                    result.add(factoryClassName, factoryName.trim());
                }
            }
        }
        // 添加到缓存中防止重新加载
        cache.put(classLoader, result);
        return result;
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load factories from location [" +
                                           FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}

Finally, the result returned is actually META-INF / spring.factories Map data corresponding to the structure. Map this actually saved the full class name of each class throughout the Spring configuration, including some of the Listener, Filter and so on. The first step to load a class, is to get to the full class name corresponding to the class, and after the specific loading process is actually done by the SpringApplication specific, careful here not to introduce, we return to our priorities, how automatic load the configuration . In spring.factories just, we look at the following elements:

# 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,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
...

Here we can see a lot of familiar names, Aop, Rabbit, and so very much, it seems that automatically loads the configuration is much more than a simple configuration we used to, SpringBoot will load all the possible configurations used in class. Here we first open RabbitAutoConfiguration a familiar look.

@Configuration
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {

This adds a lot of top class notes, we look one by one.

  1. @Configuration: We are very familiar with this comment, indicating this is a configuration class;
  2. @ConditionalOnClass (): This comment is input class number, this configuration is equivalent to a class switch adds, when the class detected when there is an input of the configuration classes take effect, otherwise it would not be instantiated. That is, if your project there is a corresponding dependence will automatically open configuration class, this is a very useful comments.
  3. @EnableConfigurationProperties (): Enable a comment @ConfigurationProperties
  4. @Import (RabbitAnnotationDrivenConfiguration.class): introducing an annotation-based configuration class

In the annotations on top of you might be wondering role @ConfigurationProperties, here we look at the specific realization of the corresponding RabbitProperties.

@ConfigurationProperties(prefix = "spring.rabbitmq")
public class RabbitProperties {

    /**
     * RabbitMQ host.
     */
    private String host = "localhost";

    /**
     * RabbitMQ port.
     */
    private int port = 5672;

    /**
     * Login user to authenticate to the broker.
     */
    private String username = "guest";
    ...

On the whole, the whole is probably a POJO class RabbitProperies, which contains the parameters of RabbitMQ, some of which have been set initial value, but the value of the initial configuration directly in the class is difficult for us to customize the way these modifications configuration parameters, use the @ConfigurationProperties in this class () comments.

@ConfigurationProperties (perfix = "spring.rabbitmq") function is loaded from the configuration of the specified prefix spring configuration, and automatically set to the corresponding member variable. It is also in this way, the real configuration of the automatic injection.

summary

Here, we actually have to start from @EnableAutoConfiguration this annotation, analysis of the entire process automatically configured. Simply repeat the process again at the top:

@EnableAutoConfiguration->AutoConfigurationImportSelector->spring.factories->EnableAutoConfiguration->RabbitAutoConfiguration(具体的配置类)->@EnableConfigurationProperties->RabbitProperties(具体的配置类)->@ConfigurationProperties(prefix = "spring.rabbitmq")

Through the layers on top of the load, we can easily implement automatic injection configuration. This process is not complicated, the next will attempt to follow the above procedure, a starter achieve their own class.

Guess you like

Origin www.cnblogs.com/NinWoo/p/11300428.html
Recommended