欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring Boot 学习笔记_自动配置原理

程序员文章站 2022-03-26 20:26:28
该系列学习笔记均是笔者通过学习某站雷丰阳老师的相关课程并结合 spring 2.* 版本源码自行整理出来的。如果有叙述不到位或者有误的地方烦请各位读者评论区给予指正,大家共同学习。先看看 application.properties 可以配置哪些全局属性一、自动配置原理1、Spring Boot 启动时加载 @SpringBootApplication 主配置类,并开启 @EnableAutoConfiguration 自动配置@SpringBootApplicationpublic class...

该系列学习笔记均是笔者通过学习某站雷丰阳老师的相关课程并结合 spring boot 2.* 版本源码自行整理出来的。如果有叙述不到位或者有误的地方烦请各位读者评论区给予指正,大家共同学习。
先看看 application.properties 可以配置哪些全局属性

一、自动配置原理

1、Spring Boot 启动时加载 @SpringBootApplication 主配置类,并开启 @EnableAutoConfiguration 自动配置

@SpringBootApplication
public class QuickstartApplication {}

@EnableAutoConfiguration
public @interface SpringBootApplication {}

2、@EnableAutoConfiguration 作用

@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
  • @Import 会向 Spring 容器中选择性导入各种组件,至于组件的选择由 AutoConfigurationImportSelector 类进行指定
  • AutoConfigurationImportSelector::selectImports 方法选择应该导入的组件
    // 返回应该被导入 Spring 容器的自动配置类全类名
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
       // 获取所有默认的自动配置类的全类名
       List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
       ...
       return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
    
    // 获取所有默认的自动配置类的全类名
    protected List<String> getCandidateConfigurations() {
        
        // getSpringFactoriesLoaderFactoryClass() => EnableAutoConfiguration.class
        List<String> configurations = 
        SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
      
        return configurations;
    }
    
    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        // loadSpringFactories 函数会返回所有 jar 包中 "META-INF/spring.factories" 扫描到的所有 key=value
        // getOrDefault 			 函数会选择出所有 key=EnableAutoConfiguration 的 value
        return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }
    
    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
    
        try {
            // FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"
            // 扫描所有 jar 包中 "META-INF/spring.factories" 获取每个 jar 包中 "META-INF/spring.factories" 的绝对磁盘路径 url
            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();
                // 将 urls 中的每一个绝对磁盘路径的 url 包装为 properties
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    // 将 properties 文件中所有 key=value 加入到 result 中
                    for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }
            return result;
        }
        catch (IOException ex) {}
    }
    

选择完后会将这些自动配置类加入 Spring 容器,由这些自动配置类完成原 Spring 工程 applicationContext.xml 工作

# 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,\
...
  • 每一个自动配置类进行自动配置功能,以 HttpEncodingAutoConfiguration(Http编码自动配置)为例
   @Configuration(proxyBeanMethods = false)    // 表示这是一个配置类,作用相当于 applicationContext.xml
   @EnableConfigurationProperties(ServerProperties.class)    // 启动指定类的 ConfigurationProperties 功能 => 将配置文件中对应的值和 ServerProperties 绑定起来,并把 ServerProperties 加入到 ioc 容器中
   
   // 以下注解均基于 Spring 底层 @Conditional 注解
   // 根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效
   @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)    // 判断当前应用是否是web应用 true => 生效
   @ConditionalOnClass(CharacterEncodingFilter.class)    // 判断当前项目有没有配置 CharacterEncodingFilter => 用于解决 SpringMVC 中乱码问题过滤器
   @ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)    // 判断配置文件是否未配置 spring.http.encoding.enabled,或配置 spring.http.encoding.enabled = true
   public class HttpEncodingAutoConfiguration {
     
     // properties 即为 Spring Boot 的全局配置文件 application.properties
     private final Encoding properties;
     
     // 从 ioc 容器中获取 properties
     public HttpEncodingAutoConfiguration(ServerProperties properties) {
   		this.properties = properties.getServlet().getEncoding();
   	}
     
    @Bean    // 给容器中添加一个组件,但是这个组件的某些值需要从 properties 中获取
   	@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;
   	}
     
   }
   
   /**
    * HttpEncodingAutoConfiguration 类中 properties 对应的对象
    *
    * HttpEncodingAutoConfiguration 类的注解 @EnableConfigurationProperties(ServerProperties.class) 会将这个
    * ServerProperties 中的属性与 Spring Boot 全局配置文件 application.properties 某些属性相绑定
    * 并把 ServerProperties 加入到 ioc 容器中,最终这个 ServerProperties 又会赋值给 HttpEncodingAutoConfiguration 类中 properties 属性
    */
   @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
   public class ServerProperties {}

HttpEncodingAutoConfiguration类会根据当前不同的条件判断,决定这个配置类是否生效
如果生效,这个配置类就会给容器中添加各种组件,这些组件的属性是从对应的 properties 类中获取的,而这个 properties 类中的属性又是和 Spring Boot 全局配置文件绑定的

3、自动配置总结

  • Spring Boot 启动时会加载大量的自动配置类,通过这些自动配置类完成 ioc 容器的组件导入
  • 不同的功能对应于不同的自动配置类,同时自动配置类中也会配置不同的 ioc 组件
  • 自动配置类给容器中添加组件的时候,会从 properties 类中获取某些属性,而这个 properties 类的属性与 Spring Boot 全局配置文件绑定的
  • xxxxAutoConfigurartion => 自动配置类,用于给容器中添加组件
  • xxxxProperties => 自动配置类对应使用的 properties 类,用于封装配置文件中相关属性

本文地址:https://blog.csdn.net/qq_43415605/article/details/107490139