Spring —— Spring Boot 配置文件

Posted Gujiu!!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring —— Spring Boot 配置文件相关的知识,希望对你有一定的参考价值。

JavaEE传送门

JavaEE

Spring —— Bean 作用域和生命周期

Spring —— Spring Boot 创建和使用


目录


Spring Boot 配置文件

如果没有配置信息, Spring Boot 项目就不能连接和此操作数据库, 甚至是不能保存可以用于排查问题的关键日志, 配置文件的作用是非常重要的.

  1. 系统使用的配置文件 (系统配置文件), 如端口号的配置, 链接数据库的配置
  2. 用户自定义配置文件

Spring Boot 配置文件格式

  1. .properties
  2. .yml (yaml)

# 注意事项 #

  1. 当一个项目中, 存在两种格式的配置文件, 并且两个配置文件间中设置了相同的配置项, 但之不同时. .properties 配置文件的优先级最高, 但加载完 .properties 文件之后, 也会加载 .yml 文件的配置信息.
  2. 理论上讲 .properties 可以和 .yml 共存, 但实际业务中, 我们通常会采用一种统一的配置文件格式, 这样可以更好的维护.

properties配置文件

properties 基本语法

# properies 以键值的形式配置的: key=vaule.

# 设置端口号
server.port=8888

# 我们还可以自定义配置项

myTest=gujiu

我们还可以读取配置项中的内容, 使用 @Value 注解来实现, @Value 注解使用 “$” 的格式读取.

@Controller // 当前类为控制器
@ResponseBody // 返回的是数据, 而非页面
public class TestController 
    @Value("$myTest")
    private String mytest;

    @RequestMapping("/getconf")
    public String getConfig() 
        return mytest;
    

注: 不可以用 @Value(“myTest”) 读取, 其含义是, 将字符串赋值给 mytest 变量.


properties 缺点

当我们想配置数据库的时候.

# 连接数据库配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456

从上述配置 key 中可以看出, properties 配置文件中会有很多的冗余信息.

想要解决这个问题,就可以使用 yml 配置⽂件的格式化了.


yml 配置文件

yml (YAML - Yet Another Markup Language) 翻译成中文 “另一种标记语言”

yml 优点

  1. yml 是一个可读性高, 写法简单, 易于理解, 他的语法和 JSON 语言类似.
  2. yml 支持更多的数据类型, 它可以简单表达清单 (数组), 散列表, 标量等数据形态, 它使用空白符号缩进和大量依赖外观的特色, 特别时候来表达或编辑数据结构, 各种配置文件等.
  3. yml 支持更多的编程语言, 它不只是 Java 中可以使用在 Golang, php, Python, Ruby, JavaScripy, Perl 中.

yml 基本语法

yml 是树形结构的配置文件: key: vaule .

# 注意 # key 和 vaule 直接使用英文冒号加空格的方式组成, 空格不可省略.

# 配置端口
server:
  port: 6666
# 自定义配置  
mytest2: gugu

同样是使用 @Value 注解使用 “$” 的格式读取.

@Controller // 当前类为控制器
@ResponseBody // 返回的是数据, 而非页面
public class TestController 
    @Value("$mytest2")
    private String myTest;

    @RequestMapping("/getconf2")
    public String getConfig2() 
        return myTest;
     

当我们配置数据库连接

# 配置数据库连接
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=utf8
    username: root
    password: 123456


yml 配置不同类型数据及 null

# 字符串
string.value: Hello

# 布尔值,true或false
boolean.value: true
boolean.value1: false

# 整数
int.value: 10
int.value1: 0b1010_0111_0100_1010_1110 # ⼆进制

# 浮点数
float.value: 3.14159
float.value1: 314159e-5 # 科学计数法

# Null,~代表null
null.value: ~

注意事项:value 值加单双引号

# 字符串
str1: Hello \\n Spring Boot.
str2: 'Hello \\n Spring Boot.'
str3: "Hello \\n Spring Boot."

读取一下, str1, str2, str3.

@Controller // 当前类为控制器
@ResponseBody // 返回的是数据, 而非页面
public class TestController 
    @Value("$str1")
    private String str1;

    @Value("$str2")
    private String str2;

    @Value("$str3")
    private String str3;

    @PostConstruct
    public void postConstruct() 
        System.out.println("str1: " + str1);
        System.out.println("str2: " + str2);
        System.out.println("str3: " + str3);
    

运行结果展示:

# 注意事项 #

  • 字符串默认不⽤加上单引号或者双引号.
  • 单引号会转义特殊字符,特殊字符最终只是⼀个普通的字符串数据.
  • 双引号不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思.

yml 配置对象

比如: 我们配置一个学生对象

student:
 id: 1
 name: Gujiu
 age: 18

或者使用行内写法

student: id: 1,name: Gujiu,age: 18

读取配置对象

这个时候就不能用 @Value 来读取配置中的对象了,此时要使用另⼀个注解 @ConfigurationProperties 来读取

# 首先要创建一个实体类:

@Component
@ConfigurationProperties(value = "student")
@Data
public class Student 
    private int id;
    private String name;
    private int age;


# 调用类代码

@Controller // 当前类为控制器
@ResponseBody // 返回的是数据, 而非页面
public class TestController 
    @Autowired
    private Student student;

    @PostConstruct
    public void postConstruct() 
        System.out.println(student);
    


//运行结果: Student(id=1, name=Gujiu, age=18)

yml 配置集合

配置文件也可以配置 list 集合

mynames:
 name:
 - Gujiu
 - GUJIU
 - gugu

或者使用行内写法

mynames: name: [Gujiu,GUJIU,gugu]

读取配置对象

和读取对象一样, 使用 @ConfigurationProperties 来读取

@Component
@ConfigurationProperties("mynames")
@Data
public class ListConfig 
 private List<String> name;


properties VS yml

  • 二者都是 Spring Boot 的配置文件, 二者的诞生时间是不同的. properties 是默认的配置文件, 诞生的比较早. yml 是后来才出现的另一种标记语言的配置文件.
  • properties 是以 key=vaule 的形式配置的键值类型的配置文件, 而 yml 使用的类似 JSON 格式的树形配置方式进行配置的. yml 层级之间使用换行缩进的方式配置,key 和 value 之间使用 “: ” 英文冒号加空格的方式设置,并且空格不可省略.
  • properties 为早期并且默认的配置文件格式,但其配置存在⼀定的冗余数据,使⽤ yml 可以很好的解决数据冗余的问题
  • yml 通用性更好, 支持更多语言,如 Java、Go、Python 等,如果是云服务器开发,可以使用一份配置⽂件作为 Java 和 Go 的共同配置文件.
  • yml 功能比较强大, 支持更多的数据类型, 对中文的兼容性非常好.

设置不同环境的配置文件

  1. 创建不同环境的配置文件:

    • application-dev.yml (开发环境)
    • application-prod.yml (生产环境)
  2. application.yml 中设置运行环境:

    # 开发环境
    spring:
      profiles:
    	active: dev
    
    # 生产环境
    spring:
      profiles:
    	active: prod
    

🌷(( ◞•̀д•́)◞⚔◟(•̀д•́◟ ))🌷

以上就是今天要讲的内容了,希望对大家有所帮助,如果有问题欢迎评论指出,会积极改正!!

这里是Gujiu吖!!感谢你看到这里🌬
祝今天的你也
开心满怀,笑容常在。

Spring Boot自动配置原理(转)

第3章 Spring Boot自动配置原理

3.1 SpringBoot的核心组件模块

首先,我们来简单统计一下SpringBoot核心工程的源码java文件数量:

我们cd到spring-boot-autoconfigure工程根目录下。执行

$ tree | grep -c .java$
模块 java文件数
spring-boot 551
spring-boot-actuator 423
spring-boot-autoconfigure 783
spring-boot-devtools 169
spring-boot-cli 180
spring-boot-tools 355

我们可以看到有783个java文件。spring-boot核心工程有551个java文件。从上面的java文件数量大致可以看出,SpringBoot技术框架的核心组成部分:

spring-boot-autoconfigure
spring-boot
spring-boot-tools

我们把SpringBoot源码导入IntelliJ IDEA,查看artifact的全部依赖关系。

IDEA有个Maven Projects窗口,一般在右侧能够找到,如果没有可以从菜单栏打开:View>Tool Windows>Maven Projects;

选择要分析的maven module(idea的module相当于eclipse的project),右击show dependencies,会出来该module的全部依赖关系图,非常清晰细致。

例如,spring-boot-starter-freemarker的依赖图分析如下:

在spring-boot-build 的pom中,我们可以看到:

           <modules>
<module>spring-boot-dependencies</module>
<module>spring-boot-parent</module>
<module>spring-boot-tools</module>
<module>spring-boot</module>
<module>spring-boot-test</module>
<module>spring-boot-autoconfigure</module>
<module>spring-boot-test-autoconfigure</module>
<module>spring-boot-actuator</module>
<module>spring-boot-devtools</module>
<module>spring-boot-docs</module>
<module>spring-boot-starters</module>
<module>spring-boot-actuator-docs</module>
<module>spring-boot-cli</module>
</modules>

其中,在spring-boot-dependencies中,SpringBoot项目维护了一份庞大依赖。这些依赖的版本都是经过实践,测试通过,不会发生依赖冲突的。就这样一个事情,就大大减少了Spring开发过程中,出现jar包冲突的概率。spring-boot-parent依赖spring-boot-dependencies。

下面我们简要介绍一下SpringBoot子modules。

spring-boot

SpringBoot核心工程。

spring-boot-starters

是SpringBoot的启动服务工程。

spring-boot-autoconfigure

是SpringBoot实现自动配置的核心工程。

spring-boot-actuator

提供SpringBoot应用的外围支撑性功能。 比如:

  • Endpoints,SpringBoot应用状态监控管理
  • HealthIndicator,SpringBoot应用健康指示表
  • 提供metrics支持
  • 提供远程shell支持

spring-boot-tools

提供了SpringBoot开发者的常用工具集。诸如,spring-boot-gradle-plugin,spring-boot-maven-plugin就是这个工程里面的。

spring-boot-cli

是Spring Boot命令行交互工具,可用于使用Spring进行快速原型搭建。你可以用它直接运行Groovy脚本。如果你不喜欢Maven或Gradle,Spring提供了CLI(Command Line Interface)来开发运行Spring应用程序。你可以使用它来运行Groovy脚本,甚至编写自定义命令。

5.2 SpringBoot Starters

Spring boot中的starter概念是非常重要的机制,能够抛弃以前繁杂的配置,统一集成进starter,应用者只需要引入starter jar包,spring boot就能自动扫描到要加载的信息。

starter让我们摆脱了各种依赖库的处理,需要配置各种信息的困扰。Spring Boot会自动通过classpath路径下的类发现需要的Bean,并织入bean。

例如,如果你想使用Spring和用JPA访问数据库,你只要依赖 spring-boot-starter-data-jpa 即可。

目前,github上spring-boot项目的最新的starter列表spring-boot/spring-boot-starters如下:

spring-boot-starter
spring-boot-starter-activemq
spring-boot-starter-actuator
spring-boot-starter-amqp
spring-boot-starter-aop
spring-boot-starter-artemis
spring-boot-starter-batch
spring-boot-starter-cache
spring-boot-starter-cloud-connectors
spring-boot-starter-data-cassandra
spring-boot-starter-data-couchbase
spring-boot-starter-data-elasticsearch
spring-boot-starter-data-jpa
spring-boot-starter-data-ldap
spring-boot-starter-data-mongodb
spring-boot-starter-data-mongodb-reactive spring-boot-starter-data-neo4j
spring-boot-starter-data-redis
spring-boot-starter-data-rest
spring-boot-starter-data-solr
spring-boot-starter-freemarker
spring-boot-starter-groovy-templates
spring-boot-starter-hateoas
spring-boot-starter-integration
spring-boot-starter-jdbc
spring-boot-starter-jersey
spring-boot-starter-jetty
spring-boot-starter-jooq
spring-boot-starter-jta-atomikos
spring-boot-starter-jta-bitronix
spring-boot-starter-jta-narayana
spring-boot-starter-log4j2
spring-boot-starter-logging
spring-boot-starter-mail
spring-boot-starter-mobile
spring-boot-starter-mustache
spring-boot-starter-parent
spring-boot-starter-reactor-netty
spring-boot-starter-security
spring-boot-starter-social-facebook
spring-boot-starter-social-linkedin
spring-boot-starter-social-twitter
spring-boot-starter-test
spring-boot-starter-thymeleaf
spring-boot-starter-tomcat
spring-boot-starter-undertow
spring-boot-starter-validation
spring-boot-starter-web
spring-boot-starter-web-services
spring-boot-starter-webflux
spring-boot-starter-websocket


(源代码目录执行shell:l|awk \'{print $9}\', l|awk \'{print $9}\'|grep -c \'starter\')

共52个。每个starter工程里面的pom描述有相应的介绍。具体的说明,参考官网文档[1]。关于这些starters的使用例子,可以参考spring-boot/spring-boot-samples

比如说,spring-boot-starter是:

Core starter, including auto-configuration support, logging and YAML

这是Spring Boot的核心启动器,包含了自动配置、日志和YAML。它的项目依赖图如下:

可以看出,这些starter只是配置,真正做自动化配置的代码的是在spring-boot-autoconfigure里面。同时spring-boot-autoconfigure依赖spring-boot工程,这个spring-boot工程是SpringBoot的核心。

SpringBoot会基于你的classpath中的jar包,试图猜测和配置您可能需要的bean。

例如,如果你的classpath中有tomcat-embedded.jar,你可能会想要一个TomcatEmbeddedServletContainerFactory Bean (SpringBoot通过获取EmbeddedServletContainerFactory来启动对应的web服务器。常用的两个实现类是TomcatEmbeddedServletContainerFactory和JettyEmbeddedServletContainerFactory)。

其他的所有基于Spring Boot的starter都依赖这个spring-boot-starter。比如说spring-boot-starter-actuator的依赖树,如下图:

5.3 @EnableAutoConfiguration自动配置原理

通过@EnableAutoConfiguration启用Spring应用程序上下文的自动配置,这个注解会导入一个EnableAutoConfigurationImportSelector的类,而这个类会去读取一个spring.factories下key为EnableAutoConfiguration对应的全限定名的值。

这个spring.factories里面配置的那些类,主要作用是告诉Spring Boot这个stareter所需要加载的那些xxxAutoConfiguration类,也就是你真正的要自动注册的那些bean或功能。然后,我们实现一个spring.factories指定的类,标上@Configuration注解,一个starter就定义完了。

如果想从自己的starter种读取应用的starter工程的配置,只需要在入口类上加上如下注解即可:

@EnableConfigurationProperties(MyProperties.class)

读取spring.factories文件的实现

是通过org.springframework.core.io.support.SpringFactoriesLoader实现。

SpringFactoriesLoader的实现类似于SPI(Service Provider Interface,在java.util.ServiceLoader的文档里有比较详细的介绍。java SPI提供一种服务发现机制,为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要[3])。

SpringFactoriesLoader会加载classpath下所有JAR文件里面的META-INF/spring.factories文件。

其中加载spring.factories文件的代码在loadFactoryNames方法里:

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

....

public static List&lt;String&gt; loadFactoryNames(Class&lt;?&gt; factoryClass, ClassLoader classLoader) {</br>
    String factoryClassName = factoryClass.getName();</br>
    try {</br>
        Enumeration&lt;URL&gt; urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :</br>
                ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));</br>
        List&lt;String&gt; result = new ArrayList&lt;&gt;();</br>
        while (urls.hasMoreElements()) {</br>
            URL url = urls.nextElement();</br>
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));</br>
            String factoryClassNames = properties.getProperty(factoryClassName);</br>
            result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));</br>
        }</br>
        return result;</br>
    }</br>
    catch (IOException ex) {</br>
        throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +</br>
                "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);</br>
    }</br>
}</br>

通过org.springframework.boot.autoconfigure.AutoConfigurationImportSelector里面的getCandidateConfigurations方法,获取到候选类的名字List<String>。该方法代码如下:

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), 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;
}

其中,getSpringFactoriesLoaderFactoryClass()方法直接返回的是EnableAutoConfiguration.class, 代码如下:

    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}

所以,getCandidateConfigurations方法里面的这段代码:

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());

会过滤出key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的全限定名对应的值。全限定名都使用如下命名方法:

包名.外部类名
包名.外部类名$内部类名

e.g:

org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration

SpringBoot中的META-INF/spring.factories(完整路径:spring-boot/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories)中关于EnableAutoConfiguration的这段配置如下:

# 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,\\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.mongo.ReactiveMongoDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.mongo.ReactiveMongoRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\\ org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\\
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\\
org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\\
org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\\
org.springframework.boot.autoconfigure.mongo.ReactiveMongoAutoConfiguration,\\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\\
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\\
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\\
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\\
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\\
org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAnnotationAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\\
org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

当然了,这些AutoConfiguration不是所有都会加载的,会根据AutoConfiguration上的@ConditionalOnClass等条件,再进一步判断是否加载。我们下文通过FreeMarkerAutoConfiguration实例来分析整个自动配置的过程。

5.4 FreeMarkerAutoConfiguration自动配置的实例分析

我们首先看spring-boot-starter-freemarker工程,目录结构如下:

.
├── pom.xml
├── spring-boot-starter-freemarker.iml
└── src
    └── main
        └── resources
            └── META-INF
                └── spring.provides

4 directories, 3 files

我们可以看出,这个工程没有任何Java代码,只有两个文件:pom.xml跟spring.provides。starter本身在你的应用程序中实际上是空的。

其中,
spring.provides文件

provides: freemarker,spring-context-support

主要是给这个starter起个好区分的名字。

Spring Boot 通过starter对项目的依赖进行统一管理. starter利用了maven的传递依赖解析机制,把常用库聚合在一起, 组成了针对特定功能而定制的依赖starter。

我们可以使用IDEA提供的maven依赖图分析的功能(如下图),得到spring-boot-starter-freemarker依赖的module。

IDEA提供的maven依赖图分析
spring-boot-starter-freemarker依赖的module

从上面的依赖图,我们可以清晰看出其间依赖关系。

当Spring Boot Application中自动配置EnableAutoConfiguration的相关类执行完毕之后,Spring Boot会进一步解析对应类的配置信息。如果我们配置了spring-boot-starter-freemarker ,maven就会通过这个starter所依赖的spring-boot-autoconfigure,自动传递到spring-boot-autoconfigure工程中。

我们来简单分析一下spring-boot-autoconfigure工程的架构。

其中,FreeMarker的自动配置类是org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration。

下面我们来简要分析一下FreeMarkerAutoConfiguration这个类。

在FreeMarkerAutoConfiguration类上面有四行注解:

@Configuration
@ConditionalOnClass({ freemarker.template.Configuration.class,
        FreeMarkerConfigurationFactory.class })
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties(FreeMarkerProperties.class)
public class FreeMarkerAutoConfiguration {
    ...
}

其中,

(1)@Configuration,是org.springframework.context.annotation包里面的注解。这么说吧,用@Configuration注解该类,等价 与XML中配置beans;用@Bean标注方法等价于XML中配置bean。

(2)@ConditionalOnClass,org.springframework.boot.autoconfigure.condition包里面的注解。意思是当类路径下有指定的类的条件下,才会去注册被标注的类为一个bean。在上面的代码中的意思就是,当类路径中有freemarker.template.Configuration.class,FreeMarkerConfigurationFactory.class两个类的时候,才会实例化FreeMarkerAutoConfiguration这个Bean。

(3)@AutoConfigureAfter,org.springframework.boot.autoconfigure包里面的注解。这个通过注解的名字意思就可以知道,当WebMvcAutoConfiguration.class这个类实例化完毕,才能实例化FreeMarkerAutoConfiguration(有个先后顺序)。SpringBoot使用@ AutoConfigureBefore、@AutoConfigureAfter注解来定义这些配置类的载入顺序。

(4)@EnableConfigurationProperties,表示启动对FreeMarkerProperties.class的内嵌配置支持,自动将FreeMarkerProperties注册为一个bean。这个FreeMarkerProperties类里面就是关于FreeMarker属性的配置:

@ConfigurationProperties(prefix = "spring.freemarker")
public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {

public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/";</br></br>

public static final String DEFAULT_PREFIX = "";</br></br>

public static final String DEFAULT_SUFFIX = ".ftl";</br></br>

/**</br>
 * Well-known FreeMarker keys which will be passed to FreeMarker\'s Configuration.</br>
 */</br>
private Map&lt;String, String&gt; settings = new HashMap&lt;&gt;();</br>

/**</br>
 * Comma-separated list of template paths.</br>
 */</br>
private String[] templateLoaderPath = new String[] { DEFAULT_TEMPLATE_LOADER_PATH };</br></br>

/**</br>
 * Prefer file system access for template loading. File system access enables hot</br>
 * detection of template changes.</br>
 */</br>
private boolean preferFileSystemAccess = true;</br></br>

public FreeMarkerProperties() {</br>
    super(DEFAULT_PREFIX, DEFAULT_SUFFIX);</br>
}</br></br>

public Map&lt;String, String&gt; getSettings() {</br>
    return this.settings;</br>
}</br></br>

public void setSettings(Map&lt;String, String&gt; settings) {</br>
    this.settings = settings;</br>
}</br></br>

public String[] getTemplateLoaderPath() {</br>
    return this.templateLoaderPath;</br>
}</br></br>

public boolean isPreferFileSystemAccess() {</br>
    return this.preferFileSystemAccess;</br>
}</br>

public void setPreferFileSystemAccess(boolean preferFileSystemAccess) {</br>
    this.preferFileSystemAccess = preferFileSystemAccess;</br>
}</br></br>

public void setTemplateLoaderPath(String... templateLoaderPaths) {</br>
    this.templateLoaderPath = templateLoaderPaths;</br>
}</br></br>

}

综上当(1)(2)两个条件满足时,才会继续(3)(4)的动作,同时注册FreeMarkerAutoConfiguration这个Bean。该类的结构如下图:

我们来看其内部类FreeMarkerWebConfiguration的代码:

    @Configuration
@ConditionalOnClass(Servlet.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
public static class FreeMarkerWebConfiguration extends FreeMarkerConfiguration {

    @Bean</br>
    @ConditionalOnMissingBean(FreeMarkerConfig.class)</br>
    public FreeMarkerConfigurer freeMarkerConfigurer() {</br>
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();</br>
        applyProperties(configurer);</br>
        return configurer;</br>
    }</br></br>

    @Bean</br>
    public freemarker.template.Configuration freeMarkerConfiguration(</br>
            FreeMarkerConfig configurer) {</br>
        return configurer.getConfiguration();</br>
    }</br></br>

    @Bean</br>
    @ConditionalOnMissingBean(name = "freeMarkerViewResolver")</br>
    @ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true)</br>
    public FreeMarkerViewResolver freeMarkerViewResolver() {</br>
        FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();</br>
        this.properties.applyToViewResolver(resolver);</br>
        return resolver;</br>
    }</br></br>

    @Bean</br>
    @ConditionalOnMissingBean</br>
    @ConditionalOnEnabledResourceChain</br>
    public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {</br>
        return new ResourceUrlEncodingFilter();</br>
    }</br></br>

}</br>

其中,

(1)@ConditionalOnWebApplication(type = Type.SERVLET), 是当该应用是基于Servlet的Web应用时。

(2)@ConditionalOnMissingBean(name = "freeMarkerViewResolver"),是当Spring容器中不存在freeMarkerViewResolver的Bean时。

(3)@ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true),指定的spring.freemarker.enabled属性是否有。如果没有(IfMissing),设为true。

当(1)(2)(3)三个条件都满足,则注册freeMarkerViewResolver这个Bean。

我们也可以自定义我们自己的my-starter,以及实现对应的@MyEnableAutoConfiguration。SpringBoot有很多第三方starter,其自动配置的原理基本都是这样,比如mybatis-spring-boot-starter的MybatisAutoConfiguration,阅读源码https://github.com/mybatis/spring-boot-starter[4]

上面文字描述了这么多,再用一张形象生动的图来说明[5]:

SpringBoot Autoconfigure 工作原理图

5.5 spring.factories与定义应用程序的初始化行为

上面说了这么多,讲的都是读取properties文件中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的全限定名对应的值。SpringBoot内部还有许多其他的key用于过滤得到需要加载的类。

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

Application Listeners

org.springframework.context.ApplicationListener=</br>
org.springframework.boot.autoconfigure.BackgroundPreinitializer

Auto Configuration Import Listeners

org.springframework.boot.autoconfigure.AutoConfigurationImportListener=</br>
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

Auto Configuration Import Filters

org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=</br>
org.springframework.boot.autoconfigure.condition.OnClassCondition

Failure analyzers

org.springframework.boot.diagnostics.FailureAnalyzer=</br>
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,</br>
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,</br>
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer

Template availability providers

org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=</br>
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,</br>
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,</br>
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,</br>
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,</br>
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

这些key仍然是定义在spring-boot/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories文件中。

还有对应的用于测试的自动配置,在
spring-boot/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories文件中定义。

另外,我们使用spring.factories里还可以定制应用程序的初始化行为。这样我们就可以在应用程序载入前操纵Spring的应用程序上下文ApplicationContext。

例如,可以使用ConfigurableApplicationContext类的addApplicationListener()方法,在应用上下文ApplicationContext中创建监听器。

自动配置运行日志报告功能就是这么实现的。我们来看在spring.factories中,Initializers一段的配置:

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

其中,AutoConfigurationReportLoggingInitializer监听到系统事件时,比如上下文刷新ContextRefreshedEvent或应用程序启动故障ApplicationFailedEvent之类的事件,Spring Boot可以做一些事情。这里说的代码在AutoConfigurationReportLoggingInitializer.AutoConfigurationReportListener里面。关于支持的事件类型supportsEventType的如下:

    private class AutoConfigurationReportListener implements GenericApplicationListener {


...
@Override

public boolean supportsEventType(ResolvableType resolvableType) {

Class<?> type = resolvableType.getRawClass();

if (type == null) {

return false;

}

return ContextRefreshedEvent.class.isAssignableFrom(type)

|| ApplicationFailedEvent.class.isAssignableFrom(type);

}

    @Override</br>
    public boolean supportsSourceType(Class&lt;?&gt; sourceType) {</br>
        return true;</br>
    }</br></br>

    @Override</br>
    public void onApplicationEvent(ApplicationEvent event) {</br>
AutoConfigurationReportLoggingInitializer.this.onApplicationEvent(event);</br>
    }</br></br>

}</br>

要以调试模式启动应用程序,可以使用-Ddebug标识,或者在application.properties文件这添加属性debug= true。这样,当我们以调试模式启动应用程序时,SpringBoot就可以帮助我们创建自动配置的运行报告。对于每个自动配置,通过报告我们可以看到它启动或失败的原因。 这个报告内容格式大致如下:

=========================
AUTO-CONFIGURATION REPORT
=========================


Positive matches:

-----------------

DataSourceAutoConfiguration matched:

- @ConditionalOnClass found required classes \'javax.sql.DataSource\', \'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType\'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)

DataSourceAutoConfiguration#dataSourceInitializer matched:

- @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer; SearchStrategy: all) did not find any beans (OnBeanCondition)

DataSourceAutoConfiguration.PooledDataSourceConfiguration matched:

- AnyNestedCondition 2 matched 0 did not; NestedCondition on DataSourceAutoConfiguration.PooledDataSourceCondition.PooledDataSourceAvailable PooledDataSource found supported DataSource; NestedCondition on DataSourceAutoConfiguration.PooledDataSourceCondition.ExplicitType @ConditionalOnProperty (spring.datasource.type) matched (DataSourceAutoConfiguration.PooledDataSourceCondition)

- @ConditionalOnMissingBean (types: javax.sql.DataSource,javax.sql.XADataSource; SearchStrategy: all) did not find any beans (OnBeanCondition)

...

Exclusions:

-----------

None</br></br>

Unconditional classes:

----------------------

org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration</br></br>

org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration</br></br>

org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration</br></br>

org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration</br></br></br>

除了SpringBoot官方提供的starter外,还有社区贡献的很多常用的第三方starter,列表可参考[2]。

另外,国内很多公司使用RPC框架dubbo,关于SpringBoot集成dubbo,可参考:https://github.com/linux-china/spring-boot-dubbo

参考资料:

1.http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-starter

2.https://github.com/spring-projects/spring-boot/tree/master/spring-boot-starters

3.http://www.cnblogs.com/javaee6/p/3714719.html

4.https://github.com/mybatis/spring-boot-starter

5.https://afoo.me/posts/2015-07-09-how-spring-boot-works.html

      </div>

以上是关于Spring —— Spring Boot 配置文件的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot配置404500页面

Spring Boot2 系列教程 | yaml 配置文件详解

Spring boot @ConfigurationProperties 和@Value

Spring Boot + MyBatis + Pagehelper 配置多数据源

Spring Boot 多模块项目创建与配置[转]

Spring Boot 自定义kafka 消费者配置 ContainerFactory最佳实践