springboot的自动配置
Spring Boot理念是约定优于配置,它通过实现了自动配置(大多数用户平时习惯设置的配置作为默认配置)的功能来为用户快速构建出标准化的应用。Spring Boot的特点可以概述为如下几点:
-
内置了嵌入式的Tomcat、Jetty等Servlet容器,应用可以不用打包成War格式,而是可以直接以Jar格式运行。
-
提供了多个可选择的”starter”以简化Maven的依赖管理(也支持Gradle),让您可以按需加载需要的功能模块。
-
尽可能地进行自动配置,减少了用户需要动手写的各种冗余配置项,Spring Boot提倡无XML配置文件的理念,使用Spring Boot生成的应用完全不会生成任何配置代码与XML配置文件。
-
提供了一整套的对应用状态的监控与管理的功能模块(通过引入spring-boot-starter-actuator),包括应用的线程信息、内存信息、应用是否处于健康状态等,为了满足更多的资源监控需求,Spring Cloud中的很多模块还对其进行了扩展。
Spring Boot的自动配置看起来神奇,其实原理非常简单,背后全依赖于@Conditional注解来实现的。
什么是@Conditional?
@Conditional是由Spring 4提供的一个新特性,用于根据特定条件来控制Bean的创建行为。而在我们开发基于Spring的应用的时候,难免会需要根据条件来注册Bean。
在业务复杂的情况下,显然需要使用到@Conditional注解来提供更加灵活的条件判断,例如以下几个判断条件:
-
在类路径中是否存在这样的一个类。
-
在Spring容器中是否已经注册了某种类型的Bean(如未注册,我们可以让其自动注册到容器中,上一条同理)。
-
一个文件是否在特定的位置上。
-
一个特定的系统属性是否存在。
-
在Spring的配置文件中是否设置了某个特定的值。
我们已经在搭建springboot工程的时候体会到了配置的简洁性,没有了之前使用spring所需配置的繁琐。
那么springboot是如何做到的呢?
我们在启动类中都要添加@SpringBootApplication,有了这个注解马上就能够让整个应用跑起来。
实际上它只是一个组合注解,包含@Configuration、@EnableAutoConfiguration、@ComponentScan这三个注解。
从启动类的@SpringBootApplication进入,在里面找到了@EnableAutoConfiguration,
@EnableAutoConfiguration里通过@Import导入了EnableAutoConfigurationImportSelector
,
进入他的父类AutoConfigurationImportSelector
找到selectImports()
方法,他调用了getCandidateConfigurations()
方法,在这里,这个方法又调用了Spring Core包中的loadFactoryNames()
方法。这个方法的作用是,会查询META-INF/spring.factories
文件中包含的JAR
文件。
当找到spring.factories文件后,SpringFactoriesLoader将查询配置文件命名的属性。
Jar
文件在org.springframework.boot.autoconfigure的spring.factories
spring.factories
内容如下(截取部分),在这个文件中,可以看到一系列Spring Boot自动配置的列表。
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.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,\
下面我们来分析一下spring boot autoconfigure里面的MongoAutoConfiguration(mongodb的自动配置),相信你就会明白这套自动配置机制到底是怎么一回事儿:
@Configuration @ConditionalOnClass({MongoClient.class}) @EnableConfigurationProperties({MongoProperties.class}) //开启属性注入。 @ConditionalOnMissingBean( type = {"org.springframework.data.mongodb.MongoDbFactory"} ) public class MongoAutoConfiguration { @Autowired private MongoProperties properties; @Autowired( required = false ) private MongoClientOptions options; @Autowired private Environment environment; private MongoClient mongo; public MongoAutoConfiguration() { } @PreDestroy public void close() { if(this.mongo != null) { this.mongo.close(); } } @Bean //使用java配置,当容器中没有这个bean的时候执行初始化 @ConditionalOnMissingBean public MongoClient mongo() throws UnknownHostException { this.mongo = this.properties.createMongoClient(this.options, this.environment); return this.mongo; } }
首先这被@Configuration注解了,是一个配置类,当满足以下条件这个bean被装配:
-
当MongoClient在类路径下。
-
当容器中没有org.springframework.data.mongodb.MongoDbFactory这类bean的时候。
此外,我们可以看一下通过@EnableConfigurationProperties({MongoProperties.class}) 自动注入的属性
@ConfigurationProperties( prefix = "spring.data.mongodb" ) public class MongoProperties { public static final int DEFAULT_PORT = 27017; private String host; private Integer port = null; private String uri = "mongodb://localhost/test"; private String database; private String authenticationDatabase; private String gridFsDatabase; private String username; private char[] password; private Class<?> fieldNamingStrategy; ...... }
所以在我们什么都不干的情况下,只需要引入spring-data-mongodb这个依赖再加上默认的MongoDB server我们就能够快速集成MongoDB,用MongodbTemplate访问数据库。
同时我们可以通过在application.yaml中修改spring.data.mongodb相关的参数就能够修改连接配置,如:
spring: data: mongodb: host: localhost port: 27017 username: chingzhu password: test123 database: icekredit