我是如何做到springboot自动配置原理解析

简介: 我是如何做到springboot自动配置原理解析

一前言

springboot 2.0.0版本分析,整体的自动配置流程如下:

具体配置参考官方文档:springboot-doc

二 @SpringBootApplication

核心注解@SpringBootConfiguration其实就是@Configuration注解,表示是个配置类;@EnableAutoConfiguration表示springboot的自动配置机制;@ComponentScan表示扫描允许注册额外的配置类;

@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan

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 {
 
    // 排除不会被应用的自动配置类,classes形式
    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
    Class<?>[] exclude() default {};
 
    // 排除不会被应用的自动配置类,字符串数组形式
    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
    String[] excludeName() default {};
 
    // 扫描基本包
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};
 
    // 扫描基本类
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};
 
}

三 AutoConfigurationImportSelector

点击@EnableAutoConfiguration 注解进入,看见@Import({AutoConfigurationImportSelector.class})是导入AutoConfigurationImportSelector类;

AutoConfigurationImportSelector 类是自动配置的核心类,其主要进行配置的功能是配置factory.propertiesspring内嵌集成引入的配置;

3.1 具体依赖图如下:

3.2 成员

    // 表示不引入配置
    private static final String[] NO_IMPORTS = new String[0];
    // 配置日志
    private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
    // 排除的自动配置
    private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
    // 声明 beanFactory
    private ConfigurableListableBeanFactory beanFactory;
    // 声明 environment (全局环境)
    private Environment environment;
    // 声明 beanClassLoader (bean的类加载器,加载spring-autoconfigure-metadata.properties中集成类)
    private ClassLoader beanClassLoader;
    // 声明 resourceLoader (资源加载器,加载spring的 factory.properties配置类)
    private ResourceLoader resourceLoader;

3.3 selectImports

selectImports 这个方法的主要功能就是导入factory.propertiesspring-autoconfigure-metadata.properties中的配置类;

 public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            try {
              // 1 加载元数据信息,本质就是加载bean,这里的bean是指我我们spring-autoconfigure-metadata.properties中集成类
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                // 2 AnnotationAttributes本质是个map
                AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                // 3  获得 spring.factories 中的配置类
                List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                // 4  配置类复制用于排序不需要的配置类
                configurations = this.removeDuplicates(configurations);
                //  优先级排序
                configurations = this.sort(configurations, autoConfigurationMetadata);
                // 需移除配置类
                Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                // 校验移除
                this.checkExcludedClasses(configurations, exclusions);
                // 执行移除配置类
                configurations.removeAll(exclusions);
                configurations = this.filter(configurations, autoConfigurationMetadata);
                this.fireAutoConfigurationImportEvents(configurations, exclusions);
                return StringUtils.toStringArray(configurations);
            } catch (IOException var6) {
                throw new IllegalStateException(var6);
            }
        }
    }

1 分析

AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);

进入方法发现加载的元数据信息的路径是 META-INF/spring-autoconfigure-metadata.properties

public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
        return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
    }

在自动配置包底下找到spring-autoconfigure-metadata.properties

点进属性文件发现都spring自动配置类名的配置信息,部分如下:

#Thu Mar 01 04:46:13 UTC 2018
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration=
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration.Configuration=
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,org.springframework.data.cassandra.core.ReactiveCassandraTemplate,reactor.core.publisher.Flux
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration.ConditionalOnClass=org.apache.solr.client.solrj.SolrClient,org.springframework.data.solr.repository.SolrRepository
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration=
............................

我们随意点开其中的一个配置类,比如第一个HttpMessageConvertersAutoConfiguration,其中的class注解如下,可以发现其自动配置类都是通过注解配置;

// 表示配置类相当于xml中的 bean标签
@Configuration
// 判定是否存在HttpMessageConverter.class类,如果不存在则引入
@ConditionalOnClass({HttpMessageConverter.class})
// 在这三个配置类配置之后再进行配置
@AutoConfigureAfter({GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class})
// 导入配置类相当于xml中的 import标签
@Import({JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class, JsonbHttpMessageConvertersConfiguration.class})
public class HttpMessageConvertersAutoConfiguration {

3 分析

this.getCandidateConfigurations(annotationMetadata, attributes);方法的主要功能是获取候选配置;

进入getCandidateConfigurations方法发现里面的主要方法是loadFactoryNames;

// 获得factory配置信息类名
 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

进入 loadFactoryNames 方法 主要是2部分;第一个是loadSpringFactories(classLoader),第二个是getOrDefault

// 加载factory类名
 public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        //  返回类名的list
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

第一部分:

loadSpringFactories本质就是使用spring的Resource资源调用获得 spring.factories 中的配置类;

// 加载spring.factories中的配置类信息
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                // 获得 `spring.factories` 配置类的URL
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();
                // 将 `spring.factories`  每个配置类的key 和 val 存储进 map
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();
 
                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
                        result.addAll((String)entry.getKey(), factoryClassNames);
                    }
                }
 
                cache.put(classLoader, result);
                return result;
            } catch (IOException var9) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
            }
        }
    }

classLoader.getResources("META-INF/spring.factories") ;中找到自动配置包中的配置如下图:

spring.factories装载配置类部分信息如下,没错这些配置都是sping启动需要的配置类信息,监听器,过滤器,自动配置的start配置类,以及启动的失败的错误分析还有模板引擎的支持,详细大家翻下配置包即可;

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

第二部分:

getOrDefault是个Map集合,map中有这个key时,就使用这个key值,如果没有就使用默认值defaultValue,返回也就是类名的list;

相关文章
|
2月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
4月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
865 0
|
4月前
|
Java Spring
Spring Boot配置的优先级?
在Spring Boot项目中,配置可通过配置文件和外部配置实现。支持的配置文件包括application.properties、application.yml和application.yaml,优先级依次降低。外部配置常用方式有Java系统属性(如-Dserver.port=9001)和命令行参数(如--server.port=10010),其中命令行参数优先级高于系统属性。整体优先级顺序为:命令行参数 &gt; Java系统属性 &gt; application.properties &gt; application.yml &gt; application.yaml。
916 0
|
1月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
1月前
|
XML JSON Java
【SpringBoot(三)】从请求到响应再到视图解析与模板引擎,本文带你领悟SpringBoot请求接收全流程!
Springboot专栏第三章,从请求的接收到视图解析,再到thymeleaf模板引擎的使用! 本文带你领悟SpringBoot请求接收到渲染的使用全流程!
192 3
|
1月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
265 3
|
1月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
337 2
|
2月前
|
Java 数据库 数据安全/隐私保护
Spring Boot四层架构深度解析
本文详解Spring Boot四层架构(Controller-Service-DAO-Database)的核心思想与实战应用,涵盖职责划分、代码结构、依赖注入、事务管理及常见问题解决方案,助力构建高内聚、低耦合的企业级应用。
748 1
|
2月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
517 5
|
2月前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
170 0
探索Spring Boot的@Conditional注解的上下文配置

热门文章

最新文章

推荐镜像

更多
  • DNS