目录
配置文件到底能写什么?怎么写?自动配置原理;
1、获取有效自动配置类
.@SpringBootApplication: Spring Boot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot需要运行这个类的main方法来启动SpringBoot应用;
SpringBootApplication
@Target(ElementType.TYPE) 设置当前注解可以标记在哪(类、方法等)
@Retention(RetentionPolicy.RUNTIME) 当注解标注的类编译以什么方式保留
RetentionPolicy.RUNTIME----会被jvm加载
@Documented java doc 会生成注解信息
@Inherited 是否会被继承
@SpringBootConfiguration:Spring Boot的配置类;
标注在某个类上,表示这是一个Spring Boot的配置类;
@Configuration:配置类上来标注这个注解;
配置类 ----- 配置文件;
配置类也是容器中的一个组件;@Component
@ComponentScan : 扫描包 相当于在spring.xml 配置中<context:comonent-scan> 但是并没有指定basepackage,如果没有指定spring底层会自动扫描当前配置类所有在的包
TypeExcludeFilter:springboot对外提供的扩展类, 可以供我们去按照我们的方式进行排除
AutoConfigurationExcludeFilter:排除所有配置类并且是自动配置类中里面的其中一个
@EnableAutoConfiguration:开启自动配置功能;
以前我们需要配置的东西,Spring Boot帮我们自动配置;@EnableAutoConfiguration告诉SpringBoot开启自动配置,会帮我们自动去加载 自动配置类
这个注解里面,最主要的就是@EnableAutoConfiguration,这么直白的名字,一看就知道它要开启自动配置,SpringBoot要开始骚了,于是默默进去@EnableAutoConfiguration的源码。
@AutoConfigurationPackage : 将当前配置类所在包保存在BasePackages的Bean中。供Spring内部使用,
就是注册了一个保存当前配置类所在包的一个Bean
@Import(AutoConfigurationImportSelector.class) 关键点!
可以看到,在@EnableAutoConfiguration注解内使用到了@import注解来完成导入配置的功能,而AutoConfigurationImportSelector实现了DeferredImportSelector;Spring内部在解析@Import注解时会调用getAutoConfigurationEntry方法
DeferredImportSelector工作原理:
判断有没有实现getImportGroup()方法,没有的话执行selectImports返回一个数组,将数组中的完整类名注册为Bean;有的话要返回一个自定义的实现DeferredImportSelector.Group的类,然后执行这个类中的process和selectimports方法
启动application时,走到了AutoConfigurationImportSelector的getImportGroup方法
返回了一个自定义的实现DeferredImportSelector.Group的类AutoConfigurationGroup
接下来会执行process方法
调用getAutoConfigurationEntry方法获取所有有效的配置类
调用getCandidateConfigurations获取所有配置类
此方法有调用getSpringFactoriesLoaderFactoryClass,
拿到EnableAutoConfiguration作为参数传入SpringFactoriesLoader.loadFactoryNames
loadSpringFactories去读取存放配置类的文件META-INF/spring.factories,会去所有jar包和类路径去读取这个文件
其实这个方法在之前已经调用过了,是在new SpringApplication 时调用的,会将读出来的结果放到缓存中
其中和自动装配相关的spring.factories
loadSpringFactories会得到所有的配置类
之后调用getOrDefault 根据EnableAutoConfiguration 过滤
拿到所有的自动配置类
getCandidateConfigurations返回的就是所有的自动配置类,就是帮我们整合第三方库做的默认配置
之后会调用这个方法
根据pom依赖中添加的starter过滤出有效的自动配置类
每一个这样的 xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置;
后续:这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。
2、自动配置生效(配置文件关联配置类)
以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理;
@Configuration(proxyBeanMethods = false)
- 标记了@Configuration Spring底层会给配置创建cglib动态代理。 作用:就是防止每次调用本类的Bean方法而重新创建对象,Bean是默认单例的
这里proxyBeanMethods = false 表示调用本类的Bean方法会重新创建对象,可以理解为时多例的
@EnableConfigurationProperties(ServerProperties.class) 开启配置属性
- 启用可以在配置类设置的属性 对应的类
它后面的参数是一个ServerProperties类,这就是习惯优于配置的最终落地点。
在这个类上,我们看到了一个非常熟悉的注解:@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中(见上面截图)。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。
至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。
而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。
@ConditionalOnBean:当容器里有指定的bean的条件下。
@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
@ConditionalOnClass:当类路径下有指定类的条件下。
@ConditionalOnMissingClass:当类路径下不存在指定类的条件下。
@ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”spring.http.encoding”, value=”enable”, matchIfMissing=true)
其中prefix指定了配置的统一前缀“spring.http.encoding”,而value指定了具体的属性名称为“enabled”。这里并没有设置havingValue的值,如果havingValue未指定值,默认情况下在属性配置中设置的值为true则生效(如上配置),false则不生效。
@ConditionalOnProperty(prefix = "filter",name = "loginFilter",havingValue = "true")
//prefix为配置文件中的前缀, //name为配置的名字 //havingValue是与配置的值对比值,当两个值相同返回true,配置类生效.
@Conditionalxxx根据当前不同的条件判断,决定这个配置类是否生效?
@Conditional派生注解(Spring注解版原生的@Conditional作用)
作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;
@Conditional扩展注解作用 | (判断是否满足当前指定条件) |
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定Bean; |
@ConditionalOnMissingBean | 容器中不存在指定Bean; |
@ConditionalOnExpression | 满足SpEL表达式指定 |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnMissingClass | 系统中没有指定的类 |
@ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定资源文件 |
@ConditionalOnWebApplication | 当前是web环境 |
@ConditionalOnNotWebApplication | 当前不是web环境 |
@ConditionalOnJndi | JNDI存在指定项 |
我们怎么知道哪些自动配置类生效;
我们可以通过设置配置文件中:启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;
细节
一但这个配置类生效;这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
所有在配置文件中能配置的属性都是在xxxxProperties类中封装;配置文件能配置什么就可以参照某个功能对应的这个属性类
还记得这个过滤器吧, 对,就是我们以前设置编码的, 我们现在不需要去web.xml配置过滤器了, 只需要往容器中注入该过滤器。它的值都是通过properties设置的
比如需要配置编码那就可以推算出
properties.getServlet().getEncoding().setCharset(UTF_8); 就等于如下配置:
properties= server 为什么呢? 因为 ServerProperties 上面有个注解@ConfigurationProperties(prefix = "server") 已经设置名为server
getServlet()= servlet
getEncoding()=encoding
setCharset(UTF_8)= charset=UTF-8
server.servlet.encoding.charset=UTF-8
所以只有知道了自动配置的原理及源码 才能灵活的配置SpringBoot
一定要记得XxxxProperties类的含义是:封装配置文件中相关属性;XxxxAutoConfiguration类的含义是:自动配置类,目的是给容器中添加组件。
简单总结:可以分为两步,1、获取有效自动配置类2、自动配置生效
Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。
自动配置流程图
https://www.processon.com/view/link/5fc0abf67d9c082f447ce49b