一. new SpringApplication()
1. SpringApplication.run(primarySource.class, args); 启动spring程序
2. 推断项目类型(REACTIVE,NONE,SERVLET)根据当前项目引入的spring jar包 SpringApplication.deduceWebApplicationType()。
maven引入spring-boot-starter依赖的话,deduceWebApplicationType=NONE
maven引入spring-boot-starter-web依赖的话, deduceWebApplicationType=SERVLET
3. 搜索当前项目下所有的 “META-INF/spring.factories”文件里的ApplicationContextInitializer的实现类使用SpringFactoriesLoader.loadFactoryNames(type, classLoader)加载并实例化,并存放在SpringApplication.initializers中。
ApplicationContextInitializer的作用:Callback interface for initializing a Spring ConfigurableApplicationContext prior to being refreshed。
4. 搜索当前项目下所有的 “META-INF/spring.factories”文件里的ApplicationListener的实现类使用SpringFactoriesLoader.loadFactoryNames(type, classLoader)加载并实例化,并存放在SpringApplication.listeners中。
ApplicationListener的作用:监听SpringApplication,Environment事件源的各种事件。
5.根据调用堆栈找到main方法所在的类,并存放在SpringApplication.mainApplicationClass。
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if (“main”.equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
primarySources vs mainApplicationClass, primarySources是SpringApplication.run的参数,mainApplicationClass是main方法所在的类。
二. springApplication.run()
1. 搜索当前项目下所有的 “META-INF/spring.factories”文件里的SpringApplicationRunListener的实现类加载并实例化,目前默认系统只提供一个实现类EventPublishingRunListener。
2. 广播ApplicationStartingEvent事件,事件源为springApplication,给所有的SpringApplication.listeners监听者。
LoggingApplicationListener(挑选一个可用的日志系统)/BackgroundPreinitializer(启动后台线程)/DelegatingApplicationListener(去delegate other listeners,是给用户作扩展使用:可以在property里定义key为context.listener.classes的listener)/LiquibaseServiceLocatorApplicationListener四个监听可以处理此事件。
举例:
当某个事件源(如:SpringApplication, ConfigurableApplicationContext,ConfigurableEnvironment)执行某个操作(或事件,如:ApplicationStartingEvent,ApplicationReadyEvent, ApplicationEnvironmentPreparedEvent)后,SpringApplicationRunListeners.listeners会遍历所有的listener(发布器)(如:EventPublishingRunListener),这个listener发布器在由事件源初始化时已经绑定了事件源,发布器通过SimpleApplicationEventMulticaster将事件广播给所有的SpringApplication.listeners[i].onApplicationEvent()(如:LoggingApplicationListener,DelegatingApplicationListener),SpringApplication.listeners[i].onApplicationEvent()在一个方法里根据不同事件类型(ApplicationStartingEvent,ApplicationReadyEvent, ApplicationEnvironmentPreparedEvent)做不同的操作。
模式:
1)角色:事件源,发布器,监听器,事件。
2)流程:由事件源来创建发布器,创建完成后发布器就有了事件源的引用,由事件源调用发布器执行某事件,发布器先创建Event,Event的属性source使用创建发布器的事件源,然后会遍历所有注册了接受事件源(listener.supportsSourceType)的当前操作(listener.supportsEventType)的监听器去执行onAction.
3)关系:事件源依赖发布器,发布器反过来关联事件源,发布器依赖事件和监听器,监听器依赖事件。通过发布器和事件,将事件源和监听器解耦。对于可响应式组件:如HTML里的组件,事件源和发布器是同一角色,因为Button能自己感应事件并发布事件,这样就只有事件源,事件,事件处理函数三个角色。
3. 创建Environment对象,如果项目类型为SERVLET,则创建StandardServletEnvironment容器,否则创建StandardEnvironment。
广播ApplicationEnvironmentPreparedEvent事件, ConfigFileApplicationListener/AnsiOutputApplicationListener/LoggingApplicationListener/ClasspathLoggingApplicationListener/BackgroundPreinitializer/FileEncodingApplicationListener六个监听可以处理此事件,其中ConfigFileApplicationListener会搜索当前项目下所有的 “META-INF/spring.factories”文件里的EnvironmentPostProcessor的实现类加载并实例化, 并立即执行这些PostProcessor(SystemEnvironmentPropertySourceEnvironmentPostProcessor,SpringApplicationJsonEnvironmentPostProcessor,CloudFoundryVcapEnvironmentPostProcessor,ConfigFileApplicationListener)。其中ConfigFileApplicationListener这个PostProcessor会搜索当前项目下所有的 “META-INF/spring.factories”文件里的PropertySourceLoader的实现类加载并实例化,并立即执行这些PropertySourceLoader(PropertiesPropertySourceLoader,YamlPropertySourceLoader)去load加载配置文件。
最后environment生成数据对象格式如下:
commandLineArgs:[] 命令行参数 main方法的args参数
servletContextInitParams:[] servletcontext初始化参数
systemProperties:[java.io.tmpdir:/tmp,sun.jnu.encoding:utf8…] jvm参数 System.getProperties()
systemEnvironment:[PWD:/home/lewis,username:lewis…] 系统变量参数 System.getenv()
applicationConfig(classpath:/application.properties):[key:value…] application.properties配置参数
Environment实例有一属性是PropertySources,PropertySources也有一属性是List<PropertySource>,environment.getProperty(key)会遍历所有的PropertySource来查找key的value。
参考配置:
https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/pdf/spring-boot-reference.pdf参考文档中的Appendix A. Common application properties部分提供了sample配置。
如何使用application.properties文件来初始化子模块:
以logging为例,LoggingApplicationListener能够接受ApplicationEnvironmentPreparedEvent事件来初始化日志子系统。当env加载完配置信息后会发布ApplicationEnvironmentPreparedEvent事件,监听便会拿到相应的当前子模块所需的配置信息”logging.config”前辍来初始化日志模块。
手动找配置文件和对应的Properties类:
下载spring-boot源码,进入到spring-boot-project目录执行shell命令:find ./ -path “*src/main*” -name “*.java” |xargs grep -e “@ConfigurationProperties(\|@ConditionalOnProperty(” | sed -r ‘s/.*\///g’
profile:根据不同的变量值(spring.profiles.active=[dev|test|prod])使用不同的配置文件。spring.profiles.active=dev可以通过application.properties或java参数或jvm参数或系统环境参数传入,根据这个值来决定使用application-dev.properties这个配置文件。也可以定义不同环境的Propreties配置类,并在该类上使用@Profile(value = “prod|test|dev”)注解。
4. new ConfigurableApplicationContext(), 根据推断项目类型(REACTIVE,NONE,SERVLET)来创建相应的对象,
SERVLET:AnnotationConfigServletWebServerApplicationContext
NONE:AnnotationConfigApplicationContext
REACTIVE:AnnotationConfigReactiveWebServerApplicationContext
这些ApplicationContext有四个重要成员变量:
DefaultListableBeanFactory beanFactory;
ConfigurableEnvironment environment;
AnnotatedBeanDefinitionReader reader;
ClassPathBeanDefinitionScanner scanner;
在初始化reader时会调用AnnotationConfigUtils.registerAnnotationConfigProcessors(applicationContext); 该方法会硬编码注册以下PostProcessor的BeanDefinition到容器: context{reader:AnnotatedBeanDefinitionReader{
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.beanDefinitionMap = {
internalConfigurationAnnotationProcessor:ConfigurationClassPostProcessor
internalAutowiredAnnotationProcessor:AutowiredAnnotationBeanPostProcessor
internalRequiredAnnotationProcessor:RequiredAnnotationBeanPostProcessor
internalCommonAnnotationProcessor:CommonAnnotationBeanPostProcessor
internalEventListenerProcessor:EventListenerMethodProcessor
internalEventListenerFactory:DefaultEventListenerFactory
}
},
scanner:ClassPathBeanDefinitionScanner}
5. applyInitializers(context); DelegatingApplicationContextInitializer/ContextIdApplicationContextInitializer/ConfigurationWarningsApplicationContextInitializer/ServerPortInfoApplicationContextInitializer/SharedMetadataReaderFactoryContextInitializer/ConditionEvaluationReportLoggingListener
DelegatingApplicationContextInitializer是给用户作扩展使用:可以在property里定义key为context.initializer.classes的initializer。
执行所有的SpringApplication.initializers.stream(init->init.initialize(context)); 其中ConfigurationWarningsApplicationContextInitializer会添加ConfigurationWarningsPostProcessor到applicationContext.beanFactoryPostProcessors,SharedMetadataReaderFactoryContextInitializer会添加CachingMetadataReaderFactoryPostProcessor到applicationContext.beanFactoryPostProcessors。
ContextIdApplicationContextInitializer:
往DefaultListableBeanFactory extend DefaultSingletonBeanRegistry里注册bean:
beanFactory.singletonObjects.put(“ContextIdApplicationContextInitializer$ContextId”, new ContextIdApplicationContextInitializer$ContextId);
beanFactory.registeredSingletons.add(“ContextIdApplicationContextInitializer$ContextId”);
ConfigurationWarningsApplicationContextInitializer:
context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));
SharedMetadataReaderFactoryContextInitializer:
applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor());
ConditionEvaluationReportLoggingListener:
applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
context.getBeanFactory().registerSingleton(“springApplicationArguments”,applicationArguments);
6. load primarySources:
6.1创建BeanDefinitionLoader根据context和primarySources,并会创建AnnotatedBeanDefinitionReader的annotatedReader成员变量和XmlBeanDefinitionReader的xmlReader成员变量,以及ClassPathBeanDefinitionScanner的scanner的成员变量。
BeanDefinitionLoader{annotatedReader:AnnotatedBeanDefinitionReader,xmlReader:XmlBeanDefinitionReader,scanner:ClassPathBeanDefinitionScanner,scanner.addExcludeFilter:ClassExcludeFilter}
6.2通过annotatedReader.register(primarySources)注册BeanDefinition。
创建AnnotatedGenericBeanDefinition abd, AnnotatedGenericBeanDefinition{metadata:StandardAnnotationMetadata{annotations:List<java.lang.annotation.Annotation>}, scope:[singleton|prototype]}
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd),将通用的注解@Lazy,@Primary,@DependsOn,@Role,@Description的value信息设置到abd的相应成员变量上。
BeanDefinitionReaderUtils.registerBeanDefinition(primarySoruce,register) 注册primarySoruce的BeanDefinition到register。
7. 广播ApplicationPreparedEvent事件。ConfigFileApplicationListener/LoggingApplicationListener/BackgroundPreinitializer/DelegatingApplicationListener
其中ConfigFileApplicationListener的onApplicationPreparedEvent方法中会添加PropertySourceOrderingPostProcessor到applicationContext.beanFactoryPostProcessors。
context.addBeanFactoryPostProcessor(new PropertySourceOrderingPostProcessor(context));
8. applicationContext.refrsh():
8.1设置ConfigurableListableBeanFactory的初始属性:
beanFactory.addBeanPostProcessor(ApplicationContextAwareProcessor,ApplicationListenerDetector)
ConfigurableListableBeanFactory.singletonObjects里注册实例有:[autoConfigurationReport, org.springframework.boot.context.ContextIdApplicationContextInitializer$ContextId, springApplicationArguments, springBootBanner, springBootLoggingSystem, environment, systemProperties, systemEnvironment]。
8.2 applicationContext.invokeBeanFactoryPostProcessors([ConfigurationWarningsPostProcessor,CachingMetadataReaderFactoryPostProcessor,PropertySourceOrderingPostProcessor,ConfigurationClassPostProcessor])
这里的BeanFactoryPostProcessors分为两种:BeanDefinitionRegistryPostProcessor和普通的BeanFactoryPostProcessor。
最关键的是执行ConfigurationClassPostProcessor这个BeanFactoryPostProcessor,它的processConfigBeanDefinitions方法会遍历ConfigurableListableBeanFactory中已经注册的BeanDefinition,找出所有@Configuration的类。
PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(internalConfigurationAnnotationProcessor, context);
搜索已注册的BeanDefinition中含有Configuration注解的Beans[只有primarySoruces],然后ConfigurationClassParser去解析
ConfigurationClassParser.doProcessConfigurationClass()递归调用// Parse each @Configuration class
parser.processMemberClasses(configClass, sourceClass);// Recursively process any member (nested) classes first
parser.processPropertySource(propertySource);//Process any @PropertySource annotations
ComponentScanAnnotationParser.parse()// Process any @ComponentScan annotations
定义ClassPathBeanDefinitionScanner,如果@ComponentScan没有定义basePackage,它从primarySoruces的package位置开始,搜索所有的Component
parser.processImports()// Process any @Import annotations
ConfigurationClass.addImportedResource(resolvedResource, readerClass)// Process any @ImportResource annotations
ConfigurationClass.addBeanMethod()// Process individual @Bean methods
parser.processDeferredImportSelectors();//加载所有的autoconfig class,并且只加载autoconfig里没有Condition注解的类。
AutoConfigurationImportSelector.selectImports()//搜索所有spring.factories中的EnableAutoConfiguration。并通过primarySoruces中的
//@EnableAutoConfiguration中的attribute进行过滤。
parser.processImports(); //将所有的autoconfig class中有Import注解的类进行加载。
ConditionEvaluator.shouldSkip()//会作Condition条件过滤。
internalConfigurationAnnotationProcessor.reader.loadBeanDefinitions(configClasses); //将解析得到的parser.configClasses的所有BeanDefinition注册到容器。
loadBeanDefinitionsForBeanMethod(beanMethod);//注册@Bean注解的method到BeanDefinition容器。
目前只有primarySoruces的类,ConfigurationClassParser.doProcessConfigurationClass(primarySoruces), 该方法会解析该config类的@PropertySource,@ComponentScan,@Import,@ImportResource,@Bean注解,该方法doProcessConfigurationClass会被递归调用,解析满足条件的所有注解类。
@ComponentScan注解会ComponentScanAnnotationParser.parse(){ClassPathBeanDefinitionScanner.doScan()},并将所有的@Component注册成为BeanDefinition。
将所有@Component的类注册BeanDefinition到容器里。它使用ClassPathScanningCandidateComponentProvider判断是否满足规则:
ClassPathScanningCandidateComponentProvider{
private final List<TypeFilter> includeFilters = new LinkedList<>();
private final List<TypeFilter> excludeFilters = new LinkedList<>();
}
TypeFilter是一系列的策略实现类,用来
AutoConfigurationExcludeFilter.isConfiguration(MetadataReader metadataReader) {
return metadataReader.getAnnotationMetadata()
.isAnnotated(Configuration.class.getName());
}
AnnotationTypeFilter{
Class<? extends Annotation> annotationType; 这个在ClassPathScanningCandidateComponentProvider.registerDefaultFilters方法中会赋值(org.springframework.stereotype.Component.class)
protected boolean matchSelf(MetadataReader metadataReader) {
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
return metadata.hasAnnotation(this.annotationType.getName()) ||
(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}
}
其中ConfigurationClassPostProcessor.postProcessBeanFactory会将所有的@Configuration注解的类enchance成cglib代理的类,这些config类不仅是用户定义的,包括spring框架里的config类,只是将类加载enhance,并没有实例化。
class ConfigurationClassEnhancer {
// The callbacks to use. Note that these callbacks must be stateless.
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
}
@Import注解会将value的类注册成为BeanDefinition。
ConfigurationClassParser.processDeferredImportSelectors()
AutoConfigurationImportSelector.selectImports()这个方法会调用AutoConfigurationImportSelector.getCandidateConfigurations会搜索当前项目下所有的 “META-INF/spring.factories”文件里的EnableAutoConfiguration的实现类。
解析所有这些@EnableAutoConfiguration的类,看是否在当前项目下引用,如果该类存在就将其注册成为BeanDefinition。
8.3 applicationContext.registerBeanPostProcessors() //Register BeanPostProcessor that intercept bean creation.
8.4 context.finishBeanFactoryInitialization();// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons()
beanFactory.getBean(beanFactory.beanDefinitionNames[i]); //创建实例,并添加到factory.singletonObjects中。
工具方法:
AnnotationUtils.findAnnotation(clazz, Component.class)//判断clazz上有没有@Component的注解。
XML配置:
1)<context:annotationconfig/> 将隐式地向 Spring 容器注册AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及equiredAnnotationBeanPostProcessor 这 4 个 BeanPostProcessor。
2)<context:component-scan/>提供了自动扫描注解类并将其注册到容器,它还包含了autowire自动装配功能。