我们可以去到上边提到的spring.factories文件中去看一下,找到spring官方提供的spring-boot-autoconfigure包,在其下去找一下该文件:
可以看到这个就是SpringBoot官方为我们提供的所有自动配置类的候选列表。我们可以在其中找到一个我们比较熟悉的自动配置类去看一下它内部的实现:
可以看到这些一个个的都是JavaConfig配置类,而且都通过@Bean注解向容器中注入了一些Bean
结论:
- SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的所有自动配置类的全限定类名
- 将这些自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
- 整个J2EE的整体解决方案和自动配置都在spring-boot-autoconfigure的jar包中;
- 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
- 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;
自动配置类被注入到容器当中后,会帮我们进行组件的自动配置和自动注入的工作,我们以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释这个过程:
首先我们先看下SpringBoot中配置文件与POJO类之间映射的方法,这是进行自动配置的基础。
配置集中化管理:SpringBoot中所有可配置项都集中在一个文件中(application.yml),这个文件中的配置通过@ConfigurationProperties注解来与我们程序内部定义的POJO类来产生关联,这些POJO类统一命名为xxxProperties,并且这些xxxProperties类中各个属性字段都有自己的默认值,这也是SpringBoot约定大于配置理念的体现,尽可能减少用户做选择的次数,但同时又不失灵活性。只要我们想,配置文件中的配置随时可以覆盖默认值。
之后,通过配合@EnableConfigurationProperties注解,就可以自动将与配置文件绑定好的这个类注入到容器中供我们使用。
自动配置类的工作流程:
- 根据限定的条件向容器中注入组件
- 使用xxxProperties对注入的组件的相关属性进行配置
//表示这是一个配置类,和以前编写的配置文件一样,也可以给容器中添加组件;
@Configuration
//将与配置文件绑定好的某个类注入到容器中,使其生效
//进入这个HttpProperties查看,将配置文件中对应的值和HttpProperties绑定起来;
//并把HttpProperties加入到ioc容器中
@EnableConfigurationProperties(HttpProperties.class)
//Spring底层@Conditional注解
//根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效;
//这里的意思就是判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
//判断系统中有没有CharacterEncodingFilter这个类,如果有配置类才生效
@ConditionalOnClass(CharacterEncodingFilter.class)
//判断配置文件中是否存在某个配置:spring.http.encoding.enabled;
//matchIfMissing = true表明即使我们配置文件中不配置pring.http.encoding.enabled=true,该配置类也是默认生效的;
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
//该类已经与配置文件绑定了
private final HttpProperties.Encoding properties;
//构建该自动配置类时将与配置文件绑定的配置类作为入参传递进去
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name()); //注入bean时使用配置类中属性的值进行初始化,相当于将配置文件中的值映射到了组件的某些属性上
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter; //注入配置好的bean
}
}
一句话总结下自动配置类的工作过程 :
- 首先容器会根据当前不同的条件判断,决定这个配置类是否生效!
- 一但这个配置类生效;这个配置类就会给容器中添加相应组件;
- 这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
- 所有在配置文件中能配置的属性都是在xxxxProperties类中封装着,配置文件可以配置什么内容,可以参照该前缀对应的属性类中的属性字段
//从配置文件中获取指定的值和bean的属性进行绑定
@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties {
// .....
}
1、SpringBoot启动会加载大量的自动配置类
2、我们首先可以看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
3、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
4、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
xxxxAutoConfigurartion:自动配置类;给容器中添加组件
xxxxProperties:封装配置文件中相关属性;
了解完自动装配的原理后,我们来关注一个细节问题,自动配置类必须在一定的条件下才能生效;
@Conditional派生注解(Spring注解版原生的@Conditional作用)
作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置里面的所有内容才生效;
@Conditional扩展注解 | 作用(判断是否满足当前条件) |
@ConditionalOnNotWebApplication | 当前不是web环境 |
@ConditionalOnWebApplication | 当前是web环境 |
@ConditionalOnResource | 类路径下是否有指定资源文件 |
@ConditionalOnExpression | 满足SpEL表达式指定 |
@ConditionalOnMissingBean | 容器中不存在指定的Bean |
@ConditionalOnBean | 容器中是否存在指定的Bean |
@ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnMissingClass | 系统中没有指定的类 |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
那么多的自动配置类,必须在一定的条件下才能生效;也就是说,我们加载了这么多的配置类,但不是所有的都生效了。
我们怎么知道哪些自动配置类生效?
我们可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;
#在配置文件中开启springboot的调试类
debug=true
Positive matches:(自动配置类启用的:正匹配)
Positive matches:
-----------------
AopAutoConfiguration matched:
- @ConditionalOnClass found required classes 'org.springframework.context.annotation.EnableAspectJAutoProxy', 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice', 'org.aspectj.weaver.AnnotatedElement' (OnClassCondition)
- @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)
AopAutoConfiguration.CglibAutoProxyConfiguration matched:
- @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)
AuditAutoConfiguration#auditListener matched:
- @ConditionalOnMissingBean (types: org.springframework.boot.actuate.audit.listener.AbstractAuditListener; SearchStrategy: all) did not find any beans (OnBeanCondition)
AuditAutoConfiguration#authenticationAuditListener matched:
- @ConditionalOnClass found required class 'org.springframework.security.authentication.event.AbstractAuthenticationEvent' (OnClassCondition)
- @ConditionalOnMissingBean (types: org.springframework.boot.actuate.security.AbstractAuthenticationAuditListener; SearchStrategy: all) did not find any beans (OnBeanCondition)
Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
Negative matches:
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
AopAutoConfiguration.JdkDynamicAutoProxyConfiguration:
Did not match:
- @ConditionalOnProperty (spring.aop.proxy-target-class=false) did not find property 'proxy-target-class' (OnPropertyCondition)
AppOpticsMetricsExportAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'io.micrometer.appoptics.AppOpticsMeterRegistry' (OnClassCondition)
ArtemisAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
Exclusions、Unconditional classes(排除的、没有限定条件的自动配置类):
Exclusions:
-----------
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
Unconditional classes:
----------------------
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration