虽然本文档基于SpringBoot1.4.0.release版本,然后SpringBoot整体的启动流程基本一致。废话不多说,现在就开发接解析吧:
一、启动原理
• SpringApplication.run
(主程序类)
– new SpringApplication
(主程序类)
• 判断是否web应用
• 加载并保存所有ApplicationContextInitializer(META-INF/spring.factories)
,
• 加载并保存所有ApplicationListener
• 获取到主程序类
– run()
• 回调所有的SpringApplicationRunListener(META-INF/spring.factories)
的starting
• 获取ApplicationArguments
• 准备环境&回调所有监听器(SpringApplicationRunListener
)的environmentPrepared
• 打印banner信息
• 创建IOC容器对象
– AnnotationConfigEmbeddedWebApplicationContext
(web环境容器)
– AnnotationConfigApplicationContext
(普通环境容器)
• 准备环境
– 执行**ApplicationContextInitializer
**. initialize()
– 监听器**SpringApplicationRunListener
**回调contextPrepared
– 加载主配置类定义信息
– 监听器**SpringApplicationRunListener
**回调contextLoaded
• 刷新启动IOC容器;
– 扫描加载所有容器中的组件
– 包括从META-INF/spring.factories
中获取的所有**EnableAutoConfiguration
**组件
• 回调容器中所有的ApplicationRunner
、CommandLineRunner
的run方法
• 监听器SpringApplicationRunListener
回调finished
二、自动配置
• Spring Boot启动扫描所有jar包的META-INF/spring.factories
中配置的
EnableAutoConfiguration
组件
• spring-boot-autoconfigure.jar\META-INF\spring.factories
有启动时需要加载的
EnableAutoConfiguration
组件配置
• 配置文件中使用debug=true可以观看到当前启用的自动配置的信息
• 自动配置会为容器中添加大量组件
• Spring Boot在做任何功能都需要从容器中获取这个功能的组件
• Spring Boot 总是遵循一个标准;容器中有我们自己配置的组件就用我们配置的,没有就用自动配
置默认注册进来的组件;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
一.SpringBoot启动原理
(1).初始化(创建SpringApplication对象)
1.保存主配置类
2.判断当前是否一个web应用的环境
3.从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来
4.从类路径下找到ETA-INF/spring.factories配置的所有ApplicationListener
5.从多个配置类中找到有main方法的主配置类
开始分析
1.保存主配置类
public SpringApplication(Object... sources) {
initialize(sources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
//1.保存主配置类
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//2.判断当前是否是一个web应用
this.webEnvironment = deduceWebEnvironment();
//3.从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;
//然后保存起来
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//4.从类路径下找到ETA-INF/spring.factories配置的所有ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//5.从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
2.判断当前是否是一个web应用
private boolean deduceWebEnvironment() {
for (String className : WEB_ENVIRONMENT_CLASSES) {
// 判断Servlet和ConfigurableWebApplicationContext 是否可以被类加载器加载到
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" };
3.设置ApplicationContextInitializers
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes,
Object... args) {
//1.获取当前线程的类加载器
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
//2.通过class和类加载器获取META-INF/spring.factories配置的所有class的名字
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//3.实例化全部属于class的类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
//4.排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
//1.获取类目录下所有META-INF/spring.factories的配置URL
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
// 获取对应URL资源的配置文件
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
// 获取配置中的factoryClassName的类名
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(
StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
} catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
"] factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<T>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
// 注意此时调用的是无参
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
} catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
this.initializers.addAll(initializers);
}
4.设置ApplicationListeners
private Class<?> deduceMainApplicationClass() {
try {
//获取当前栈信息
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
//获取主类信息
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
} catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
(2).运行(运行run方法)
1.获取并启动监听器
2.构造容器环境
3.打印banner
4.创建容器
5.准备容器
6.刷新容器
7.刷新容器后的扩展接口
8.回调finished()方法
public ConfigurableApplicationContext run(String... args) {
//时间监控
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
//第一步:获取并启动监听器
//获取SpringApplicationRunListeners;从类路径下META-INF/spring.factories
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的获取SpringApplicationRunListener.starting()方法
listeners.started();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//第二步:构造容器环境
//创建环境完成后回调SpringApplicationRunListener.environmentPrepared()表示环境准备完成
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//打印banner
Banner printedBanner = printBanner(environment);
//第三步:创建容器
//创建ApplicationContext;决定创建web的ioc还是普通的ioc
context = createApplicationContext();
//第四步:准备容器
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
//第五步:刷新容器
//刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版
//扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
refreshContext(context);
//第六步:刷新容器后的扩展接口
//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
//ApplicationRunner先回调,CommandLineRunner再回调??这两个是干嘛的?
afterRefresh(context, applicationArguments);
//所有的SpringApplicationRunListener回调finished()方法
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//整个SpringBoot应用启动完成以后返回启动的ioc容器;
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, ex);
throw new IllegalStateException(ex);
}
}
1.获取并启动监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
// 构造方法的入参
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 创建SpringApplicationRunListeners
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
...
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// 向initialMulticaster中添加下上文监听器
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
...
}
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType:resolveDefaultEventType(event));
//获取属于启动事件的监听器且调用invokeListener()方法
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
} else {
invokeListener(listener, event);
}
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
// 会执行listener.onApplicationEvent()方法
listener.onApplicationEvent(event);
} catch (Throwable err) {
errorHandler.handleError(err);
}
} else {
try {
listener.onApplicationEvent(event);
} catch (ClassCastException ex) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
LogFactory.getLog(getClass()).debug("Non-matching event type for listener: " + listener, ex);
}
}
}
2.构造容器环境
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// 获取ConfigurableEnvironment(不存在则创建一个)
ConfigurableEnvironment environment = getOrCreateEnvironment();
/**
* 配置环境propertySource和profiles
* configurePropertySources(environment, args);
* configureProfiles(environment, args);
*/
configureEnvironment(environment, applicationArguments.getSourceArgs());
//回调环境准备完毕时间(第二次回调listener的方法)
listeners.environmentPrepared(environment);
//判断是不是web环境实是则重新构造一个web环境
if (isWebEnvironment(environment) && !this.webEnvironment) {
environment = convertToStandardEnvironment(environment);
}
return environment;
}
3.打印banner
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
if (printBannerViaDeprecatedMethod(environment)) {
return null;
}
ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
: new DefaultResourceLoader(getClassLoader());
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
resourceLoader, this.banner);
//bannerMode是Banner.Mode.CONSOLE;
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
//进入打印方法
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
//获取banner
Banner banner = getBanner(environment, this.fallbackBanner);
//打印
banner.printBanner(environment, sourceClass, out);
//返回
return new PrintedBanner(banner, sourceClass);
}
private static final Banner DEFAULT_BANNER = new SpringBootBanner();
private static final String[] BANNER = { "",
" . ____ _ __ _ _",
" /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\",
"( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
" \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )",
" ' |____| .__|_| |_|_| |_\\__, | / / / /",
" =========|_|==============|___/=/_/_/_/" };
private static final String SPRING_BOOT = " :: Spring Boot :: ";
private Banner getBanner(Environment environment, Banner definedBanner) {
Banners banners = new Banners();
banners.addIfNotNull(getImageBanner(environment));
banners.addIfNotNull(getTextBanner(environment));
if (banners.hasAtLeastOneBanner()) {
return banners;
}
if (this.fallbackBanner != null) {
return this.fallbackBanner;
}
return DEFAULT_BANNER;
}
打印banner
public void printBanner(Environment environment, Class<?> sourceClass,
PrintStream printStream) {
//打印banner图
for (String line : BANNER) {
printStream.println(line);
}
//获取SpringApplication对应坐在包的版本
String version = SpringBootVersion.getVersion();
//构造对应的版本号
version = (version == null ? "" : " (v" + version + ")");
String padding = "";
while (padding.length() < STRAP_LINE_SIZE
- (version.length() + SPRING_BOOT.length())) {
padding += " ";
}
//打印版本
printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT,
AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version));
//打印空行
printStream.println();
}
4.创建容器
// 默认的容器
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
// WEB容器
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
//判断创建WEB容器还是默认的容器
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
} catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
5.准备容器
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments,
Banner printedBanner) {
//1.准备上下文环境;将environment保存到ioc中
context.setEnvironment(environment);
//2.postProcessApplicationContext() 用来支持自定义扩展的(默认什么都不执行)
postProcessApplicationContext(context);
//3.applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法;
applyInitializers(context);
//4.回调所有的SpringApplicationRunListener的contextPrepared();
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);
}
//5.调用registerSingleton()方法注册命令参数和Banner
context.getBeanFactory().registerSingleton("springApplicationArguments",applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
//6.load() 会将启动类加载spring容器beanDefinitionMap中(注意这边可以多个)
load(context, sources.toArray(new Object[sources.size()]));
//7.prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
listeners.contextLoaded(context);
}
执行postProcessApplicationContext
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
// beanNameGenerator为空
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
// resourceLoader为空
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context)
.setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context)
.setClassLoader(this.resourceLoader.getClassLoader());
}
}
}
load()
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
//通过来源类+容器 初始化一个BeanDefinitionLoader
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
//加载来源类
loader.load();
}
加载来源类
private int load(Class<?> source) {
//不进去
if (isGroovyPresent()) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
GroovyBeanDefinitionSource loader =
BeanUtils.instantiateClass(source,GroovyBeanDefinitionSource.class);
load(loader);
}
}
//是否有Component注解
if (isComponent(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}
6.刷新容器
该步骤是和Spring启动流程有关清查Spring启动原理,这里不做过多解释
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
/**
* 刷新上下文环境
* 初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验
* 如环境变量中必须设置某个值才能运行,否则不能运行,这个时候可以在这里加这个校验,
* 重写initPropertySources方法就好了
*/
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
/**
* 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
* 设置SPEL表达式#{key}的解析器
* 设置资源编辑注册器,如PerpertyEditorSupper的支持
* 添加ApplicationContextAwareProcessor处理器
* 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
* 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory)
* 则会将beanFactory的实例注入进去
*/
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
/**
* 激活各种BeanFactory处理器包括:
* 1.BeanDefinitionRegistryBeanFactoryPostProcessor
* 2.普通的BeanFactoryPostProcessor执行对应的postProcessBeanDefinitionRegistry方法
* 3.postProcessBeanFactory方法
*/
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
/**
* 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor 不是BeanFactoryPostProcessor
* 注意两者的区别 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
*/
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化上下文中的资源文件,如国际化文件的处理等
initMessageSource();
// Initialize event multicaster for this context.
// 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 给子类扩展初始化其他Bean
onRefresh();
// Check for listener beans and register them.
// 在所有bean中查找listener bean,然后注册到广播器中
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
/**
* 设置转换器
* 注册一个默认的属性值解析器
* 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
* 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
*/
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
/**
* 初始化生命周期处理器DefaultLifecycleProcessor,DefaultLifecycleProcessor
* 含有start方法和stop方法,spring启动的时候调用start方法开始生命周期,
* spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,启动有一直运行
* 启动所有实现了Lifecycle接口的类
* 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理
* 即对那种在spring启动后需要处理的一些类,这些类实现了
* ApplicationListener<ContextRefreshedEvent> ,
* 这里就是要触发这些类的执行(执行onApplicationEvent方法)
* spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、
* ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
* 完成初始化
* 通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
*/
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
7.刷新容器后的扩展接口
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
}
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
//默认两个都没有
for (Object runner : new LinkedHashSet<Object>(runners)) {
//ApplicationRunner先回调,CommandLineRunner再回调
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
8.回调finished()方法
略
二.事件监听机制
SpringBoot
事件监听分为两种运行时监听器,上下文监听器
SpringBoot
整体框架就是通过该监听器org.springframework.boot.SpringApplicationRunListeners
,来触发上下文监听器。通过上下文监听器来完成整体逻辑,比如加载配置文件,加载配置类,初始化日志环境等。
1) 运行时监听器
SpringApplicationRunListener
# spring-boot Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
2) 上下文监听器
ApplicationListener
# spring-boot Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener
# spring-boot-autoconfigure Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
DelegatingApplicationContextInitializer 啥也不做
ContextIdApplicationContextInitializer 设置容器的ID为"应用名字:profile.active"
ConfigurationWarningsApplicationContextInitializer
初始化器 | 使用环境属性context.initializer.classes 指定的初始化器(initializers )进行初始化工作,如果没有指定则什么都不做 |
---|---|
DelegatingApplicationContextInitializer | 使用环境属性context.initializer.classes 指定的初始化器(initializers )进行初始化工作,如果没有指定则什么都不做 |
ContextIdApplicationContextInitializer | 设置Spring应用上下文的ID,会参照环境属性: |
spring.application.name | |
spring.application.index | |
spring.profiles.active | |
如果这些属性都没有,ID使用"application"。 | |
ConfigurationWarningsApplicationContextInitializer | 对于一般配置错误在日志中作出警告 |
ServerPortInfoApplicationContextInitializer | 将内置servlet容器实际使用的监听端口写入到Environment环境属性中。这样属性"local.server.port"就可以直接通过@Value注入到测试中,或者通过环境属性Environment获取。 |
SharedMetadataReaderFactoryContextInitializer | 创建一个SpringBoot和ConfigurationClassPostProcessor 共用的CachingMetadataReaderFactory 对象,实现类使用ConcurrentReferenceCachingMetadataReaderFactory |
AutoConfigurationReportLoggingInitializer | 写入日志。除非出现问题,否则会在级别记录报告,在这种情况下,它们是使用级别的。ConditionEvaluationReportDEBUGINFO此初始化程序不应在多个应用程序上下文实例之间共享。 |
三.自动装配
EnableAutoConfiguration
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
EnableAutoConfigurationImportSelector
是@EnableAutoConfiguration
所@Import的DeferredImportSelector
实现类,由于DeferredImportSelector
作为ImportSelector
的子接口,所以组件自动装配逻辑在selectImports(AnnotationMetadata)
方法中实现:
@EnableAutoConfiguration
类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {}
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
@Override
public String[] selectImports(AnnotationMetadata metadata) {
if (!isEnabled(metadata)) { return NO_IMPORTS; }
try {
// 1.获取主类的EnableAutoConfiguration的属性
AnnotationAttributes attributes = getAttributes(metadata);
// 2.获取META-INF/spring.factories中的EnableAutoConfiguration的类名
List<String> configurations = getCandidateConfigurations(metadata,attributes);
// 3.去重
configurations = removeDuplicates(configurations);
// 4.获取exculusion的EnableAutoConfiguration类
Set<String> exclusions = getExclusions(metadata, attributes);
// 5.排除exculusion的EnableAutoConfiguration类
configurations.removeAll(exclusions);
// 6.排序
configurations = sort(configurations);
// 7.记录日志
recordWithConditionEvaluationReport(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
2.获取META-INF/spring.factories
中的EnableAutoConfiguration
的类名
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
// 获取META-INF/spring.factories目录下EnableAutoConfiguration的类
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
4.获取exculusion的EnableAutoConfiguration类
protected Set<String> getExclusions(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<String>();
// 获取exclude属性下类的列表
excluded.addAll(asList(attributes, "exclude"));
// 获取excludeName属性下类的列表
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
// 获取配置文件中的exclusions
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
private List<String> getExcludeAutoConfigurationsProperty() {
// 是否是配置化的环境
if (getEnvironment() instanceof ConfigurableEnvironment) {
Excludes excludes = new Excludes();
// 以spring.autoconfigure.作为前缀初始化RelaxedDataBinder
RelaxedDataBinder binder = new RelaxedDataBinder(excludes,"spring.autoconfigure.");
// 绑定excludes的excludes属性
binder.bind(new PropertySourcesPropertyValues(
((ConfigurableEnvironment) getEnvironment()).getPropertySources()));
return excludes.getExclude();
}
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(getEnvironment(),
"spring.autoconfigure.");
String[] exclude = resolver.getProperty("exclude", String[].class);
return (Arrays.asList(exclude == null ? new String[0] : exclude));
}
7.记录confgurations和exclusions
private void recordWithConditionEvaluationReport(List<String> configurations,
Collection<String> exclusions) throws IOException {
ConditionEvaluationReport report = ConditionEvaluationReport
.get(getBeanFactory());
// 记录confgurations
report.recordEvaluationCandidates(configurations);
// 记录exclusions
report.recordExclusions(exclusions);
}
四:ConditionOnXXX源码解析
@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)该注解表示,如果存在它修饰的类的bean,则不需要再创建这个bean;可以给该注解传入参数例如@ConditionOnMissingBean(name = "example"),这个表示如果name为“example”的bean存在,这该注解修饰的代码块不执行。
@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
@ConditionalOnNotWebApplication(不是web应用)
@ConditionalOnProperty(当有配置信息时生效)
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
// 1.获取当前类中的ConditionalOnProperty的属性
List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap(
metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName()));
// 2.比对ConditionalOnProperty的属性和配置中的值
List<ConditionOutcome> noMatchOutcomes = findNoMatchOutcomes(
allAnnotationAttributes, context.getEnvironment());
if (noMatchOutcomes.isEmpty()) {
return ConditionOutcome.match();
}
return ConditionOutcome.noMatch(getCompositeMessage(noMatchOutcomes));
}