SpringBoot-02-自动配置原理
自动配置原理
@SpringBootApplication 解析
我们是在 @SpringBootApplication
中确定的 SpringBoot 的程序入口,也是 SpringBoot 的初始化开始的地方。那么 SpringBoot 是如何实现自动配置的呢,将 @SpringBootApplication
点开,可以看到是下面三个注解组成的:
1 |
@SpringBootConfiguration
本质就是个 @Configuration
表示这个类是一个配置类(也就是可以当作 applicationContext.xml 使用的类),比如在里面使用注解 @Bean
代替 <bean>
来配置 IOC 容器的 Bean。
@ComponentScan
主要是用来扫描包组件的,它可以自定义扫描的 BasePackage,如果没有指定的话,就是 @SpringBootApplication
所在的地方为 BasePackage 。
@EnableAutoConfiguration
这个是核心,又包含了下面的两种注解:
1 |
@AutoConfigurationPackage
这里又套娃导入了一个 @Import({Registrar.class})
,点开 Registrar.class 可以看到,代码里面主要干了下面的事情:
自动配置包类,注册了当前路径为下面的 PackageNames 作为配置的下属包(其实也对应 @ComponentScan
):
1 | AutoConfigurationPackages.register(getPackageNames().toArray()); // 有简略 |
@Import({AutoConfigurationImportSelector.class})
这里主要导入了 AutoConfigurationImportSelector.class 这个类,主要干的事情就是:
1 | public String[] selectImports () { |
也就是获得 100 多个 web 的 starter 所需要配置的类的全类名(其实是在一个文件中写死的类名),然后返回。
SpringBoot 更厉害的是,它不是全部都真的将所有的预设类实例化并添加到 IOC 容器中的,而是根据 @Conditional
注解,根据里面的条件判断是否加载这个类。
比如虽然导入了 web-starter 的开发环境,可能需要 AOP 相关,但是 SpringBoot 是根据 @ConditionalOnClass(Advice.class)
来判断是否加载的,只有导入了 AspectJ 这个包(Advice.class 存在),SpringBoot 才会给你将 AOP 所需要的类都给加入到 IOC 容器中。
这就是传说中的按需加载。
自动装配
具体实现细节
上面大概说了说实利用 @Conditional
系列注解进行按需加载的,我们来结合一个熟悉的案例分析一下,DispatcherServlet:
上面说到了返回的 100 多个配置类的全类名统一格式都是 XXXXAutoConfiguration,通过运行这些类,来对相关内容进行自动配置。
我们点开 DispathcerServletAutoConfiguration,这个就是对 DispathcerServlet 进行自动配置的类,先看看程序头:
1 |
|
@ConditionalOnClass
表示导入了 DispathcerSevlet(也就是 SpringMVC) 后才会运行下面的自动装配类。@AutoConfigureAfter
表示先自动加载完服务器的 AutoConfiguration 之后再加载自己。这两个都是启动装配的起始条件。
再进一步就是子类 RegistrationConfiguration 了:
1 |
|
@EnableConfigurationProperties
表示使用 WebMvcProperties.class 内容作为配置文件,而这个类是使用 spring.mvc
作为配置的 prefix 的。
前面都是讲了按需加载的一些东西,那么具体的 DispatcherServlet 的配置细节在那里呢?
1 | public DispatcherServletRegistrationBean dispatcherServletRegistration() { |
可以看到是将一系列的配置信息都设置到了 registration 中,最后返回,这里就是将获取的所有配置信息设置的地方。
更改设置信息
如何修改默认的设置信息呢,当然是在 application.properties 里面修改了,那么这些修改又是如何影响到 SpringBoot 的自动装配呢,我们以 CharacterEncodingFilter 的自动装配为例展示一下:
1 | //调用外部的 服务器设置 |
根据上面的代码,我们能看到配置信息的最重要来源就是上一级的 ServerProperties.class 里面获取的,那么 ServerProperties 又是如何生成的呢?
上一篇文章前面提到了 @ConfigurationProperties(prefix="XXX")
标注了之后会从 application.properties 找到前缀为 XXX 的配置然后调用 set 方法进行配置注入。 ServerProperties.class 在创建之后会属性都是默认值,然后再经过 @ConfigurationProperties(prefix="XXX")
从配置文件中注入外部设置来覆盖默认设置。
具体从读取到 @ConfigurationProperties 再到读取 application.properties 注入设置的详细源码,一定会再详细介绍的。
现在对于 SpringBoot 的了解还是太浅了……
QAQ
自动装配总结
- SpringBoot 会首先获取所有自动装配运行类的名字,然后依次运行 XXXAutoConfiguration 的自动装配运行类,负责装配 XXX。
- 自动装配运行类通过
@Conditional
系列注解,判断满足要求之后开始从 XXXProperties.class 中拿到具体的配置信息。XXXProperties 和 application.properties 绑定。 - 自动装配运行类运行后会向 IOC 容器中添加很多配置好的组件,IOC 有了这些配置好的组件之后就拥有了对应的功能。
- 可以通过自己使用
@Bean
向 IOC 中添加配件来实现自定义配置,或者在 application.properties 中设置自定义配置。
自动装配开发技巧
开发的时候将对应的场景依赖引入即可,xxx-starter
查看场景依赖的哪些元素装配了,可以在设置中设置 debug=true,会打印日志,Positive 生效部分,Negative 不生效部分