9.自动配置原理
那些属性可以在配置文件中写呢:
具体:Part X. Appendices
Appendix A. Common application properties
自动配置原理:
1.springboot在启动时加载著配置类(@SpringBootApplication标注的类),开启了自动配置功能(@EnableAutoConfiguration)
2.@EnableAutoConfiguration的作用:
1.@EnableAutoConfiguration标签的代码如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage------------------>自动扫描启动类包下和其子包下的所有带标签的组件
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
...
}
2.AutoConfigurationImportSelector的代码如下:
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
...
//获取候选配置
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
....
}
3.getCandidateConfigurations的代码如下:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//第一个参数返回:EnableAutoConfiguration.class
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;
}
4.loadFactoryNames代码如下:
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
5.loadSpringFactories代码如下:
{
...
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
...
}
总结:发现其底层是获取jar类路径下的: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,\
...很多很多!
每一个这样的xxxAutoConfiguration都是容器的一个组件,都加到容器中,用他们来做自动配置!
springboot的精髓:
1.springboot启动时会加载大量的自动配置类(xxxAutoConfiguration)
2.我们看我们需要的功能有没有springboot默认写好的自动配置类
3.我们再来看这个自动配置类中到底配置了哪些组件(只要我们要用的组件有,就不需要再来配置了)
4.给容器中自动配置类添加组件时,会从properties类中获取某些属性值。我们就可以在配置文件中指定这些属性的值4
xxxAutoConfiguration:自动配置类
给容器中添加组件
xxxProperties:封装了配置文件中相关的属性
以HttpEncodingAutoConfiguration来理解其底层的(http编码自动设置)为例解释自动配置原理:
@Configuration( //表示这是一个配置类,跟以前编写的配置文件一样(<bean></bean>)也可以给容器中添加组件
proxyBeanMethods = false
)
@EnableConfigurationProperties({ServerProperties.class})//启动指定类的ConfigurationProperties功能;将配置文件中的值和ServerProperties绑定起来
//判断当前类是不是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(//里面是spring的@Conditional(条件判断注解),根据不同的条件,如果满足指定的条件,配置类中的配置就会生效
type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})//判断当前项目有没有这个类:CharacterEncodingFilter;springmvc中进行乱码解决的过滤器
@ConditionalOnProperty(//判断当前项目是否存在某个配置:server.servlet.encoding.enabled; 如果不存在,判断也是成立的()matchIfMissing = true),
//即使我们的配置文件中不配置server.servlet.encoding.enabled=true,也是默认生效的
prefix = "server.servlet.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
//这个Encoding 类是ServerProperties的内部类,所以和springboot的appliaction.properties文件以形成了映射关系(重要!)
private final Encoding properties;
@Bean//给容器中添加一个组件,这个组件的某些值要从properties中获取
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
return filter;
}
}
根据当前不同的条件判断,决定这个配置类是否生效!!
细节
1.@Conditional派生注解(spring注解版的原生的@Conditional的作用)
作用:是必须@Conditional指定的条件必须成立,才能给容器中添加组件,配置里面的内容才能生效
@Conditional扩展注解
|
作用(判断是否满足当前条件)
|
@ConditionalOnjava
|
系统的java版本是否满足要求
|
@ConditionalOnBean
|
容器中存在指定的bean
|
@ConditionalOnMissingBean
|
容器中不存在指定的bean
|
@ConditionalOnExpression
|
满足SPEL表达式的
|
@ConditionalOnClass
|
系统中存在指定的类
|
@ConditionalOnMissingClass
|
系统中不存在指定的class
|
@ConditionalOnSingleCandidate
|
容器中只有一个指定的bean,或者这个bean是首选的bean
|
@ConditionalOnProperty
|
系统中指定的属性是否存在指定的值
|
@ConditionalOnResource
|
类路径下是否存在指定的资源文件
|
自动配置类必须在一定的条件下才能生效!
我们可以在配置文件中设置;debug=true,控制台上会输出自动配置的类!
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:(自动配置类启动的)
-----------------
AopAutoConfiguration matched:
- @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)
AopAutoConfiguration.ClassProxyingConfiguration matched:
- @ConditionalOnMissingClass did not find unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition)
- @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)
。。。。
Negative matches:(自动配置类没有匹配上的)
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
AopAutoConfiguration.AspectJAutoProxyingConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'org.aspectj.weaver.Advice' (OnClassCondition)
....