关于Spring Boot 的运作原理,我们还是回归到@SpringBootApplication 注解上来,这个注解是一个组合注解,它的核心功能是由@EnableAutoConfiguration 注解提供的。
下面我们来看下@EnableAutoConfiguration 注解的源码:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
这里的关键功能是@Import 注解导入的配置功能,EnableAutoConfigurationImportSelector 使用SpringFactoriesLoader.loadFactoryNames 方法来扫描具有META-INF/spring.factories 文件的jar包,而我们的spring-boot-autoconfigure-1.3.0.x.jar 里就有一个spring.factories 文件,此文件中声明了有哪些自动配置,如图3 所示。
# 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.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,\
图3 自动配置
打开上面任意一个AutoConfiguration 文件, 一般都有下面的条件注解, 在
spring-boot-autoconfigure-1.3.0.x.jar 的org.springframwork.boot.autoconfigure.condition 包下,条件注解如下。
@ConditionalOnBean:当容器里有指定的Bean 的条件下。
@ConditionalOnClass:当类路径下有指定的类的条件下。
@ConditionalOnExpression:基于SpEL 表达式作为判断条件。
@ConditionalOnJava:基于JVM 版本作为判断条件。
@ConditionalOnJndi:在JNDI 存在的条件下查找指定的位置。
@ConditionalOnMissingBean:当容器里没有指定Bean 的情况下。
@ConditionalOnMissingClass:当类路径下没有指定的类的条件下。
@ConditionalOnNotWebApplication:当前项目不是Web 项目的条件下。
@ConditionalOnProperty:指定的属性是否有指定的值。
@ConditionalOnResource:类路径是否有指定的值。
@ConditionalOnSingleCandidate:当指定Bean 在容器中只有一个,或者虽然有多个但是指定首选的Bean。
@ConditionalOnWebApplication:当前项目是Web 项目的条件下。
这些注解都是组合了@Conditional 元注解,只是使用了不同的条件(Condition)。
实例分析
在了解了Spring Boot 的运作原理和主要的条件注解后,现在来分析一个简单的Spring Boot 内置的自动配置功能:http 的编码配置。
我们在常规项目中配置http 编码的时候是在web.xml 里配置一个filter,如:
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
自动配置要满足两个条件:
- 能配置CharacterEncodingFilter 这个Bean;
- 能配置encoding 和forceEncoding 这两个参数。
1.配置参数
Spring Boot 的自动配置是基于类型安全的配置实现的,这里的配置类可以在application.properties 中直接设置,源码如下:
@ConfigurationProperties(prefix = "spring.http.encoding")//1
public class HttpEncodingProperties {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");//2
private Charset charset = DEFAULT_CHARSET; //2
private boolean force = true; //3
public Charset getCharset() {
return this.charset;
}
public void setCharset(Charset charset) {
this.charset = charset;
}
public boolean isForce() {
return this.force;
}
public void setForce(boolean force) {
this.force = force;
}
}
代码解释
① 在application.properties 配置的时候前缀是spring.http.encoding;
② 默认编码方式为UTF-8,若修改可使用spring.http.encoding.charset=编码;
③ 设置forceEncoding,默认为true,若修改可使用spring.http.encoding.force=false。
2.配置Bean
通过调用上述配置,并根据条件配置CharacterEncodingFilter 的Bean,我们来看看源码:
@Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class) //1
@ConditionalOnClass(CharacterEncodingFilter.class) //2
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled",
matchIfMissing = true) //3
public class HttpEncodingAutoConfiguration {
@Autowired
private HttpEncodingProperties httpEncodingProperties; //3
@Bean//4
@ConditionalOnMissingBean(CharacterEncodingFilter.class) //5
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.httpEncodingProperties.getCharset().name());
filter.setForceEncoding(this.httpEncodingProperties.isForce());
return filter;
}
}
代码解释
① 开启属性注入,通过@EnableConfigurationProperties 声明,使用@Autowired 注入;
② 当CharacterEncodingFilter 在类路径的条件下;
③ 当设置spring.http.encoding=enabled 的情况下,如果没有设置则默认为true,即条件符合;
④ 像使用Java 配置的方式配置CharacterEncodingFilter 这个Bean;
⑤ 当容器中没有这个Bean 的时候新建Bean。
转载:http://geek.csdn.net/news/detail/115064