《springboot-自动配置-启动》
springboot 我想大家应该都不陌生, 现在大部分公司几乎都来用它开发,因为它简单明了,并且给我们程序员减少了很多的开发外不必要的工作量,那么我们今天就来研究一下,首先大家是否清楚springboot的优点是什么?或者用一个词来形容它,“脚手架”,为什么叫它脚手架呢?大家来想,平时大家应该会看到建筑工人盖楼房的时候,会在楼房的周围包裹一圈架子,可以让工人大哥们可以站在上面自由的走来走去盖房子,不知道这个比喻精确吗,但个人认为是这样的,springboot就相当于这一圈的脚手架,很方便让程序工人很快的写代码(盖房子),因为它把spring以及第三方比方redis.、tomcat、mybatis等等一系列的组件都已经集成进来,并且不用编写大量的xml,之前我们用spring,肯定需要写spring.xml,用mybait的时候需要写mybait.xml,现在不需要了,这就是它的优点。但是我们知道了优点,我们既然要用它,不能只知道应用就可以了,我们要知道为什么它有这样的优点;好, 那作为程序员就少说一些废话,直接进入主题吧;(其实springboot真的没有多少内容)
本人分别通过它的自动配置以及启动两大方面来介绍这神奇又伟大的哥们儿;(图加文字描述)
自动配置:这里主要讲的就是springboot 通过@import注解导入了AutoConfigurationImportSelector这个类;AutoConfigurationImportSelector实现了DeferredImportSelector接口重写了getImportGroup()这个方法返回AutoConfigurationGroup类(自动配置分组),又因为这个类AutoConfigurationGroup实现了DeferredImportSelector.Group,所以重写了process()方法,然后在这个方法里扫描了所有jar包下的META-INF/spring.factories,然后把有关EnableAutoConfiguration类作为key所有配置类找了出来,再调用selectImports()方法进行排序(记住这个排序只是再当前组里有效)
注意: 实现了DeferredImportSelector这个接口,如果不重写getImportGroup()这个方法,就会执行AutoConfigurationImportSelector类里面重写selectImports()这个方法,如果重写了getImportGroup()方法,就会执行getImportGroup()方法里返回的AutoConfigurationGroup这个类里的的process()和selectImports()方法,然后上面说的排序只是再当前组里有效,这里的当前组就是AutoConfigurationGroup;

 
 
 
 
 
 
 
 
 

我们说了,它只加载了有关EnableAutoConfiguration类的配置类,然后再哪里体现的呢, 看图
 
 
上面讲了springboot自动配置, 那下面我们来讲启动,说起启动我想大家用过springboot应该都会很清楚可以通过jar启动,java -jar 项目启动springboot项目因为它有内嵌的tomcat, 或者是打成war包 扔进外置tomcat中进行运行, 那么问题来了?
1. 本身就是jar包, 那么jar包里面jar是如何运行的?java没有任何手段实现了jar包里还可以运行jar, 也就是我们所说的 fat.jar (胖子jar)
2. 内嵌tomcat,是如何内嵌的? 如果关联起来的?
3.外嵌tomcat,是如果外嵌的? 如果关联起来的?
4. 知道运行web项目, 我们肯定不光是写一些spring或者mybatis相关的xml, 最重要的一个xml,就是web.xml 我想大家应该都不陌生,那么web.xml里面配置了什么东东呢,就是加载spring容器以及 DispatcherServlet(前端控制器),
1、那我们是不是弄明白springBoot是如何与spring结合;
2、内置tomcat如何创建的
3、如何加载DispatcherServlet;
4、外置tomcat在什么地方进行结合进来的,或者说外置tomcat, 为什么执行 sh./statrup.sh启动的时候怎么可以运行main方法的;
首先这里我介绍一个springboot启动jar的知识点,首先我们肯定要清楚是如果是启动jar包,肯定pom.xml里面打包类型为jar包
<packaging>jar</packaging>

引入这个组件才可以打成jar包
然后运行打包就会在项目的jar包下的META-INF下生成一个MANIFEST.MF文件,这个文件里内容下面图片

然后其实就是当咱们运行java -jar的时候, 就在这个文件里找到Main-Class对应的springboot自定义的类加载器JarLauncher,然后这个加载器就会去加载 jar包下的BOOT-INF里的lib下的所有jar包和classes类里面的所有类

 
弄明白这几个问题,我们也就算彻底搞明白springboot启动了,好了不多说,来吧;
加载spring容器

DispatcherServlet(前端控制器)

1、那我们是不是弄明白springBoot是如何与spring结合?
首先我们执行DemoApplication的run方法

看到执行run方法,执行两个步骤,一个new了SpringApplication对象,然后又执行了new完后的run方法

那么我就可以直接看run方法里面,最终要的一个方法啊refreshContext()这个方法里面你一直点击下去你就发现,跳转到了spring最重要的一个方法refresh()方法里面吗

 
我想大家看到spring源码跳到这个方法里,应该就特别清楚了吧,就是这样和spring结合起来的 ,这里我就不多说了,如果不清楚去看我写的spring
 
2、内置tomcat如何创建的
首先大家必须清楚spring源码, 其实spring源码在refresh()方法里面有一个onRefresh()方法,这个方法在spring里是一个空的, 就是为了解耦,如果我们想用,就可以重写这个方法,springboot创建内置tomcat其实就是重写了这个方法,然后new tomcat(); 创建了一个这样类ServletWebServerApplicationContext重写了onRefresh()方法

然后重要的这个ServletContext servletContext = getServletContext(); 这个方法,如果是内置tomcat,这个方法就是返回null,如果是外置tomcat,这个方法就会查询出有关外置tomcat的信息, 其实这里也就是解释了外置tomcat是如何关联进来的,我们先来讲内置tomcat,如果是null, 就会执行if为null的代码块,然后重要看这个方法ServletWebServerFactory factory = getWebServerFactory();

进入这个方法里String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class); 然后我们看ServletWebServerFactory.class这个类,这个类是一个接口, 里面有一个方法WebServer getWebServer(ServletContextInitializer... initializers);, 然后接口,肯定是有实现类来重写这个方法,所以我们就找到了

 
TomcatServletWebServerFactory这个实现类实现了ServletWebServerFactory重写了getWebServer()方法

然后大家看这个方法,一目了然,其实就是创建了tomcat,这就是内置tomcat;

然后这里顺便把 3、如何加载DispatcherServlet; 其实就是回到上面这个方法this.webServer = factory.getWebServer(getSelfInitializer()); getSelfInitializer()这个方法就是创建了DispatcherServlet,


然后大家肯定会想dispatcherServlet是如何注册进来的,其实DispatcherServletAutoConfiguration 自动配置类就把dispatcherServlet 作为bean创建了

3.外嵌tomcat,是如果外嵌的? 如果关联起来的?
刚才上面我们讲到了 ServletContext servletContext = getServletContext(); 这个方法如果返回不为null; 就会走if 不为null的代码块;

然后这里特殊讲一下用到了spI机制 spI 是什么 就是 service producer interface (提供服务接口), 它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类;
这里外置tomcat就是通过这种方式进行的解耦,那么如果做呢,
首先把pom.xml里的spring-boot-starter-tomcat 排除掉;

然后我们找到spring-web.jar下的META-INF/services/ 下面的文件,就可以看到这个类org.springframework.web.SpringServletContainerInitializer


其实外置tomcat启动时候,就会加载这个类,执行这个类的onStartup() 方法

 

上面这两个类, 第一个就不用说了 这个就是DispatcherServlet , 第二个springbootServletInitializer类就是让外置tomcat去启动springboot的main方法;
 
 
这里run方法就是找到我们springboot项目里Application类执行main方法,然后记得还要继承SpringBootServletInitializer类重写下面这个方法configure,
return builder.source(Application.class)


好了这里就大概把springboot的基本知识点讲完了, 本人也就是4年的程序员,不是科班出生,但是我会努力的,写的也不是很清楚,其实主要是让我自己复习的时候方便看,如果大家觉的不好,就多多指点,谢谢大家!