Spring Boot 启动源码解析二
Posted 踩踩踩从踩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot 启动源码解析二相关的知识,希望对你有一定的参考价值。
Spring Boot 使用及启动源码解析一_踩踩踩从踩的博客-CSDN博客
前言
之前的文章主要介绍的是spring boot 也就是 spring boot application 这个启动类, 有兴趣的可以看看之前的,这篇文章继续 研究 spring boot 自动装配,如何利用自动装配 将所有的对象 注入的容器中,方便我们使用,对于我们开发新组件,很有用,有时候 自己的开发时,也许你应该会想,我都没加什么@component 注解,当然更没有加 @configuration + @bean 的方式注入,但为什么我们就能注入进来拉,像mysql 等 中间组件,其实也不是难事,看一下源码 就明白了。
自动装配注解
我们使用的时候 有 SpringBootApplication 注解 继承自 EnableAutoConfiguration 还有 componentScan 等注解
后面 进去 很简单的 autoConfigurationPackage 有 自动配置 配置
这里在引入到 register .class 类 注册器
在selector 选择器 才是最重要 会 一堆stater 在这里选择 到底要加载 那个 类进行加载的。
引入那个类进行加载
找到对应的 autoconfiguration 类,我们选择 自动装配的类
说一下怎么加载到 selecter 并加载 对应的autoconfigruation 去怎么加载 到 配置文件反射到的对象。
读取spring .factory 文件 并且扫描 并配置 具体对象的注入。 具体可以看看这篇文章。
Spring boot基本使用及 stater机制原理_踩踩踩从踩的博客-CSDN博客_spring stater
springboot中监听器
spring boot 的源码中,会发现内部大量的监听器,这些监听器大概有两类。
# Run Listeners
#事件发布运行监听器,是springboot中配置的唯一一个应用运行监听器,作用是通过一个多路广播器,将springboot运行状态的变化,构建成事件,并广播给各个监听器
org.springframework.boot.SpringApplicationRunListener=\\
org.springframework.boot.context.event.EventPublishingRunListener
# Application Listeners
org.springframework.context.ApplicationListener=\\
org.springframework.boot.ClearCachesApplicationListener(),\\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\\
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.context.logging.ClasspathLoggingApplicationListener,\\
org.springframework.boot.context.logging.LoggingApplicationListener,\\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
# Application Listeners
org.springframework.context.ApplicationListener=\\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
当程序开始运行的时候,可以看到启动了一个运行的监听器,并且创建了一个springApplicationRunListeners 对象,该对象是一个封装工具类,封装了所有启动监听器。
整体的实例化
在 EventPublishingRunListener.java
这在springboot 经常要监听到的,整体监听的数据进行处理。
在监听器实例化之前,检查是否符合固定的类型
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType)
//判断监听器是否是GenericApplicationListener子类,如不是返回一个GenericApplicationListenerAdapter
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
此时可以看到GenericApplicationListener类,该类是spring提供的用于重写匹配监听器事件的接口,如果需要判断的监听器是GenericApplicationListener的子类,说明类型匹配方法已被重现,就调用子类的匹配方法,如果不是,提供一个默认的适配器来匹配GenericApplicationListenerAdapter
public boolean supportsEventType(ResolvableType eventType)
if (this.delegate instanceof SmartApplicationListener)
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
else
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
可以看到该类最终调用的是declaredEventType.isAssignableFrom(eventType)
方法,也就是说,如果我们没有重写监听器匹配方法,那么发布的事件 event 会被监听 event以及监听event的父类的监听器监听到。
Springboot内嵌tomcat
在使用springboot搭建一个web应用程序的时候,我们发现不需要自己搭建一个tomcat服务器,只需要引入spring-boot-starter-web,在应用启动时会自动启动嵌入式的tomcat作为服务器,下面来分析下源码的分析流程:
之前我们已经讲过了自动装配的原理,其实tomcat的实现机制也是从自动装配开始的。
ServletWebServerFactoryAutoConfiguration类
从这个类上可以看到,当前配置类主要导入了BeanPostProcessorRegister,该类实现了ImportBeanDefinitionRegister接口,可以用来注册额外的BeanDefinition,同时,该类还导入了EmbeddedTomcat,EmbeddedJetty,EmbeddedUndertow三个类,可以根据用户的需求去选择使用哪一个web服务器,默认情况下使用的是tomcat
当自动装配功能完成之后会接着执行onRefresh的方法(ServletWebServerApplicationContext)
创建web服务,默认获取的是tomcat的web容器(ServletWebServerApplicationContext)
ServletWebServerApplicationContext
DefaultListableBeanFactory
/*
第一个参数type表示要查找的类型
第二个参数表示是否考虑非单例bean
第三个参数表示是否允许提早初始化
*/
@Override
public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit)
//配置还未被冻结或者类型为null或者不允许早期初始化
if (!isConfigurationFrozen() || type == null || !allowEagerInit)
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
//此处注意isConfigurationFrozen为false的时候表示beanDefinition可能还会发生更改和添加,所以不能进行缓存,如果允许非单例bean,那么从保存所有bean的集合中获取,否则从单例bean中获取
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null)
return resolvedBeanNames;
//如果缓存中没有获取到,那么只能重新获取,获取到之后就存入缓存
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader()))
cache.put(type, resolvedBeanNames);
return resolvedBeanNames;
默认启动的方法。
完成内嵌tomcat的api调用(TomcatServletWebServerFactory)
获取tomcat服务(TomcatServletWebServerFactory)
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat)
return new TomcatWebServer(tomcat, getPort() >= 0);
public TomcatWebServer(Tomcat tomcat, boolean autoStart)
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
//初始化
initialize();
完成tomcat的初始化
除了refresh方法之外,在finishRefresh()方法中也对tomcat做了相关的处理(ServletWebServerApplicationContext)
其实最后应用上下文关闭时会调用tomcat的关闭
在refreshContext中注册一个关闭的钩子函数,而钩子函数可以完成关闭的功能
ServletWebServerApplicationContext
@Override
protected void onClose()
super.onClose();
stopAndReleaseWebServer();
整个tomcat整和到springboot里面了 ,具体在源码中看一遍你就明白了,主要是理解原理,去推,可以自己看时,跟着走走,比较晕,但是 走一遍,也不是特别那个。
以上是关于Spring Boot 启动源码解析二的主要内容,如果未能解决你的问题,请参考以下文章