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 启动源码解析二的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 使用及启动源码解析一

spring boot 源码解析 启动流程

Spring Boot 启动源码解析系列六:执行启动方法一

Spring Boot 启动源码解析二

Spring Boot 启动源码解析二

SpringBoot 源码解析 ----- Spring Boot的核心能力 - 自动配置源码解析