实打实的springboot源码
//springboot的源码就两个重点
//@SpringBootApplication注解
//SpringApplication.run()方法
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
从run()方法开始吧
// run方法是一个静态方法,用于启动SpringBoot
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
// 继续调用静态的run方法
return run(new Class<?>[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
/**
* 构建一个SpringApplication对象,该对象主要封装了环境web具体类型和监听器
* 并调用其run方法来启动
*/
return new SpringApplication(primarySources).run(args);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 【1】给resourceLoader属性赋值,注意传入的resourceLoader参数为null
this.resourceLoader = resourceLoader;
// 【1.5】 判断传入的primarySources参数是否为空,如果为空报错
Assert.notNull(primarySources, "PrimarySources must not be null");
// 【2】给primarySources属性赋值,传入的primarySources其实就是SpringApplication.run(MainApplication.class, args);中的MainApplication.class
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
/**
* 【3】给webApplicationType属性赋值,根据classpath中存在哪种类型的类来确定是哪种应用类型
* 有两种web类型 1.servlet
* 2.reactive
*/
this.webApplicationType = WebApplicationType.deduceFromClasspath();
static WebApplicationType deduceFromClasspath() {
// 若classpath中不存在"org.springframework." + "web.servlet.DispatcherServlet"和"org.glassfish.jersey.servlet.ServletContainer"
// 则返回WebApplicationType.REACTIVE,表明是reactive应用
//如果两个都存在返回servlet应用
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
// 若{ "javax.servlet.Servlet",
// "org.springframework.web.context.ConfigurableWebApplicationContext" }
// 如果SERVLET和WEBFLUX都不存在,则说明是不是web应用
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
// 最终返回普通的servlet应用
return WebApplicationType.SERVLET;
}
/**
* 【4】给initializers属性赋值,利用SpringBoot自定义的SPI从spring.factories中加载ApplicationContextInitializer接口的实现类并赋值给initializers属性,和下面的setListeners()差不多,只分析一个即可
* 此时仅仅只是把对象new出来保存在initializers集合中
*/
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
/**
* 【5】给listeners属性赋值,利用SpringBoot自定义的SPI从spring.factories中加载ApplicationListener接口的实现类并赋值给listeners属性
* 此时仅仅只是把对象new出来保存在listeners集合中,和上面方法同理,只是传入的接口类型不同
*/
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[]{});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
// 【1】获得类加载器
ClassLoader classLoader = getClassLoader();
/**
* 【2】将接口类型和类加载器作为参数传入loadFactoryNames方法,从/META-INF/spring.factories配置文件中进行加载接口实现类
* names中保存了配置文件中key为ApplicationContextInitializer中的每一个value '/' 作为value分隔符
*/
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 【3】利用反射实例化从spring.factories中加载的接口实现类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
// 新建instances集合,用于存储稍后实例化后的SPI扩展类对象
List<T> instances = new ArrayList<>(names.size());
// 遍历name集合,names集合存储了所有SPI扩展类的全限定名
for (String name : names) {
try {
// 根据全限定名利用反射加载类
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
// 断言刚才加载的SPI扩展类是否属于SPI接口类型
Assert.isAssignable(type, instanceClass);
// 获得SPI扩展类的构造器
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
// 实例化SPI扩展类
T instance = (T) BeanUtils.instantiateClass(constructor, args);
// 添加进instances集合
instances.add(instance);
} catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
// 返回
return instances;
}
// 【4】进行排序
AnnotationAwareOrderComparator.sort(instances);
// 【5】返回加载并实例化好的接口实现类
return instances;
}
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
/**
* 【6】给mainApplicationClass属性赋值,即这里要推断哪个类调用了main函数,然后再赋值给mainApplicationClass属性,用于后面启动流程中打印一些日志。
* 在此处抛出了一个异常,然后拿到异常栈信息,因为异常栈封装了从入口到异常的所有方法的信息
* 遍历异常栈,找到方法名为main的方法,拿到该方法所在类的全限定类名保存到 mainApplicationClass 属性中
*/
this.mainApplicationClass = deduceMainApplicationClass();
}
public ConfigurableApplicationContext run(String... args) {
// new 一个StopWatch用于统计run启动过程花了多少时间
StopWatch stopWatch = new StopWatch();
// 开始计时
stopWatch.start();
ConfigurableApplicationContext context = null;
// exceptionReporters集合用来存储异常报告器,用来报告SpringBoot启动过程的异常
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 配置headless属性,即“java.awt.headless”属性,默认为ture
// 其实是想设置该应用程序,即使没有检测到显示器,也允许其启动.对于服务器来说,是不需要显示器的,所以要这样设置.
configureHeadlessProperty();
/**
* 监听者模式
* 【1】从spring.factories配置文件中加载到EventPublishingRunListener对象并赋值给SpringApplicationRunListeners
* EventPublishingRunListener对象可以理解为一个广播器
* 广播器拥有所有监听器的引用
* 主要用来发射SpringBoot启动过程中内置的一些生命周期事件(标志每个不同启动阶段),并且会根据不同的事件向不同的监听器发射事件
* 然后监听器执行方法
*
* 也就说此时这个 listeners 就是一个广播器
*
*/
SpringApplicationRunListeners listeners = getRunListeners(args);
/**
* 调用广播器的starting方法,
*/
listeners.starting();
private SpringApplicationRunListeners getRunListeners(String[] args) {
// 构造一个由SpringApplication.class和String[].class组成的types
Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
// 1) 根据SpringApplicationRunListener接口去spring.factories配置文件中加载其SPI扩展实现类
// 2) 构建一个SpringApplicationRunListeners对象并返回
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
public void starting() {
// 遍历listeners集合,这里实质取出的就是刚才从spring.factories中取出的SPI实现类EventPublishingRunListener
// 而EventPublishingRunListener对象承担了SpringBoot启动过程中负责广播不同的生命周期事件
for (SpringApplicationRunListener listener : this.listeners) {
// 调用EventPublishingRunListener的starting方法来广播ApplicationStartingEvent事件
listener.starting();
}
}
try {
// 创建ApplicationArguments对象,封装了args参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
/**
* 【2】准备环境变量,包括系统变量,环境变量,命令行参数,默认变量,servlet相关配置变量,随机值,
* JNDI属性值,以及配置文件(比如application.properties)等,注意这些环境变量是有优先级的
* 为什么有优先级:因为spring的yml文件可以同时存在好几个,springboot会把按照顺序把这些配置文件都读取一遍
* 后面读取的属性会覆盖前面相同属性的值
* 并且还会根据设置的spring-profiles 和 spring.profiles.active 选择读取那个环境(生产、测试、上线)yml文件
*
* 重点!!!!springboot的自动装配
*
* 1.yml文件为什么会有提示?
* @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) serverProperties类上的注解
* @ConfigurationProperties spring-boot 提供该注解将配置文件的值映射到类上使用。
* 建立一个映射,spring会扫描所有加了该注解的bean,然后这些bean的属性映射到 yml文件
*
* 2.serverProperties类这些类是如何被springboot放到bdMap中的
* @SpringBootApplication -> @EnableAutoConfiguration -> @Import(AutoConfigurationImportSelector.class)
* AutoConfigurationImportSelector implements ImportSelector -> selectImports() 把返回值注册进bdMap
* SpringFactoriesLoader.loadFactoryNames() 还是从spring.factories 找到所有 EnableAutoConfiguration实现类
* 变成bd注册进bdMap中 —> 这些实现类他上面又有@EnableConfigurationProperties(ServerProperties.class)注解
* -> @Import(EnableConfigurationPropertiesImportSelector.class)
* 注册了两个后置处理器
* -> ConfigurationPropertiesBeanRegistrar.class.getName()
* ConfigurationPropertiesBindingPostProcessorRegistrar.class.getName()
* -> ConfigurationPropertiesBeanRegistrar implements ImportBeanDefinitionRegistrar
* -> register(registry,(ConfigurableListableBeanFactory) registry, type);
* 把serverProperties这个类注册进容器中,用来接收application.yml中的值
*
* 3.yml文件是如何加载到springboot中?
* prepareEnvironment() -> 发射【ApplicationEnvironmentPreparedEvent】事件
* -> 扫描默认的路径读取属性 -> 保存在 ConfigurableEnvironment 中
*
* ConfigurationPropertiesBindingPostProcessorRegistrar上一步注册的后置处理器最终完成属性的绑定
* 即把值保存在对应的 xxxxProperties 的bean中
*
*
* TODO 这里准备环境变量是不是加载所有application.properties等环境变量?跟Spring的加载环境变量有啥区别?是不是这里加载了Spring那边就不用再管了?自己在application.properties,外部参数等可以设置环境变量的地方上编辑多个环境变量看这里能否加载进来???
* TODO 自己想想加密的属性是如何扩展的?如何改造?
*/
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// 配置spring.beaninfo.ignore属性,默认为true,即跳过搜索BeanInfo classes.
configureIgnoreBeanInfo(environment);
// 【3】控制台打印SpringBoot的banner标志
Banner printedBanner = printBanner(environment);
// 【4】根据不同类型创建不同类型的spring applicationContext容器
// 因为这里是servlet环境,所以创建的是AnnotationConfigServletWebServerApplicationContext容器对象
context = createApplicationContext();
// 【5】从spring.factories配置文件中加载异常报告期实例,这里加载的是FailureAnalyzers
// 注意FailureAnalyzers的构造器要传入ConfigurableApplicationContext,因为要从context中获取beanFactory和environment
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[]{ConfigurableApplicationContext.class}, context); // ConfigurableApplicationContext是AnnotationConfigServletWebServerApplicationContext的父接口
// 【6】为刚创建的AnnotationConfigServletWebServerApplicationContext容器对象做一些初始化工作,准备一些容器属性值等
// 1)为AnnotationConfigServletWebServerApplicationContext的属性AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner设置environgment属性
// 2)根据情况对ApplicationContext应用一些相关的后置处理,比如设置resourceLoader属性等
// 3)在容器刷新前调用各个ApplicationContextInitializer的初始化方法,ApplicationContextInitializer是在构建SpringApplication对象时从spring.factories中加载的
// 4)》》》》》发射【ApplicationContextInitializedEvent】事件,标志context容器被创建且已准备好
// 5)从context容器中获取beanFactory,并向beanFactory中注册一些单例bean,比如applicationArguments,printedBanner
// 6)TODO 加载bean到application context,注意这里只是加载了部分bean比如mainApplication这个bean,大部分bean应该是在AbstractApplicationContext.refresh方法中被加载?这里留个疑问先
// 7)》》》》》发射【ApplicationPreparedEvent】事件,标志Context容器已经准备完成
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 【7】刷新容器,这一步至关重要,以后会在分析Spring源码时详细分析,主要做了以下工作:
// 1)在context刷新前做一些准备工作,比如初始化一些属性设置,属性合法性校验和保存容器中的一些早期事件等;
// 2)让子类刷新其内部bean factory,注意SpringBoot和Spring启动的情况执行逻辑不一样
// 3)对bean factory进行配置,比如配置bean factory的类加载器,后置处理器等
// 4)完成bean factory的准备工作后,此时执行一些后置处理逻辑,子类通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置
// 在这一步,所有的bean definitions将会被加载,但此时bean还不会被实例化
// 5)执行BeanFactoryPostProcessor的方法即调用bean factory的后置处理器:
// BeanDefinitionRegistryPostProcessor(触发时机:bean定义注册之前)和BeanFactoryPostProcessor(触发时机:bean定义注册之后bean实例化之前)
// 6)注册bean的后置处理器BeanPostProcessor,注意不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的
// 7)初始化国际化MessageSource相关的组件,比如消息绑定,消息解析等
// 8)初始化事件广播器,如果bean factory没有包含事件广播器,那么new一个SimpleApplicationEventMulticaster广播器对象并注册到bean factory中
/**
* 9)AbstractApplicationContext定义了一个模板方法onRefresh,留给子类覆写,比如ServletWebServerApplicationContext覆写了该方法来创建内嵌的tomcat容器
* 此时他仅仅只是把Tomcat给实例化出来,并没有与 DispatcherServlet 进行绑定
* DispatcherServletAutoConfiguration这个配置类进行实例化bean的过程中(构造方法)
* 完成了 Tomcat和 DispatcherServlet 绑定
*/
// 10)注册实现了ApplicationListener接口的监听器,之前已经有了事件广播器,此时就可以派发一些early application events
// 11)完成容器bean factory的初始化,并初始化所有剩余的单例bean。这一步非常重要,一些bean postprocessor会在这里调用。
// 12)完成容器的刷新工作,并且调用生命周期处理器的onRefresh()方法,并且发布ContextRefreshedEvent事件
refreshContext(context);
// 【8】执行刷新容器后的后置处理逻辑,注意这里为空方法
afterRefresh(context, applicationArguments);
// 停止stopWatch计时
stopWatch.stop();
// 打印日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 》》》》》发射【ApplicationStartedEvent】事件,标志spring容器已经刷新,此时所有的bean实例都已经加载完毕
listeners.started(context);
// 【9】调用ApplicationRunner和CommandLineRunner的run方法,实现spring容器启动后需要做的一些东西比如加载一些业务数据等
callRunners(context, applicationArguments);
}
// 【10】若启动过程中抛出异常,此时用FailureAnalyzers来报告异常
// 并》》》》》发射【ApplicationFailedEvent】事件,标志SpringBoot启动失败
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 》》》》》发射【ApplicationReadyEvent】事件,标志SpringApplication已经正在运行即已经成功启动,可以接收服务请求了。
listeners.running(context);
}
// 若出现异常,此时仅仅报告异常,而不会发射任何事件
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
// 这个语句是我自己加上去的,spring容器刷新完毕后用来打印容器中加载的bean信息
String[] definitionNames = context.getBeanDefinitionNames();
/** TODO
* **思考**: SpringBoot的`run`方法会调用`prepareContext`会加载一些`bean`,
* 同时,在调用`AbstractApplicationContext`的`refresh`方法时也会加载一些`bean`,这些加载的`bean`有什么不同?
*/
// TODO 只有在这一步才会打印剩下的bean,不是在prepareEnvironment加载的bean???
System.out.println("=======================下面开始打印容器中所有的bean name=============================");
for (String name : definitionNames) {
System.out.println(name);
}
System.out.println("=======================打印容器中所有的bean name结束=============================");
// 【11】最终返回容器
return context;
}
//看一下他是如何对Tomcat进行初始化的
protected void onRefresh() {
super.onRefresh();
try {
createWebServer(); // 这里创建服务器
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
// 还记得EmbeddedTomcat 配置类中注册了一个TomcatServletWebServerFactory类型的bean吗?
// getWebServerFactory方法就是从容器中获取到TomcatServletWebServerFactory类型的bean
ServletWebServerFactory factory = getWebServerFactory();
//调用TomcatServletWebServerFactory的getWebServer方法得到Tomcat服务器
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
// TODO:这里的初始化属性源跟ConfigFileApplicationListener监听加载属性配置有何关系???// 替换Servlet相关的属性源???
initPropertySources();
}
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory
: createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
@SpringBootApplication注解
//先分析@Import(AutoConfigurationImportSelector.class)注解
//因为实现了ImportSeclotr注解,所以直接看selectImports()方法
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 加载spring-autoconfigure-metadata.properties文件的键值对数据到autoConfigurationMetadata,
// 供AutoConfigurationImportSelector过滤加载。注意spring-autoconfigure-metadata.properties文件为maven build构建的时候生成的
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 基于@Configuration注解的元数据相关过滤条件返回自动配置类,如@SpringBootApplication(exclude = FreeMarkerAutoConfiguration.class),
// 则要排除FreeMarkerAutoConfiguration这个自动配置类
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
// 获取符合条件的自动配置类,避免加载不必要的自动配置类从而造成内存浪费
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
// 获取是否有配置spring.boot.enableautoconfiguration属性,默认返回true
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获得@Congiguration标注的Configuration类即被审视introspectedClass的注解数据,
// 比如:@SpringBootApplication(exclude = FreeMarkerAutoConfiguration.class)
// 将会获取到exclude = FreeMarkerAutoConfiguration.class和excludeName=""的注解数据
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 【1】得到spring.factories文件配置的所有自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
// 利用LinkedHashSet移除重复的配置类
configurations = removeDuplicates(configurations);
// 得到要排除的自动配置类,比如注解属性exclude的配置类
// 比如:@SpringBootApplication(exclude = FreeMarkerAutoConfiguration.class)
// 将会获取到exclude = FreeMarkerAutoConfiguration.class的注解数据
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 检查要被排除的配置类,因为有些不是自动配置类,故要抛出异常
checkExcludedClasses(configurations, exclusions);
// 【2】将要排除的配置类移除
configurations.removeAll(exclusions);
// 【3】因为从spring.factories文件获取的自动配置类太多,如果有些不必要的自动配置类都加载进内存,会造成内存浪费,因此这里需要进行过滤
// 注意这里会调用AutoConfigurationImportFilter的match方法来判断是否符合@ConditionalOnBean,@ConditionalOnClass或@ConditionalOnWebApplication,后面会重点分析一下
configurations = filter(configurations, autoConfigurationMetadata);
// 【4】获取了符合条件的自动配置类后,此时触发AutoConfigurationImportEvent事件,
// 目的是告诉ConditionEvaluationReport条件评估报告器对象来记录符合条件的自动配置类
// 该事件什么时候会被触发?--> 在刷新容器时调用invokeBeanFactoryPostProcessors后置处理器时触发
fireAutoConfigurationImportEvents(configurations, exclusions);
// 【5】将符合条件和要排除的自动配置类封装进AutoConfigurationEntry对象,并返回
return new AutoConfigurationEntry(configurations, exclusions);
}
private void fireAutoConfigurationImportEvents(List<String> configurations,
Set<String> exclusions) {
// 从spring.factories总获取到AutoConfigurationImportListener即ConditionEvaluationReportAutoConfigurationImportListener
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
// 新建一个AutoConfigurationImportEvent事件
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this,
configurations, exclusions);
// 遍历刚获取到的AutoConfigurationImportListener
for (AutoConfigurationImportListener listener : listeners) {
// 这里调用各种Aware方法用于触发事件前赋值,比如设置factory,environment等
invokeAwareMethods(listener);
// 真正触发AutoConfigurationImportEvent事件即回调listener的onXXXEveent方法。这里用于记录自动配置类的评估信息
listener.onAutoConfigurationImportEvent(event);
}
}
}
private List<String> filter(List<String> configurations,
AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
// 将从spring.factories中获取的自动配置类转出字符串数组
String[] candidates = StringUtils.toStringArray(configurations);
// 定义skip数组,是否需要跳过。注意skip数组与candidates数组顺序一一对应
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
// getAutoConfigurationImportFilters方法:拿到OnBeanCondition,OnClassCondition和OnWebApplicationCondition
// 然后遍历这三个条件类去过滤从spring.factories加载的大量配置类
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
// 调用各种aware方法,将beanClassLoader,beanFactory等注入到filter对象中,
// 这里的filter对象即OnBeanCondition,OnClassCondition或OnWebApplicationCondition
invokeAwareMethods(filter);
// 判断各种filter来判断每个candidate(这里实质要通过candidate(自动配置类)拿到其标注的
// @ConditionalOnClass,@ConditionalOnBean和@ConditionalOnWebApplication里面的注解值)是否匹配,
// 注意candidates数组与match数组一一对应
/* *********************【重点关注】******************************* */
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
@Override
public boolean[] match(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata) {
// 创建评估报告
ConditionEvaluationReport report = ConditionEvaluationReport
.find(this.beanFactory);
// 注意getOutcomes是模板方法,将spring.factories文件种加载的所有自动配置类传入
// 子类(这里指的是OnClassCondition,OnBeanCondition和OnWebApplicationCondition类)去过滤
// 注意outcomes数组存储的是不匹配的结果,跟autoConfigurationClasses数组一一对应
/*****************************【重点关注】*********************************************/
ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses,
autoConfigurationMetadata);
boolean[] match = new boolean[outcomes.length];
// 遍历outcomes,这里outcomes为null则表示匹配,不为null则表示不匹配
for (int i = 0; i < outcomes.length; i++) {
ConditionOutcome outcome = outcomes[i];
match[i] = (outcome == null || outcome.isMatch());
if (!match[i] && outcomes[i] != null) {
// 这里若有某个类不匹配的话,此时调用父类SpringBootCondition的logOutcome方法打印日志
logOutcome(autoConfigurationClasses[i], outcomes[i]);
// 并将不匹配情况记录到report
if (report != null) {
report.recordConditionEvaluation(autoConfigurationClasses[i], this,
outcomes[i]);
}
}
}
return match;
}
// 遍历match数组,注意match顺序跟candidates的自动配置类一一对应
for (int i = 0; i < match.length; i++) {
// 若有不匹配的话
if (!match[i]) {
// 不匹配的将记录在skip数组,标志skip[i]为true,也与candidates数组一一对应
skip[i] = true;
// 因为不匹配,将相应的自动配置类置空
candidates[i] = null;
// 标注skipped为true
skipped = true;
}
}
}
// 这里表示若所有自动配置类经过OnBeanCondition,OnClassCondition和OnWebApplicationCondition过滤后,全部都匹配的话,则全部原样返回
if (!skipped) {
return configurations;
}
// 建立result集合来装匹配的自动配置类
List<String> result = new ArrayList<>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
// 若skip[i]为false,则说明是符合条件的自动配置类,此时添加到result集合中
if (!skip[i]) {
result.add(candidates[i]);
}
}
// 打印日志
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in "
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)
+ " ms");
}
// 最后返回符合条件的自动配置类
return new ArrayList<>(result);
}
最后分析一个点,application.properties是如何绑定的
- 这个类一定会被加载,别问为什么,上面的代码debug自己走一遍绝对看得到
public static class ConfigurationPropertiesBeanRegistrar
implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, // metadata是AnnotationMetadataReadingVisitor对象,存储了某个配置类的元数据
BeanDefinitionRegistry registry) {
// (1)得到@EnableConfigurationProperties注解的所有属性值,
// 比如@EnableConfigurationProperties(ServerProperties.class),那么得到的值是ServerProperties.class
// (2)然后再将得到的@EnableConfigurationProperties注解的所有属性值注册到容器中
getTypes(metadata).forEach((type) -> register(registry,
(ConfigurableListableBeanFactory) registry, type));
}
}
private void register(BeanDefinitionRegistry registry,
ConfigurableListableBeanFactory beanFactory, Class<?> type) {
// 得到type的名字,一般用类的全限定名作为bean name
String name = getName(type);
// 根据bean name判断beanFactory容器中是否包含该bean
if (!containsBeanDefinition(beanFactory, name)) {
// 若不包含,那么注册bean definition
registerBeanDefinition(registry, name, type);
}
}
public class ConfigurationPropertiesBindingPostProcessorRegistrar
implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// 若容器中没有注册ConfigurationPropertiesBindingPostProcessor这个处理属性绑定的后置处理器,
// 那么将注册ConfigurationPropertiesBindingPostProcessor和ConfigurationBeanFactoryMetadata这两个bean
// 注意onApplicationEnvironmentPreparedEvent事件加载配置属性在先,然后再注册一些后置处理器用来处理这些配置属性
if (!registry.containsBeanDefinition(
ConfigurationPropertiesBindingPostProcessor.BEAN_NAME)) {
// (1)注册ConfigurationPropertiesBindingPostProcessor后置处理器,用来对配置属性进行后置处理
registerConfigurationPropertiesBindingPostProcessor(registry);
// (2)注册一个ConfigurationBeanFactoryMetadata类型的bean,
// 注意ConfigurationBeanFactoryMetadata实现了BeanFactoryPostProcessor,然后其会在postProcessBeanFactory中注册一些元数据
registerConfigurationBeanFactoryMetadata(registry);
}
}
// 注册ConfigurationPropertiesBindingPostProcessor后置处理器
private void registerConfigurationPropertiesBindingPostProcessor(
BeanDefinitionRegistry registry) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(ConfigurationPropertiesBindingPostProcessor.class);
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(
ConfigurationPropertiesBindingPostProcessor.BEAN_NAME, definition);
}
// 注册ConfigurationBeanFactoryMetadata后置处理器
private void registerConfigurationBeanFactoryMetadata(
BeanDefinitionRegistry registry) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(ConfigurationBeanFactoryMetadata.class);
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(ConfigurationBeanFactoryMetadata.BEAN_NAME,
definition);
}
}
//ConfigurationPropertiesBindingPostProcessor后置处理器的主要方法
public void afterPropertiesSet() throws Exception {
// We can't use constructor injection of the application context because
// it causes eager factory bean initialization
// 【步骤1】利用afterPropertiesSet这个勾子方法从容器中获取之前注册的ConfigurationBeanFactoryMetadata对象赋给beanFactoryMetadata属性
// (问1)beanFactoryMetadata这个bean是什么时候注册到容器中的?
// (答1)在ConfigurationPropertiesBindingPostProcessorRegistrar类的registerBeanDefinitions方法中将beanFactoryMetadata这个bean注册到容器中
// (问2)从容器中获取beanFactoryMetadata对象后,什么时候会被用到?
// (答2)beanFactoryMetadata对象的beansFactoryMetadata集合保存的工厂bean相关的元数据,在ConfigurationPropertiesBindingPostProcessor类
// 要判断某个bean是否有FactoryAnnotation或FactoryMethod时会根据这个beanFactoryMetadata对象的beansFactoryMetadata集合的元数据来查找
this.beanFactoryMetadata = this.applicationContext.getBean(
ConfigurationBeanFactoryMetadata.BEAN_NAME,
ConfigurationBeanFactoryMetadata.class);
// 【步骤2】new一个ConfigurationPropertiesBinder,用于后面的外部属性绑定时使用
this.configurationPropertiesBinder = new ConfigurationPropertiesBinder(
this.applicationContext, VALIDATOR_BEAN_NAME); // VALIDATOR_BEAN_NAME="configurationPropertiesValidator"
}
//ConfigurationBeanFactoryMetadata后置处理器的主要方法
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
this.beanFactory = beanFactory;
// 遍历beanFactory的beanDefinitionName,即每个bean的名字(比如工厂方法对应的bean名字)
for (String name : beanFactory.getBeanDefinitionNames()) {
// 根据name得到beanDefinition
BeanDefinition definition = beanFactory.getBeanDefinition(name);
// 工厂方法名:一般是注解@Bean的方法名
String method = definition.getFactoryMethodName();
// 工厂bean名:一般是注解@Configuration的类名
String bean = definition.getFactoryBeanName();
if (method != null && bean != null) {
// 将beanDefinitionName作为Key,封装了工厂bean名和工厂方法名的FactoryMetadata对象作为value装入beansFactoryMetadata中
this.beansFactoryMetadata.put(name, new FactoryMetadata(bean, method));
}
}
}