diff --git a/ReadMe.md b/ReadMe.md
index 979b79b..84572da 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -30,9 +30,11 @@
-## Java基础
+
+
+# Java基础
-### 基础知识
+## 基础知识
* [面向对象基础](docs/Java/basic/面向对象基础.md)
* [Java基本数据类型](docs/Java/basic/Java基本数据类型.md)
* [string和包装类](docs/Java/basic/string和包装类.md)
@@ -56,7 +58,7 @@
* [序列化和反序列化](docs/Java/basic/序列化和反序列化.md)
* [继承封装多态的实现原理](docs/Java/basic/继承封装多态的实现原理.md)
-### 容器
+## 集合类
* [Java集合类总结](docs/Java/collection/Java集合类总结.md)
* [Java集合详解:一文读懂ArrayList,Vector与Stack使用方法和实现原理](docs/Java/collection/Java集合详解:一文读懂ArrayList,Vector与Stack使用方法和实现原理.md)
@@ -68,7 +70,7 @@
* [Java集合详解:HashSet,TreeSet与LinkedHashSet](docs/Java/collection/Java集合详解:HashSet,TreeSet与LinkedHashSet.md)
* [Java集合详解:Java集合类细节精讲](docs/Java/collection/Java集合详解:Java集合类细节精讲.md)
-## JavaWeb
+# JavaWeb
* [走进JavaWeb技术世界:JavaWeb的由来和基础知识](docs/JavaWeb/走进JavaWeb技术世界:JavaWeb的由来和基础知识.md)
* [走进JavaWeb技术世界:JSP与Servlet的曾经与现在](docs/JavaWeb/走进JavaWeb技术世界:JSP与Servlet的曾经与现在.md)
@@ -87,9 +89,9 @@
* [走进JavaWeb技术世界:深入浅出Mybatis基本原理](docs/JavaWeb/走进JavaWeb技术世界:深入浅出Mybatis基本原理.md)
* [走进JavaWeb技术世界:极简配置的SpringBoot](docs/JavaWeb/走进JavaWeb技术世界:极简配置的SpringBoot.md)
-## Java进阶
+# Java进阶
-### 并发编程
+## 并发编程
* [Java并发指南:并发基础与Java多线程](docs/Java/concurrency/Java并发指南:并发基础与Java多线程.md)
* [Java并发指南:深入理解Java内存模型JMM](docs/Java/concurrency/Java并发指南:深入理解Java内存模型JMM.md)
@@ -108,7 +110,7 @@
* [Java并发指南:ForkJoin并发框架与工作窃取算法剖析](docs/Java/concurrency/Java并发指南:ForkJoin并发框架与工作窃取算法剖析.md)
* [Java并发编程学习总结](docs/Java/concurrency/Java并发编程学习总结.md)
-### JVM
+## JVM
* [JVM总结](docs/Java/JVM/JVM总结.md)
* [深入理解JVM虚拟机:JVM内存的结构与消失的永久代](docs/Java/JVM/深入理解JVM虚拟机:JVM内存的结构与消失的永久代.md)
@@ -126,7 +128,7 @@
* [深入理解JVM虚拟机:再谈四种引用及GC实践](docs/Java/JVM/深入理解JVM虚拟机:再谈四种引用及GC实践.md)
* [深入理解JVM虚拟机:GC调优思路与常用工具](docs/Java/JVM/深入理解JVM虚拟机:GC调优思路与常用工具.md)
-### Java网络编程
+## Java网络编程
* [Java网络编程和NIO详解:JAVA 中原生的 socket 通信机制](docs/Java/network/Java网络编程与NIO详解:JAVA中原生的socket通信机制.md)
* [Java网络编程与NIO详解:JAVA NIO 一步步构建IO多路复用的请求模型](docs/Java/network/Java网络编程与NIO详解:JavaNIO一步步构建IO多路复用的请求模型.md)
@@ -139,8 +141,10 @@
* [Java网络编程与NIO详解:基于NIO的网络编程框架Netty](docs/Java/network/Java网络编程与NIO详解:基于NIO的网络编程框架Netty.md)
* [Java网络编程与NIO详解:Java网络编程与NIO详解](docs/Java/network/Java网络编程与NIO详解:深度解读Tomcat中的NIO模型.md)
* [Java网络编程与NIO详解:Tomcat中的Connector源码分析(NIO)](docs/Java/network/Java网络编程与NIO详解:Tomcat中的Connector源码分析(NIO).md)
-## Spring全家桶
-### Spring
+
+# Spring全家桶
+
+## Spring
* [SpringAOP的概念与作用](docs/Spring全家桶/Spring/Spring常见注解.md)
* [SpringBean的定义与管理(核心)](docs/Spring全家桶/Spring/Spring常见注解.md)
@@ -157,9 +161,9 @@
* [Spring概述](docs/Spring全家桶/Spring/Spring常见注解.md)
* [第一个Spring应用](docs/Spring全家桶/Spring/Spring常见注解.md)
-### Spring源码分析
+## Spring源码分析
-* [Spring源码剖析:Spring概述](docs/Spring全家桶/Spring源码分析/Spring源码剖析:Spring概述.md)
+### 综合
* [Spring源码剖析:初探SpringIOC核心流程](docs/Spring全家桶/Spring源码分析/Spring源码剖析:初探SpringIOC核心流程.md)
* [Spring源码剖析:SpringIOC容器的加载过程 ](docs/Spring全家桶/Spring源码分析/Spring源码剖析:SpringIOC容器的加载过程.md)
* [Spring源码剖析:懒加载的单例Bean获取过程分析](docs/Spring全家桶/Spring源码分析/Spring源码剖析:懒加载的单例Bean获取过程分析.md)
@@ -169,7 +173,56 @@
* [Spring源码剖析:Spring事务概述](docs/Spring全家桶/Spring源码分析/Spring源码剖析:Spring事务概述.md)
* [Spring源码剖析:Spring事务源码剖析](docs/Spring全家桶/Spring源码分析/Spring源码剖析:Spring事务源码剖析.md)
-### SpringMVC
+### AOP
+* [AnnotationAwareAspectJAutoProxyCreator 分析(上)](docs/Spring全家桶/Spring源码分析/SpringAOP/AnnotationAwareAspectJAutoProxyCreator分析(上).md)
+* [AnnotationAwareAspectJAutoProxyCreator 分析(下)](docs/Spring全家桶/Spring源码分析/SpringAOP/AnnotationAwareAspectJAutoProxyCreator分析(下).md)
+* [AOP示例demo及@EnableAspectJAutoProxy](docs/Spring全家桶/Spring源码分析/SpringAOP/AOP示例demo及@EnableAspectJAutoProxy.md)
+* [SpringAop(四):jdk 动态代理](docs/Spring全家桶/Spring源码分析/SpringAOP/SpringAop(四):jdk动态代理.md)
+* [SpringAop(五):cglib 代理](docs/Spring全家桶/Spring源码分析/SpringAOP/SpringAop(五):cglib代理.md)
+* [SpringAop(六):aop 总结](docs/Spring全家桶/Spring源码分析/SpringAOP/SpringAop(六):aop总结.md)
+
+### 事务
+* [spring 事务(一):认识事务组件](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(一):认识事务组件.md)
+* [spring 事务(二):事务的执行流程](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(二):事务的执行流程.md)
+* [spring 事务(三):事务的隔离级别与传播方式的处理](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(三):事务的隔离级别与传播方式的处理01.md)
+* [spring 事务(四):事务的隔离级别与传播方式的处理](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(四):事务的隔离级别与传播方式的处理02.md)
+* [spring 事务(五):事务的隔离级别与传播方式的处理](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(五):事务的隔离级别与传播方式的处理03.md)
+* [spring 事务(六):事务的隔离级别与传播方式的处理](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(六):事务的隔离级别与传播方式的处理04.md)
+
+### 启动流程
+* [spring启动流程(一):启动流程概览](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(一):启动流程概览.md)
+* [spring启动流程(二):ApplicationContext 的创建](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(二):ApplicationContext的创建.md)
+* [spring启动流程(三):包的扫描流程](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(三):包的扫描流程.md)
+* [spring启动流程(四):启动前的准备工作](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(四):启动前的准备工作.md)
+* [spring启动流程(五):执行 BeanFactoryPostProcessor](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(五):执行BeanFactoryPostProcessor.md)
+* [spring启动流程(六):注册 BeanPostProcessor](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(六):注册BeanPostProcessor.md)
+* [spring启动流程(七):国际化与事件处理](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(七):国际化与事件处理.md)
+* [spring启动流程(八):完成 BeanFactory 的初始化](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(八):完成BeanFactory的初始化.md)
+* [spring启动流程(九):单例 bean 的创建](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(九):单例bean的创建.md)
+* [spring启动流程(十):启动完成的处理](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(十):启动完成的处理.md)
+* [spring启动流程(十一):启动流程总结](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(十一):启动流程总结.md)
+
+### 组件分析
+* [spring 组件之 ApplicationContext](docs/Spring全家桶/Spring源码分析/Spring组件分析/Spring组件之ApplicationContext.md)
+* [spring 组件之 BeanDefinition](docs/Spring全家桶/Spring源码分析/Spring组件分析/Spring组件之BeanDefinition.md)
+* [Spring 组件之 BeanFactory](docs/Spring全家桶/Spring源码分析/Spring组件分析/Spring组件之BeanFactory.md)
+* [spring 组件之 BeanFactoryPostProcessor](docs/Spring全家桶/Spring源码分析/Spring组件分析/Spring组件之BeanFactoryPostProcessor.md)
+* [spring 组件之 BeanPostProcessor](docs/Spring全家桶/Spring源码分析/Spring组件分析/Spring组件之BeanPostProcessor.md)
+
+### 重要机制探秘
+
+* [ConfigurationClassPostProcessor(一):处理 @ComponentScan 注解](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/ConfigurationClassPostProcessor(一):处理@ComponentScan注解.md)
+* [ConfigurationClassPostProcessor(三):处理 @Import 注解](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/ConfigurationClassPostProcessor(三):处理@Import注解.md)
+* [ConfigurationClassPostProcessor(二):处理 @Bean 注解](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/ConfigurationClassPostProcessor(二):处理@Bean注解.md)
+* [ConfigurationClassPostProcessor(四):处理 @Conditional 注解](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/ConfigurationClassPostProcessor(四):处理@Conditional注解.md)
+* [Spring 探秘之 AOP 的执行顺序](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/Spring探秘之AOP的执行顺序.md)
+* [Spring 探秘之 Spring 事件机制](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/Spring探秘之Spring事件机制.md)
+* [spring 探秘之循环依赖的解决(一):理论基石](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/Spring探秘之循环依赖的解决(一):理论基石.md)
+* [spring 探秘之循环依赖的解决(二):源码分析](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/Spring探秘之循环依赖的解决(二):源码分析.md)
+* [spring 探秘之监听器注解 @EventListener](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/spring探秘之监听器注解@EventListener.md)
+* [spring 探秘之组合注解的处理](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/Spring探秘之组合注解的处理.md)
+
+## SpringMVC
* [SpringMVC中的国际化功能](docs/Spring全家桶/SpringMVC/SpringMVC中的国际化功能.md)
* [SpringMVC中的异常处理器](docs/Spring全家桶/SpringMVC/SpringMVC中的异常处理器.md)
@@ -180,16 +233,22 @@
* [SpringMVC如何实现文件上传](docs/Spring全家桶/SpringMVC/SpringMVC如何实现文件上传.md)
* [SpringMVC中的常用功能](docs/Spring全家桶/SpringMVC/SpringMVC中的常用功能.md)
-### SpringMVC源码分析
+## SpringMVC源码分析
* [SpringMVC源码分析:SpringMVC概述](docs/Spring全家桶/SpringMVC源码分析/SpringMVC源码分析:SpringMVC概述.md)
* [SpringMVC源码分析:SpringMVC设计理念与DispatcherServlet](docs/Spring全家桶/SpringMVC源码分析/SpringMVC源码分析:SpringMVC设计理念与DispatcherServlet.md)
* [SpringMVC源码分析:DispatcherServlet的初始化与请求转发 ](docs/Spring全家桶/SpringMVC源码分析/SpringMVC源码分析:DispatcherServlet的初始化与请求转发.md)
* [SpringMVC源码分析:DispatcherServlet如何找到正确的Controller ](docs/Spring全家桶/SpringMVC源码分析/SpringMVC源码分析:DispatcherServlet如何找到正确的Controller.md)
* [SpringMVC源码剖析:消息转换器HttpMessageConverter与@ResponseBody注解](docs/Spring全家桶/SpringMVC/SpringMVC源码剖析:消息转换器HttpMessageConverter与@ResponseBody注解.md)
-* [SpringMVC源码分析:SpringMVC的视图解析原理 ](docs/Spring全家桶/SpringMVC源码分析/SpringMVC源码分析:SpringMVC的视图解析原理.md)
+* [DispatcherServlet 初始化流程 ](docs/Spring全家桶/SpringMVC源码分析/DispatcherServlet初始化流程.md)
+* [RequestMapping 初始化流程 ](docs/Spring全家桶/SpringMVC源码分析/RequestMapping初始化流程.md)
+* [Spring 容器启动 Tomcat ](docs/Spring全家桶/SpringMVC源码分析/Spring容器启动Tomcat.md)
+* [SpringMVC demo 与@EnableWebMvc 注解 ](docs/Spring全家桶/SpringMVC源码分析/SpringMVC的Demo与@EnableWebMvc注解.md)
+* [SpringMVC 整体源码结构总结 ](docs/Spring全家桶/SpringMVC源码分析/SpringMVC整体源码结构总结.md)
+* [请求执行流程(一)之获取 Handler ](docs/Spring全家桶/SpringMVC源码分析/请求执行流程(一)之获取Handler.md)
+* [请求执行流程(二)之执行 Handler 方法 ](docs/Spring全家桶/SpringMVC源码分析/请求执行流程(二)之执行Handler方法.md)
-### SpringBoot
+## SpringBoot
* [SpringBoot系列:SpringBoot的前世今生](docs/Spring全家桶/SpringBoot/SpringBoot的前世今生.md)
* [给你一份SpringBoot知识清单.md](docs/Spring全家桶/SpringBoot/给你一份SpringBoot知识清单.md)
@@ -206,15 +265,62 @@
* [SpringBoot中的任务调度与@Async](docs/Spring全家桶/SpringBoot/SpringBoot中的任务调度与@Async.md)
* [基于SpringBoot中的开源监控工具SpringBootAdmin](docs/Spring全家桶/SpringBoot/基于SpringBoot中的开源监控工具SpringBootAdmin.md)
-### SpringBoot源码分析
-
-### SpringCloud
-
-### SpringCloud源码分析
-
-todo
-
-## 设计模式
+## SpringBoot源码分析
+* [@SpringBootApplication 注解](docs/Spring全家桶/SpringBoot源码解析/@SpringBootApplication注解.md)
+* [springboot web应用(一):servlet 组件的注册流程](docs/Spring全家桶/SpringBoot源码解析/SpringBootWeb应用(一):servlet组件的注册流程.md)
+* [springboot web应用(二):WebMvc 装配过程](docs/Spring全家桶/SpringBoot源码解析/SpringBootWeb应用(二):WebMvc装配过程.md)
+
+* [SpringBoot 启动流程(一):准备 SpringApplication](docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(一):准备SpringApplication.md)
+* [SpringBoot 启动流程(二):准备运行环境](docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(二):准备运行环境.md)
+* [SpringBoot 启动流程(三):准备IOC容器](docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(三):准备IOC容器.md)
+* [springboot 启动流程(四):启动IOC容器](docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(四):启动IOC容器.md)
+* [springboot 启动流程(五):完成启动](docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(五):完成启动.md)
+* [springboot 启动流程(六):启动流程总结](docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(六):启动流程总结.md)
+
+* [springboot 自动装配(一):加载自动装配类](docs/Spring全家桶/SpringBoot源码解析/SpringBoot自动装配(一):加载自动装配类.md)
+* [springboot 自动装配(二):条件注解](docs/Spring全家桶/SpringBoot源码解析/SpringBoot自动装配(二):条件注解.md)
+* [springboot 自动装配(三):自动装配顺序](docs/Spring全家桶/SpringBoot源码解析/SpringBoot自动装配(三):自动装配顺序.md)
+
+## SpringCloud
+* [SpringCloud概述](docs/Spring全家桶/SpringCloud/SpringCloud概述.md)
+* [Spring Cloud Config](docs/Spring全家桶/SpringCloud/SpringCloudConfig.md)
+* [Spring Cloud Consul](docs/Spring全家桶/SpringCloud/SpringCloudConsul.md)
+* [Spring Cloud Eureka](docs/Spring全家桶/SpringCloud/SpringCloudEureka.md)
+* [Spring Cloud Gateway](docs/Spring全家桶/SpringCloud/SpringCloudGateway.md)
+* [Spring Cloud Hystrix](docs/Spring全家桶/SpringCloud/SpringCloudHystrix.md)
+* [Spring Cloud LoadBalancer](docs/Spring全家桶/SpringCloud/SpringCloudLoadBalancer.md)
+* [Spring Cloud OpenFeign](docs/Spring全家桶/SpringCloud/SpringCloudOpenFeign.md)
+* [Spring Cloud Ribbon](docs/Spring全家桶/SpringCloud/SpringCloudRibbon.md)
+* [Spring Cloud Sleuth](docs/Spring全家桶/SpringCloud/SpringCloudSleuth.md)
+* [Spring Cloud Zuul](docs/Spring全家桶/SpringCloud/SpringCloudZuul.md)
+
+## SpringCloud 源码分析
+* [Spring Cloud Config源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudConfig源码分析.md)
+* [Spring Cloud Eureka源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudEureka源码分析.md)
+* [Spring Cloud Gateway源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudGateway源码分析.md)
+* [Spring Cloud Hystrix源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudHystrix源码分析.md)
+* [Spring Cloud LoadBalancer源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudLoadBalancer源码分析.md)
+* [Spring Cloud OpenFeign源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudOpenFeign源码分析.md)
+* [Spring Cloud Ribbon源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudRibbon源码分析.md)
+
+## SpringCloud Alibaba
+* [SpringCloud Alibaba概览](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibaba概览.md)
+* [SpringCloud Alibaba nacos](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibabaNacos.md)
+* [SpringCloud Alibaba RocketMQ](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibabaRocketMQ.md)
+* [SpringCloud Alibaba sentinel](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibabaSentinel.md)
+* [SpringCloud Alibaba skywalking](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibabaSkywalking.md)
+* [SpringCloud Alibaba seata](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibabaSeata.md)
+
+## SpringCloud Alibaba源码分析
+* [Spring Cloud Seata源码分析](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudSeata源码分析.md)
+* [Spring Cloud Sentinel源码分析](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudSentinel源码分析.md)
+* [SpringCloudAlibaba nacos源码分析:概览](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudAlibabaNacos源码分析:概览.md)
+* [SpringCloudAlibaba nacos源码分析:服务发现](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudAlibabaNacos源码分析:服务发现.md)
+* [SpringCloudAlibaba nacos源码分析:服务注册](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudAlibabaNacos源码分析:服务注册.md)
+* [SpringCloudAlibaba nacos源码分析:配置中心](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudAlibabaNacos源码分析:配置中心.md)
+* [Spring Cloud RocketMQ源码分析](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudRocketMQ源码分析.md)
+
+# 设计模式
* [设计模式学习总结](docs/Java/design-parttern/设计模式学习总结.md)
* [初探Java设计模式:创建型模式(工厂,单例等).md](docs/Java/design-parttern/初探Java设计模式:创建型模式(工厂,单例等).md)
@@ -224,32 +330,32 @@ todo
* [初探Java设计模式:Spring涉及到的种设计模式.md](docs/Java/design-parttern/初探Java设计模式:Spring涉及到的种设计模式.md)
-## 计算机基础
+# 计算机基础
-### 计算机网络
+## 计算机网络
todo
-### 操作系统
+## 操作系统
todo
-#### Linux相关
+## Linux相关
todo
-### 数据结构与算法
+## 数据结构与算法
todo
-#### 数据结构
+## 数据结构
todo
-#### 算法
+## 算法
todo
-## 数据库
+# 数据库
todo
-### MySQL
+## MySQL
* [Mysql原理与实践总结](docs/database/Mysql原理与实践总结.md)
* [重新学习Mysql数据库:无废话MySQL入门](docs/database/重新学习MySQL数据库:无废话MySQL入门.md)
* [重新学习Mysql数据库:『浅入浅出』MySQL和InnoDB](docs/database/重新学习MySQL数据库:『浅入浅出』MySQL和InnoDB.md)
@@ -266,9 +372,9 @@ todo
* [重新学习Mysql数据库:Mysql主从复制,读写分离,分表分库策略与实践](docs/database/重新学习MySQL数据库:Mysql主从复制,读写分离,分表分库策略与实践.md)
-## 缓存
+# 缓存
-### Redis
+## Redis
* [Redis原理与实践总结](docs/cache/Redis原理与实践总结.md)
* [探索Redis设计与实现开篇:什么是Redis](docs/cache/探索Redis设计与实现开篇:什么是Redis.md)
* [探索Redis设计与实现:Redis的基础数据结构概览](docs/cache/探索Redis设计与实现:Redis的基础数据结构概览.md)
@@ -287,11 +393,30 @@ todo
* [探索Redis设计与实现:Redis事务浅析与ACID特性介绍](docs/cache/探索Redis设计与实现:Redis事务浅析与ACID特性介绍.md)
* [探索Redis设计与实现:Redis分布式锁进化史 ](docs/cache/探索Redis设计与实现:Redis分布式锁进化史.md )
-## 消息队列
-
-### Kafka
-
-## 大后端
+# 消息队列
+
+## Kafka
+* [消息队列kafka详解:Kafka快速上手(Java版)](docs/mq/kafka/消息队列kafka详解:Kafka快速上手(Java版).md)
+* [消息队列kafka详解:Kafka一条消息存到broker的过程](docs/mq/kafka/消息队列kafka详解:Kafka一条消息存到broker的过程.md)
+* [消息队列kafka详解:消息队列kafka详解:Kafka介绍](docs/mq/kafka/消息队列kafka详解:Kafka介绍.md)
+* [消息队列kafka详解:Kafka原理分析总结篇](docs/mq/kafka/消息队列kafka详解:Kafka原理分析总结篇.md)
+* [消息队列kafka详解:Kafka常见命令及配置总结](docs/mq/kafka/消息队列kafka详解:Kafka常见命令及配置总结.md)
+* [消息队列kafka详解:Kafka架构介绍](docs/mq/kafka/消息队列kafka详解:Kafka架构介绍.md)
+* [消息队列kafka详解:Kafka的集群工作原理](docs/mq/kafka/消息队列kafka详解:Kafka的集群工作原理.md)
+* [消息队列kafka详解:Kafka重要知识点+面试题大全](docs/mq/kafka/消息队列kafka详解:Kafka重要知识点+面试题大全.md)
+* [消息队列kafka详解:如何实现延迟队列](docs/mq/kafka/消息队列kafka详解:如何实现延迟队列.md)
+* [消息队列kafka详解:如何实现死信队列](docs/mq/kafka/消息队列kafka详解:如何实现死信队列.md)
+
+## RocketMQ
+* [RocketMQ系列:事务消息(最终一致性)](docs/mq/RocketMQ/RocketMQ系列:事务消息(最终一致性).md)
+* [RocketMQ系列:基本概念](docs/mq/RocketMQ/RocketMQ系列:基本概念.md)
+* [RocketMQ系列:广播与延迟消息](docs/mq/RocketMQ/RocketMQ系列:广播与延迟消息.md)
+* [RocketMQ系列:批量发送与过滤](docs/mq/RocketMQ/RocketMQ系列:批量发送与过滤.md)
+* [RocketMQ系列:消息的生产与消费](docs/mq/RocketMQ/RocketMQ系列:消息的生产与消费.md)
+* [RocketMQ系列:环境搭建](docs/mq/RocketMQ/RocketMQ系列:环境搭建.md)
+* [RocketMQ系列:顺序消费](docs/mq/RocketMQ/RocketMQ系列:顺序消费.md)
+
+# 大后端
* [后端技术杂谈开篇:云计算,大数据与AI的故事](docs/backend/后端技术杂谈开篇:云计算,大数据与AI的故事.md)
* [后端技术杂谈:搜索引擎基础倒排索引](docs/backend/后端技术杂谈:搜索引擎基础倒排索引.md)
* [后端技术杂谈:搜索引擎工作原理](docs/backend/后端技术杂谈:搜索引擎工作原理.md)
@@ -306,8 +431,8 @@ todo
* [后端技术杂谈:十分钟理解Kubernetes核心概念](docs/backend/后端技术杂谈:十分钟理解Kubernetes核心概念.md)
* [后端技术杂谈:捋一捋大数据研发的基本概念](docs/backend/后端技术杂谈:捋一捋大数据研发的基本概念.md)
-## 分布式
-### 分布式理论
+# 分布式
+## 分布式理论
* [分布式系统理论基础:一致性PC和PC ](docs/distributed/basic/分布式系统理论基础:一致性PC和PC.md)
* [分布式系统理论基础:CAP ](docs/distributed/basic/分布式系统理论基础:CAP.md)
* [分布式系统理论基础:时间时钟和事件顺序](docs/distributed/basic/分布式系统理论基础:时间时钟和事件顺序.md)
@@ -318,7 +443,7 @@ todo
* [分布式系统理论基础:zookeeper分布式协调服务 ](docs/distributed/basic/分布式系统理论基础:zookeeper分布式协调服务.md)
* [分布式理论总结](docs/distributed/分布式技术实践总结.md)
-### 分布式技术
+## 分布式技术
* [搞懂分布式技术:分布式系统的一些基本概念](docs/distributed/practice/搞懂分布式技术:分布式系统的一些基本概念.md )
* [搞懂分布式技术:分布式一致性协议与Paxos,Raft算法](docs/distributed/practice/搞懂分布式技术:分布式一致性协议与Paxos,Raft算法.md)
* [搞懂分布式技术:初探分布式协调服务zookeeper](docs/distributed/practice/搞懂分布式技术:初探分布式协调服务zookeeper.md )
@@ -339,29 +464,29 @@ todo
* [搞懂分布式技术:浅谈分布式消息技术Kafka](docs/distributed/practice/搞懂分布式技术:浅谈分布式消息技术Kafka.md )
* [分布式技术实践总结](docs/distributed/分布式理论总结.md)
-## 面试指南
+# 面试指南
todo
-### 校招指南
+## 校招指南
todo
-### 面经
+## 面经
todo
-## 工具
+# 工具
todo
-## 资料
+# 资料
todo
-### 书单
+## 书单
todo
-## 待办
+# 待办
springboot和springcloud
-## 微信公众号
+# 微信公众号
-### Java技术江湖
+## Java技术江湖
如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号【Java技术江湖】

diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\346\211\223\345\214\205\344\270\216\345\220\257\345\212\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\346\211\223\345\214\205\344\270\216\345\220\257\345\212\250.md"
new file mode 100644
index 0000000..9f13c13
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\346\211\223\345\214\205\344\270\216\345\220\257\345\212\250.md"
@@ -0,0 +1,1388 @@
+在使用`maven`构建`springboot`项目时,`springboot`相关 jar 包可以使用`parent方式`引入(即在`pom.xml`的`parent`节点引入`springboot`的`GAV`:`org.springframework.boot:spring-boot-starter-parent:2.1.1.RELEASE`),也可以使用`非parent方式`引入(即在 pom 的 dependencyManagement 节点引入`springboot`的`GAV`:`org.springframework.boot:spring-boot-dependencies:2.1.1.RELEASE`)。同时,在打包时,我们可以打成 jar 包,也可以打成 war 包,本文旨在梳理各引入、打包方式的异同。
+
+### 1\. parent 方式引入,打成 jar 包
+
+parent 方式,即在 pom 文件中,将 springboot 的依赖当成项目的 parent 引入,pom 文件示例如下:
+
+```
+
+
+ 4.0.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.1.RELEASE
+
+
+ com.gitee.funcy
+ springboot-parent-jar
+ 1.0.0
+ jar
+ springboot parent jar打包方式
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 3.8.1
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+
+```
+
+添加一个 controller:
+
+```
+package com.gitee.funcy.mavenparent.jar.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * {这里添加描述}
+ *
+ * @author funcy
+ * @date 2019-12-13 10:43 下午
+ */
+@RestController
+public class IndexController {
+
+ @RequestMapping("/")
+ public String helloWorld() {
+ return "hello world";
+ }
+
+}
+
+```
+
+再引入启动类:
+
+```
+package com.gitee.funcy.mavenparent.jar;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * {这里添加描述}
+ *
+ * @author funcy
+ * @date 2019-12-13 10:36 下午
+ */
+@SpringBootApplication
+public class Main {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Main.class, args);
+ }
+
+}
+
+```
+
+运行 Main 方法,请求`http://localhost:8080/`,结果如下:
+
+```
+ $ curl http://localhost:8080/
+hello world
+
+```
+
+可以看到,项目运行成功。
+
+接着,尝试使用 jar 包启动:
+
+```
+# 打包
+ mvn clean install -Dmaven.test.skip=true
+ # 启动jar包
+ java -jar target/springboot-parent-jar-1.0.0.jar
+
+```
+
+可以看到,项目启动成功,请求请求`http://localhost:8080/`,也能显示正确结果。
+
+### 2\. 非 parent 方式引入,打成 jar 包
+
+在实际项目中,项目的 parent 依赖可能给了其他项目,此时 parent 引用就无法进行了,这时我们需要非 parent 引入。非 parent 引入的 pom 如下:
+
+```
+
+
+ 4.0.0
+
+ com.gitee.funcy
+ springboot-jar
+ 1.0.0
+ jar
+ springboot非parent jar打包方式
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 2.1.1.RELEASE
+ 3.8.1
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+
+```
+
+再添加一个`ControllerIndexController.java`与启动类`Main.java`,这两个文件与上述示例相同,这里就不作展示了。
+
+运行 Main 方法,请求`http://localhost:8080/`,结果如下:
+
+```
+ $ curl http://localhost:8080/
+hello world
+
+```
+
+可以看到,项目运行成功。
+
+接着,尝试使用 jar 包启动:
+
+```
+# 打包
+ mvn clean install -Dmaven.test.skip=true
+ # 启动jar包
+ java -jar target/springboot-jar-1.0.0.jar
+
+```
+
+可以看到,项目启动成功,请求请求`http://localhost:8080/`,也能显示正确结果。
+
+### 3\. parent 方式引入,打成 war 包
+
+以上两种方式都是打成 jar,为了兼容传统的 servlet 应用,springboot 也支持打包 war 包,parent 引入打包 war 包的 pom 文件如下:
+
+```
+
+
+ 4.0.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.1.RELEASE
+
+
+ com.gitee.funcy
+ springboot-parent-war
+ 1.0.0
+
+ war
+ springboot parent war打包方式
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 3.8.1
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-test
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
+ 3.2.2
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+```
+
+再添加一个`ControllerIndexController.java`与启动类`Main.java`,这两个文件与上述示例相同,这里就不作展示了。
+
+除此之外,war 包方式还需要添加一个类,用以实现`SpringBootServletInitializer`,该类与启动类`Main.java`位于同一个包下,主要是用来引导 tomcat 等 servlet 容器加载 servlet,内容如下:
+
+```
+/**
+ * {这里添加描述}
+ *
+ * @author funcy
+ * @date 2019-12-20 1:22 下午
+ */
+public class StartApplication extends SpringBootServletInitializer {
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
+ // 注意这里要指向原先用main方法执行的Application启动类
+ return builder.sources(Main.class);
+ }
+}
+
+```
+
+运行 Main 方法,请求`http://localhost:8080/`,结果如下:
+
+```
+ $ curl http://localhost:8080/
+hello world
+
+```
+
+可以看到,项目运行成功。
+
+接着,尝试使用 jar 包启动:
+
+```
+# 打包
+ mvn clean install -Dmaven.test.skip=true
+ # 启动jar包
+ java -jar target/springboot-parent-war-1.0.0.jar
+
+```
+
+可以看到,项目启动成功,请求请求`http://localhost:8080/`,也能显示正确结果。
+
+### 4\. 非 parent 方式引入,打成 war 包
+
+同样地,打成 war 包时,也可使用非 parent 引入方式:
+
+```
+
+
+ 4.0.0
+
+ com.gitee.funcy
+ springboot-war
+ 1.0.0
+
+ war
+ springboot非parent war打包方式
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 2.1.1.RELEASE
+ 3.8.1
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-test
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
+ 3.2.2
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+
+```
+
+再添加一个`ControllerIndexController.java`、`StartApplication.java`与启动类`Main.java`,这三个文件与上述示例相同,这里就不作展示了。
+
+运行 Main 方法,请求`http://localhost:8080/`,结果如下:
+
+```
+ $ curl http://localhost:8080/
+hello world
+
+```
+
+可以看到,项目运行成功。
+
+接着,尝试使用 jar 包启动:
+
+```
+# 打包
+ mvn clean install -Dmaven.test.skip=true
+ # 启动jar包
+ java -jar target/springboot-war-1.0.0.jar
+
+```
+
+可以看到,项目启动成功,请求请求`http://localhost:8080/`,也能显示正确结果。
+
+### 5\. 总结
+
+springboot 引入及打包方式组合下来有如下四种:
+
+| 打包 / 引入 | parent 方式 | 非 parent 方式 |
+| --- | --- | --- |
+| jar | parent-jar 方式 | 非 parent-jar 方式 |
+| war | parent-war 方式 | 非 parent-war 方式 |
+
+### 1\. 开发时启动
+
+在开发时启动 springboot 应用,指的是直接运行源码,如在开发时在 ide 中运行启动类的 main () 方法。
+
+#### 1.1 在 ide 中执行启动类的`main()`方法
+
+自从有了 springboot 后,web 项目就不必再放到 web 容器中运行了,直接运行项目的`main()`方法就行了:
+
+
+
+启动日志如下:
+
+```
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 21:11:16.365 INFO 84046 --- [ main] com.gitee.funcy.maven.jar.Main : Starting Main on l with PID 84046 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-jar/target/classes started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo)
+2020-01-07 21:11:16.368 INFO 84046 --- [ main] com.gitee.funcy.maven.jar.Main : No active profile set, falling back to default profiles: default
+2020-01-07 21:11:17.468 INFO 84046 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 21:11:17.497 INFO 84046 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 21:11:17.497 INFO 84046 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 21:11:17.513 INFO 84046 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 21:11:17.605 INFO 84046 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 21:11:17.605 INFO 84046 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1206 ms
+2020-01-07 21:11:17.861 INFO 84046 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 21:11:18.096 INFO 84046 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 21:11:18.100 INFO 84046 --- [ main] com.gitee.funcy.maven.jar.Main : Started Main in 1.988 seconds (JVM running for 2.34)
+2020-01-07 21:11:32.155 INFO 84046 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
+2020-01-07 21:11:32.155 INFO 84046 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2020-01-07 21:11:32.223 INFO 84046 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 68 ms
+
+```
+
+访问`http://localhost:8080/`,结果如下:
+
+```
+$ curl http://localhost:8080
+hello world
+
+```
+
+以上启动方式**war 与 jar 打包方式**都支持。
+
+#### 1.2`mvn spring-boot:run`启动
+
+这种方式也是源码启动,在命令行界面进入项目对应的源码目录下,然后执行`mvn spring-boot:run`命令:
+
+```
+springboot-parent-war $ mvn spring-boot:run
+[INFO] Scanning for projects...
+[INFO]
+[INFO] ---------------< com.gitee.funcy:springboot-parent-war >----------------
+[INFO] Building springboot parent war打包方式 1.0.0
+[INFO] --------------------------------[ war ]---------------------------------
+[INFO]
+[INFO] >>> spring-boot-maven-plugin:2.1.1.RELEASE:run (default-cli) > test-compile @ springboot-parent-war >>>
+[INFO]
+[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ springboot-parent-war ---
+[INFO] Using 'UTF-8' encoding to copy filtered resources.
+[INFO] Copying 0 resource
+[INFO] Copying 0 resource
+[INFO]
+[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ springboot-parent-war ---
+[INFO] Changes detected - recompiling the module!
+[INFO] Compiling 3 source files to /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-parent-war/target/classes
+[INFO]
+[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ springboot-parent-war ---
+[INFO] Using 'UTF-8' encoding to copy filtered resources.
+[INFO] skip non existing resourceDirectory /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-parent-war/src/test/resources
+[INFO]
+[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ springboot-parent-war ---
+[INFO] No sources to compile
+[INFO]
+[INFO] <<< spring-boot-maven-plugin:2.1.1.RELEASE:run (default-cli) < test-compile @ springboot-parent-war <<<
+[INFO]
+[INFO]
+[INFO] --- spring-boot-maven-plugin:2.1.1.RELEASE:run (default-cli) @ springboot-parent-war ---
+
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 21:40:50.577 INFO 84448 --- [ main] com.gitee.funcy.mavenparent.war.Main : Starting Main on funcydeMacBook-Pro.local with PID 84448 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-parent-war/target/classes started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-parent-war)
+2020-01-07 21:40:50.579 INFO 84448 --- [ main] com.gitee.funcy.mavenparent.war.Main : No active profile set, falling back to default profiles: default
+2020-01-07 21:40:51.311 INFO 84448 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 21:40:51.336 INFO 84448 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 21:40:51.337 INFO 84448 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 21:40:51.347 INFO 84448 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 21:40:51.406 INFO 84448 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 21:40:51.406 INFO 84448 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 800 ms
+2020-01-07 21:40:51.582 INFO 84448 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 21:40:51.736 INFO 84448 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 21:40:51.739 INFO 84448 --- [ main] com.gitee.funcy.mavenparent.war.Main : Started Main in 1.39 seconds (JVM running for 3.943)
+2020-01-07 21:41:04.068 INFO 84448 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
+2020-01-07 21:41:04.069 INFO 84448 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2020-01-07 21:41:04.076 INFO 84448 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 7 ms
+
+```
+
+可以看到,项目启动成功,请求`http://localhost:8080`,也能获得结果:
+
+```
+ $ curl http://localhost:8080
+hello world
+
+```
+
+以上启动方式**war 与 jar 打包方式**都支持。
+
+### 2\. jar 包启动
+
+#### 2.1`java -jar`方式启动
+
+对于打成`jar包`的`springboot`项目,使用`java -jar xxx.jar`命令即可启动:
+
+```
+:target $ java -jar springboot-jar-1.0.0.jar
+
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 21:47:47.075 INFO 85080 --- [ main] com.gitee.funcy.maven.jar.Main : Starting Main on funcydeMacBook-Pro.local with PID 85080 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-jar/target/springboot-jar-1.0.0.jar started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-jar/target)
+2020-01-07 21:47:47.077 INFO 85080 --- [ main] com.gitee.funcy.maven.jar.Main : No active profile set, falling back to default profiles: default
+2020-01-07 21:47:48.152 INFO 85080 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 21:47:48.186 INFO 85080 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 21:47:48.186 INFO 85080 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 21:47:48.202 INFO 85080 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 21:47:48.303 INFO 85080 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 21:47:48.303 INFO 85080 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1177 ms
+2020-01-07 21:47:48.502 INFO 85080 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 21:47:48.677 INFO 85080 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 21:47:48.680 INFO 85080 --- [ main] com.gitee.funcy.maven.jar.Main : Started Main in 1.977 seconds (JVM running for 2.398)
+
+```
+
+访问`http://localhost:8080`,同样也能获得结果.
+
+#### 2.2`java org.springframework.boot.loader.JarLauncher`方式启动
+
+这种启动方式就魔幻了:好好的一个 jar,要先解压,然后直接运行里面的类,操作如下:
+
+```
+target $ unzip -d ./tmp springboot-jar-1.0.0.jar
+Archive: springboot-jar-1.0.0.jar
+ creating: ./tmp/META-INF/
+ inflating: ./tmp/META-INF/MANIFEST.MF
+ creating: ./tmp/org/
+ creating: ./tmp/org/springframework/
+ creating: ./tmp/org/springframework/boot/
+··· 省略其他内容
+target $ cd tmp/
+tmp $ java org.springframework.boot.loader.JarLauncher
+
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 21:56:00.472 INFO 85431 --- [ main] com.gitee.funcy.maven.jar.Main : Starting Main on funcydeMacBook-Pro.local with PID 85431 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-jar/target/tmp/BOOT-INF/classes started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-jar/target/tmp)
+2020-01-07 21:56:00.475 INFO 85431 --- [ main] com.gitee.funcy.maven.jar.Main : No active profile set, falling back to default profiles: default
+2020-01-07 21:56:01.589 INFO 85431 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 21:56:01.619 INFO 85431 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 21:56:01.619 INFO 85431 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 21:56:01.634 INFO 85431 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 21:56:01.722 INFO 85431 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 21:56:01.722 INFO 85431 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1203 ms
+2020-01-07 21:56:01.931 INFO 85431 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 21:56:02.154 INFO 85431 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 21:56:02.157 INFO 85431 --- [ main] com.gitee.funcy.maven.jar.Main : Started Main in 2.025 seconds (JVM running for 2.472)
+
+```
+
+总结下,步骤如下:
+
+1. 进入项目`target/`目录
+2. 解压`jar包`到`tmp`目录:`unzip -d ./tmp springboot-jar-1.0.0.jar`
+3. 进入`tmp目录`:`cd tmp/`
+4. 运行:`java org.springframework.boot.loader.JarLauncher`
+
+访问`http://localhost:8080`,也能得到正确结果。
+
+> 注:这种神奇的启动方式在什么情况下会使用呢?我曾经见过一些项目组,为了安全会把生产的配置文件放在服务器上,在部署项目的时候,先解压 jar 包,然后替换相应的配置文件,再运行。这种解压 jar 包、替换配置文件的方式就可以用此启动方式了。当然,这些解压、替换、启动等操作都会写进 shell 脚本里,自动化运行。
+
+### 3\. war 包启动
+
+#### 3.1`java -jar`方式启动
+
+项目都打成`war包`了,还能使用`java -jar`启动?是的,`springboot`就是这么方便:
+
+```
+target $ java -jar springboot-war-1.0.0.war
+
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 22:11:54.284 INFO 85638 --- [ main] com.gitee.funcy.maven.war.Main : Starting Main on funcydeMacBook-Pro.local with PID 85638 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-war/target/springboot-war-1.0.0.war started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-war/target)
+2020-01-07 22:11:54.287 INFO 85638 --- [ main] com.gitee.funcy.maven.war.Main : No active profile set, falling back to default profiles: default
+2020-01-07 22:11:55.257 INFO 85638 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 22:11:55.286 INFO 85638 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 22:11:55.287 INFO 85638 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 22:11:55.299 INFO 85638 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 22:11:55.711 INFO 85638 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 22:11:55.711 INFO 85638 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1379 ms
+2020-01-07 22:11:55.873 INFO 85638 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 22:11:56.031 INFO 85638 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 22:11:56.034 INFO 85638 --- [ main] com.gitee.funcy.maven.war.Main : Started Main in 2.066 seconds (JVM running for 2.469)
+2020-01-07 22:12:01.189 INFO 85638 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
+2020-01-07 22:12:01.190 INFO 85638 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2020-01-07 22:12:01.195 INFO 85638 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
+
+```
+
+看,项目真的跑起来了!
+
+#### 3.2`java org.springframework.boot.loader.WarLauncher`方式启动
+
+`springboot`的`jar包`可以解压,然后运行某个类来启动,`war包`竟然也有这种方法!`jar包`的启动类是`org.springframework.boot.loader.JarLauncher`,相应的`war包`启动类是`org.springframework.boot.loader.WarLauncher`,步骤如下:
+
+1. 进入项目`target/`目录
+2. 解压`war包`到`tmp`目录:`unzip -d ./tmp springboot-war-1.0.0.war`
+3. 进入`tmp目录`:`cd tmp/`
+4. 运行:`java org.springframework.boot.loader.WarLauncher`
+
+过程如下:
+
+```
+target $ unzip -d ./tmp springboot-war-1.0.0.war
+Archive: springboot-war-1.0.0.war
+ creating: ./tmp/META-INF/
+ inflating: ./tmp/META-INF/MANIFEST.MF
+ creating: ./tmp/org/
+ creating: ./tmp/org/springframework/
+ creating: ./tmp/org/springframework/boot/
+··· 省略其他
+target $ cd tmp/
+tmp $ java org.springframework.boot.loader.WarLauncher
+
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 22:17:09.637 INFO 85782 --- [ main] com.gitee.funcy.maven.war.Main : Starting Main on funcydeMacBook-Pro.local with PID 85782 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-war/target/tmp/WEB-INF/classes started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-war/target/tmp)
+2020-01-07 22:17:09.640 INFO 85782 --- [ main] com.gitee.funcy.maven.war.Main : No active profile set, falling back to default profiles: default
+2020-01-07 22:17:10.576 INFO 85782 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 22:17:10.603 INFO 85782 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 22:17:10.604 INFO 85782 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 22:17:10.616 INFO 85782 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 22:17:10.725 INFO 85782 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 22:17:10.725 INFO 85782 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1046 ms
+2020-01-07 22:17:10.942 INFO 85782 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 22:17:11.137 INFO 85782 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 22:17:11.140 INFO 85782 --- [ main] com.gitee.funcy.maven.war.Main : Started Main in 1.817 seconds (JVM running for 2.183)
+2020-01-07 22:17:15.024 INFO 85782 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
+2020-01-07 22:17:15.024 INFO 85782 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2020-01-07 22:17:15.029 INFO 85782 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
+
+```
+
+可以看到,项目也启动成功了!
+
+#### 3.3 传统方式启动:使用 tomcat 容器
+
+最初的`war包`就是放在 tomcat 等容器中运行的,我们也来试试`war包`在 tomcat 容器中运行情况如何。这里说的 tomcat 容器是指在[tomcat 官网](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Ftomcat.apache.org%2F "tomcat官网")下载的容器,非`springboot`内置容器。这里我下载的是`apache-tomcat-8.5.47`,过程如下:
+
+```
+... 省略tomcat日志输出
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 22:28:23.519 INFO 85904 --- [ost-startStop-1] c.g.funcy.maven.war.StartApplication : Starting StartApplication on funcydeMacBook-Pro.local with PID 85904 (/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/springboot-war-1.0.0/WEB-INF/classes started by funcy in /Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47)
+2020-01-07 22:28:23.523 INFO 85904 --- [ost-startStop-1] c.g.funcy.maven.war.StartApplication : No active profile set, falling back to default profiles: default
+2020-01-07 22:28:24.256 INFO 85904 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 676 ms
+2020-01-07 22:28:24.655 INFO 85904 --- [ost-startStop-1] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 22:28:24.920 INFO 85904 --- [ost-startStop-1] c.g.funcy.maven.war.StartApplication : Started StartApplication in 1.86 seconds (JVM running for 3.98)
+07-Jan-2020 22:28:24.974 信息 [localhost-startStop-1] org.apache.jasper.servlet.TldScanner.scanJars 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
+07-Jan-2020 22:28:24.999 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/springboot-war-1.0.0.war] has finished in [3,468] ms
+07-Jan-2020 22:28:25.000 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/docs]
+07-Jan-2020 22:28:25.010 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/docs] has finished in [10] ms
+07-Jan-2020 22:28:25.010 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/manager]
+07-Jan-2020 22:28:25.027 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/manager] has finished in [17] ms
+07-Jan-2020 22:28:25.027 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/examples]
+07-Jan-2020 22:28:25.181 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/examples] has finished in [154] ms
+07-Jan-2020 22:28:25.181 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/ROOT]
+07-Jan-2020 22:28:25.191 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/ROOT] has finished in [10] ms
+07-Jan-2020 22:28:25.191 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/host-manager]
+07-Jan-2020 22:28:25.202 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/host-manager] has finished in [11] ms
+07-Jan-2020 22:28:25.206 信息 [main] org.apache.coyote.AbstractProtocol.start 开始协议处理句柄["http-nio-8080"]
+07-Jan-2020 22:28:25.212 信息 [main] org.apache.coyote.AbstractProtocol.start 开始协议处理句柄["ajp-nio-8009"]
+07-Jan-2020 22:28:25.213 信息 [main] org.apache.catalina.startup.Catalina.start Server startup in 3717 ms
+2020-01-07 22:29:30.754 INFO 85904 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2020-01-07 22:29:30.767 INFO 85904 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 12 ms
+
+```
+
+请求`http://localhost:8080/springboot-war-1.0.0/`,结果如下:
+
+```
+$ curl 'http://localhost:8080/springboot-war-1.0.0/'
+hello world
+
+```
+
+可以看到,已经部署成功了。
+
+### 4\. 总结
+
+| | main () 方法 | mvn 命令 | java -jar | java xxx.WarLauncher | java xxx.JarLauncher | 外置容器 |
+| --- | --- | --- | --- | --- | --- | --- |
+| war | 支持 | 支持 | 支持 | 支持 | 不支持 | 支持 |
+| jar | 支持 | 支持 | 支持 | 不支持 | 支持 | 不支持
+
+### 1\. maven 打包后的文件
+
+进入`springboot-jar/target`目录,使用`tree`命令,目录结构如下:
+
+```
+ $ tree
+.
+├── classes
+│ └── com
+│ └── gitee
+│ └── funcy
+│ └── maven
+│ └── jar
+│ ├── Main.class
+│ └── controller
+│ └── IndexController.class
+├── generated-sources
+│ └── annotations
+├── maven-archiver
+│ └── pom.properties
+├── maven-status
+│ └── maven-compiler-plugin
+│ └── compile
+│ └── default-compile
+│ ├── createdFiles.lst
+│ └── inputFiles.lst
+├── springboot-jar-1.0.0.jar
+└── springboot-jar-1.0.0.jar.original
+
+14 directories, 7 files
+
+```
+
+注意`springboot-jar-1.0.0.jar`与`springboot-jar-1.0.0.jar.original`的区别:`springboot-jar-1.0.0.jar.original`属于原始 Maven 打包 jar 文件,该文件仅包含应用本地资源,如编译后的 classes 目录下的资源文件等,未引入第三方依赖资源;而`springboot-jar-1.0.0.jar`引入了第三方依赖资源(主要为 jar 包)。
+
+使用`unzip springboot-jar-1.0.0.jar -d tmp`解压 jar 包,内容如下:
+
+```
+ $ tree tmp/
+tmp/
+├── BOOT-INF
+│ ├── classes
+│ │ └── com
+│ │ └── gitee
+│ │ └── funcy
+│ │ └── maven
+│ │ └── jar
+│ │ ├── Main.class
+│ │ └── controller
+│ │ └── IndexController.class
+│ └── lib
+│ ├── classmate-1.4.0.jar
+│ ├── hibernate-validator-6.0.13.Final.jar
+│ ├── jackson-annotations-2.9.0.jar
+│ ├── jackson-core-2.9.7.jar
+│ ├── jackson-databind-2.9.7.jar
+│ ├── jackson-datatype-jdk8-2.9.7.jar
+│ ├── jackson-datatype-jsr310-2.9.7.jar
+│ ├── jackson-module-parameter-names-2.9.7.jar
+│ ├── javax.annotation-api-1.3.2.jar
+│ ├── jboss-logging-3.3.2.Final.jar
+│ ├── jul-to-slf4j-1.7.25.jar
+│ ├── log4j-api-2.11.1.jar
+│ ├── log4j-to-slf4j-2.11.1.jar
+│ ├── logback-classic-1.2.3.jar
+│ ├── logback-core-1.2.3.jar
+│ ├── slf4j-api-1.7.25.jar
+│ ├── snakeyaml-1.23.jar
+│ ├── spring-aop-5.1.3.RELEASE.jar
+│ ├── spring-beans-5.1.3.RELEASE.jar
+│ ├── spring-boot-2.1.1.RELEASE.jar
+│ ├── spring-boot-autoconfigure-2.1.1.RELEASE.jar
+│ ├── spring-boot-starter-2.1.1.RELEASE.jar
+│ ├── spring-boot-starter-json-2.1.1.RELEASE.jar
+│ ├── spring-boot-starter-logging-2.1.1.RELEASE.jar
+│ ├── spring-boot-starter-tomcat-2.1.1.RELEASE.jar
+│ ├── spring-boot-starter-web-2.1.1.RELEASE.jar
+│ ├── spring-context-5.1.3.RELEASE.jar
+│ ├── spring-core-5.1.3.RELEASE.jar
+│ ├── spring-expression-5.1.3.RELEASE.jar
+│ ├── spring-jcl-5.1.3.RELEASE.jar
+│ ├── spring-web-5.1.3.RELEASE.jar
+│ ├── spring-webmvc-5.1.3.RELEASE.jar
+│ ├── tomcat-embed-core-9.0.13.jar
+│ ├── tomcat-embed-el-9.0.13.jar
+│ ├── tomcat-embed-websocket-9.0.13.jar
+│ └── validation-api-2.0.1.Final.jar
+├── META-INF
+│ ├── MANIFEST.MF
+│ └── maven
+│ └── com.gitee.funcy
+│ └── springboot-jar
+│ ├── pom.properties
+│ └── pom.xml
+└── org
+ └── springframework
+ └── boot
+ └── loader
+ ├── ExecutableArchiveLauncher.class
+ ├── JarLauncher.class
+ ├── LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
+ ├── LaunchedURLClassLoader.class
+ ├── Launcher.class
+ ├── MainMethodRunner.class
+ ├── PropertiesLauncher$1.class
+ ├── PropertiesLauncher$ArchiveEntryFilter.class
+ ├── PropertiesLauncher$PrefixMatchingArchiveFilter.class
+ ├── PropertiesLauncher.class
+ ├── WarLauncher.class
+ ├── archive
+ │ ├── Archive$Entry.class
+ │ ├── Archive$EntryFilter.class
+ │ ├── Archive.class
+ │ ├── ExplodedArchive$1.class
+ │ ├── ExplodedArchive$FileEntry.class
+ │ ├── ExplodedArchive$FileEntryIterator$EntryComparator.class
+ │ ├── ExplodedArchive$FileEntryIterator.class
+ │ ├── ExplodedArchive.class
+ │ ├── JarFileArchive$EntryIterator.class
+ │ ├── JarFileArchive$JarFileEntry.class
+ │ └── JarFileArchive.class
+ ├── data
+ │ ├── RandomAccessData.class
+ │ ├── RandomAccessDataFile$1.class
+ │ ├── RandomAccessDataFile$DataInputStream.class
+ │ ├── RandomAccessDataFile$FileAccess.class
+ │ └── RandomAccessDataFile.class
+ ├── jar
+ │ ├── AsciiBytes.class
+ │ ├── Bytes.class
+ │ ├── CentralDirectoryEndRecord.class
+ │ ├── CentralDirectoryFileHeader.class
+ │ ├── CentralDirectoryParser.class
+ │ ├── CentralDirectoryVisitor.class
+ │ ├── FileHeader.class
+ │ ├── Handler.class
+ │ ├── JarEntry.class
+ │ ├── JarEntryFilter.class
+ │ ├── JarFile$1.class
+ │ ├── JarFile$2.class
+ │ ├── JarFile$JarFileType.class
+ │ ├── JarFile.class
+ │ ├── JarFileEntries$1.class
+ │ ├── JarFileEntries$EntryIterator.class
+ │ ├── JarFileEntries.class
+ │ ├── JarURLConnection$1.class
+ │ ├── JarURLConnection$JarEntryName.class
+ │ ├── JarURLConnection.class
+ │ ├── StringSequence.class
+ │ └── ZipInflaterInputStream.class
+ └── util
+ └── SystemPropertyUtils.class
+
+21 directories, 91 files
+
+```
+
+可以看到,文件中主要分为如下几个目录:
+
+* `BOOT-INF/classes`目录存放应用编译后的 class 文件;
+* `BOOT-INF/lib`目录存放应用依赖的 jar 包;
+* `META-INF/`目录存放应用依赖的 jar 包;
+* `org/`目录存放 spring boot 相关的 class 文件。
+
+### 2.`java -jar`启动 springboot jar 包
+
+java 官方规定,`java -jar`命令引导的具体启动类必须配置在`MANIFEST.MF`文件中,而根据`jar文件规范`,`MANIFEST.MF`文件必须存放在`/META-INF/`目录下。因此,启动类配置在 jar 包的`/META-INF/MANIFEST.MF`文件中,查看该文件,内容如下:
+
+```
+$ cat MANIFEST.MF
+Manifest-Version: 1.0
+Archiver-Version: Plexus Archiver
+Built-By: fangchengyan
+Start-Class: com.gitee.funcy.maven.jar.Main
+Spring-Boot-Classes: BOOT-INF/classes/
+Spring-Boot-Lib: BOOT-INF/lib/
+Spring-Boot-Version: 2.1.1.RELEASE
+Created-By: Apache Maven 3.6.0
+Build-Jdk: 1.8.0_222
+Main-Class: org.springframework.boot.loader.JarLauncher
+
+```
+
+发现`Main-Class`属性指向的`Class`为`org.springframework.boot.loader.JarLauncher`,而该类存放在 jar 包的`org/springframework/boot/loader/`目录下,并且项目的引导类定义在`Start-Class`属性性中,该属性并非 java 平台标准`META-INF/MANIFEST.MF`属性。
+
+> 注:
+>
+> 1. `org.springframework.boot.loader.JarLauncher`是可执行 jar 的启动器,`org.springframework.boot.loader.WarLauncher`是可执行 war 的启动器。
+>
+>
+> 2. `org.springframework.boot.loader.JarLauncher`所在的 jar 文件的 Maven GAV 信息为`org.springframework.boot:spring-boot-loader:${springboot-version}`,通常情况下,这个依赖没有必要引入 springboot 项目的 pom.xml 文件。
+
+查看`JarLauncher`源码,如下:
+
+```
+public class JarLauncher extends ExecutableArchiveLauncher {
+
+ static final String BOOT_INF_CLASSES = "BOOT-INF/classes/";
+
+ static final String BOOT_INF_LIB = "BOOT-INF/lib/";
+
+ public JarLauncher() {
+ }
+
+ protected JarLauncher(Archive archive) {
+ super(archive);
+ }
+
+ @Override
+ protected boolean isNestedArchive(Archive.Entry entry) {
+ if (entry.isDirectory()) {
+ return entry.getName().equals(BOOT_INF_CLASSES);
+ }
+ return entry.getName().startsWith(BOOT_INF_LIB);
+ }
+
+ public static void main(String[] args) throws Exception {
+ new JarLauncher().launch(args);
+ }
+
+}
+
+```
+
+可以发现,`BOOT-INF/classes/`与`BOOT-INF/lib/`分别使用常量`BOOT_INF_CLASSES`和`BOOT_INF_LIB`表示,并且用于`isNestedArchive(Archive.Entry)`方法判断,从该方法的实现分析,方法参数`Archive.Entry`看似为 jar 文件中的资源,比如`application.properties`。
+
+`Archive.Entry`有两种实现,其中一种为`org.springframework.boot.loader.archive.JarFileArchive.JarFileEntry`,基于`java.util.jar.JarEntry`,表示`FAT JAR`嵌入资源,另一种为`org.springframework.boot.loader.archive.ExplodedArchive.FileEntry`,基于文件系统实现。这也说明了`JarLauncher`支持`JAR`和`文件系统`两种启动方式。
+
+> 文件系统启动方式如下:
+>
+> 1. 解压 jar 包到`temp`目录:`unzip springboot-jar-1.0.0.jar -d tmp`
+> 2. 进入`temp`目录,运行命令:`java org.springframework.boot.loader.JarLauncher`可以看到,项目同样能正常启动。
+
+在`JarLauncher`作为引导类时,当执行`java -jar`命令时,`/META-INF`资源的`Main-Class`属性将调用其`main(String[])`方法,实际上调用的是`JarLauncher#launch(args)`方法,而该方法继承于基类`org.springframework.boot.loader.Launcher`,它们之间的继承关系如下:
+
+* `org.springframework.boot.loader.Launcher`
+ * `org.springframework.boot.loader.ExecutableArchiveLauncher`
+ * `org.springframework.boot.loader.JarLauncher`
+ * `org.springframework.boot.loader.WarLauncher`
+
+简单来说,springboot jar 启动过程如下:
+
+1. `java -jar xxx.jar`运行的是`JarLauncher`
+2. `JarLauncher#main(String[])`方法会调用`Launcher#launch(String[])`方法,创建 ClassLoader () 及调用项目的`main`方法
+ * 项目主类的获取实现位于`ExecutableArchiveLauncher#getMainClass()`,主要是从`/META-INF/MANIFEST.MF`获取`Start-Class`属性
+ * 项目主类的 main () 方法调用位于`MainMethodRunner#run()`,使用反射方式进行调用
+
+### 3.`java -jar`启动 springboot war 包
+
+从上面的分析,我们得到了启动 jar 包的`org.springframework.boot.loader.JarLauncher`以及启动 war 包的`org.springframework.boot.loader.WarLauncher`,这里我们来分析下`WarLauncher`上如何工作的。
+
+`WarLauncher`代码如下:
+
+```
+public class WarLauncher extends ExecutableArchiveLauncher {
+
+ private static final String WEB_INF = "WEB-INF/";
+
+ private static final String WEB_INF_CLASSES = WEB_INF + "classes/";
+
+ private static final String WEB_INF_LIB = WEB_INF + "lib/";
+
+ private static final String WEB_INF_LIB_PROVIDED = WEB_INF + "lib-provided/";
+
+ public WarLauncher() {
+ }
+
+ protected WarLauncher(Archive archive) {
+ super(archive);
+ }
+
+ @Override
+ public boolean isNestedArchive(Archive.Entry entry) {
+ if (entry.isDirectory()) {
+ return entry.getName().equals(WEB_INF_CLASSES);
+ }
+ else {
+ return entry.getName().startsWith(WEB_INF_LIB)
+ || entry.getName().startsWith(WEB_INF_LIB_PROVIDED);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ new WarLauncher().launch(args);
+ }
+
+}
+
+```
+
+可以看到,`WEB-INF/classes/`、`WEB-INF/lib/`、`WEB-INF/lib-provided/`均为`WarLauncher`的`Class Path`,其中`WEB-INF/classes/`、`WEB-INF/lib/`是传统的 Servlet 应用的 ClassPath 路径,而`WEB-INF/lib-provided/`属性 springboot`WarLauncher`定制实现。那么`WEB-INF/lib-provided/`究竟是干嘛的呢?看到`provided`,我们可以大胆猜想`WEB-INF/lib-provided/`存放的是`pom.xml`文件中,`scope`为`provided`的 jar。
+
+为了验证以上猜想,修改的 pom.xml 文件如下:
+
+```
+
+
+ 4.0.0
+
+ com.gitee.funcy
+ springboot-war
+ 1.0.0
+
+ war
+ springboot非parent war打包方式
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 2.1.1.RELEASE
+ 3.8.1
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-test
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
+ 3.2.2
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+
+```
+
+这里我们添加了 springboot 的测试 jar`org.springframework.boot:spring-boot-test`,并将其`scope`设置为`provided`. 运行 maven 打包命令`mvn clean install -Dmaven.test.skip=true`,可以看到项目能正常打包。
+
+打包完成后,进入`target`目录,运行`java -jar springboot-war-1.0.0.war`,项目能正常启动。
+
+接下来,我们来看看`springboot-war-1.0.0.war`有些啥。首先使用`unzip springboot-war-1.0.0.war -d tmp`命令解压,再使用`tree -h`命令查看文件结构,结果如下
+
+```
+ $ tree -h
+.
+├── [ 128] META-INF
+│ ├── [ 311] MANIFEST.MF
+│ └── [ 96] maven
+│ └── [ 96] com.gitee.funcy
+│ └── [ 128] springboot-war
+│ ├── [ 95] pom.properties
+│ └── [3.3K] pom.xml
+├── [ 160] WEB-INF
+│ ├── [ 96] classes
+│ │ └── [ 96] com
+│ │ └── [ 96] gitee
+│ │ └── [ 96] funcy
+│ │ └── [ 96] maven
+│ │ └── [ 160] war
+│ │ ├── [ 688] Main.class
+│ │ ├── [ 891] StartApplication.class
+│ │ └── [ 96] controller
+│ │ └── [ 646] IndexController.class
+│ ├── [1.2K] lib
+│ │ ├── [ 65K] classmate-1.4.0.jar
+│ │ ├── [1.1M] hibernate-validator-6.0.13.Final.jar
+│ │ ├── [ 65K] jackson-annotations-2.9.0.jar
+│ │ ├── [316K] jackson-core-2.9.7.jar
+│ │ ├── [1.3M] jackson-databind-2.9.7.jar
+│ │ ├── [ 33K] jackson-datatype-jdk8-2.9.7.jar
+│ │ ├── [ 98K] jackson-datatype-jsr310-2.9.7.jar
+│ │ ├── [8.4K] jackson-module-parameter-names-2.9.7.jar
+│ │ ├── [ 26K] javax.annotation-api-1.3.2.jar
+│ │ ├── [ 65K] jboss-logging-3.3.2.Final.jar
+│ │ ├── [4.5K] jul-to-slf4j-1.7.25.jar
+│ │ ├── [258K] log4j-api-2.11.1.jar
+│ │ ├── [ 17K] log4j-to-slf4j-2.11.1.jar
+│ │ ├── [284K] logback-classic-1.2.3.jar
+│ │ ├── [461K] logback-core-1.2.3.jar
+│ │ ├── [ 40K] slf4j-api-1.7.25.jar
+│ │ ├── [294K] snakeyaml-1.23.jar
+│ │ ├── [360K] spring-aop-5.1.3.RELEASE.jar
+│ │ ├── [656K] spring-beans-5.1.3.RELEASE.jar
+│ │ ├── [935K] spring-boot-2.1.1.RELEASE.jar
+│ │ ├── [1.2M] spring-boot-autoconfigure-2.1.1.RELEASE.jar
+│ │ ├── [ 413] spring-boot-starter-2.1.1.RELEASE.jar
+│ │ ├── [ 421] spring-boot-starter-json-2.1.1.RELEASE.jar
+│ │ ├── [ 423] spring-boot-starter-logging-2.1.1.RELEASE.jar
+│ │ ├── [ 422] spring-boot-starter-tomcat-2.1.1.RELEASE.jar
+│ │ ├── [ 421] spring-boot-starter-web-2.1.1.RELEASE.jar
+│ │ ├── [1.0M] spring-context-5.1.3.RELEASE.jar
+│ │ ├── [1.2M] spring-core-5.1.3.RELEASE.jar
+│ │ ├── [274K] spring-expression-5.1.3.RELEASE.jar
+│ │ ├── [ 23K] spring-jcl-5.1.3.RELEASE.jar
+│ │ ├── [1.3M] spring-web-5.1.3.RELEASE.jar
+│ │ ├── [782K] spring-webmvc-5.1.3.RELEASE.jar
+│ │ ├── [3.1M] tomcat-embed-core-9.0.13.jar
+│ │ ├── [244K] tomcat-embed-el-9.0.13.jar
+│ │ ├── [257K] tomcat-embed-websocket-9.0.13.jar
+│ │ └── [ 91K] validation-api-2.0.1.Final.jar
+│ └── [ 96] lib-provided
+│ └── [194K] spring-boot-test-2.1.1.RELEASE.jar
+└── [ 96] org
+ └── [ 96] springframework
+ └── [ 96] boot
+ └── [ 544] loader
+ ├── [3.5K] ExecutableArchiveLauncher.class
+ ├── [1.5K] JarLauncher.class
+ ├── [1.5K] LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
+ ├── [5.6K] LaunchedURLClassLoader.class
+ ├── [4.6K] Launcher.class
+ ├── [1.5K] MainMethodRunner.class
+ ├── [ 266] PropertiesLauncher$1.class
+ ├── [1.4K] PropertiesLauncher$ArchiveEntryFilter.class
+ ├── [1.9K] PropertiesLauncher$PrefixMatchingArchiveFilter.class
+ ├── [ 19K] PropertiesLauncher.class
+ ├── [1.7K] WarLauncher.class
+ ├── [ 416] archive
+ │ ├── [ 302] Archive$Entry.class
+ │ ├── [ 437] Archive$EntryFilter.class
+ │ ├── [ 945] Archive.class
+ │ ├── [ 273] ExplodedArchive$1.class
+ │ ├── [1.1K] ExplodedArchive$FileEntry.class
+ │ ├── [1.5K] ExplodedArchive$FileEntryIterator$EntryComparator.class
+ │ ├── [3.7K] ExplodedArchive$FileEntryIterator.class
+ │ ├── [5.1K] ExplodedArchive.class
+ │ ├── [1.7K] JarFileArchive$EntryIterator.class
+ │ ├── [1.1K] JarFileArchive$JarFileEntry.class
+ │ └── [7.2K] JarFileArchive.class
+ ├── [ 224] data
+ │ ├── [ 485] RandomAccessData.class
+ │ ├── [ 282] RandomAccessDataFile$1.class
+ │ ├── [2.6K] RandomAccessDataFile$DataInputStream.class
+ │ ├── [3.2K] RandomAccessDataFile$FileAccess.class
+ │ └── [3.9K] RandomAccessDataFile.class
+ ├── [ 768] jar
+ │ ├── [4.9K] AsciiBytes.class
+ │ ├── [ 616] Bytes.class
+ │ ├── [3.0K] CentralDirectoryEndRecord.class
+ │ ├── [5.1K] CentralDirectoryFileHeader.class
+ │ ├── [4.5K] CentralDirectoryParser.class
+ │ ├── [ 540] CentralDirectoryVisitor.class
+ │ ├── [ 345] FileHeader.class
+ │ ├── [ 12K] Handler.class
+ │ ├── [3.5K] JarEntry.class
+ │ ├── [ 299] JarEntryFilter.class
+ │ ├── [2.0K] JarFile$1.class
+ │ ├── [1.2K] JarFile$2.class
+ │ ├── [1.3K] JarFile$JarFileType.class
+ │ ├── [ 15K] JarFile.class
+ │ ├── [1.6K] JarFileEntries$1.class
+ │ ├── [2.0K] JarFileEntries$EntryIterator.class
+ │ ├── [ 14K] JarFileEntries.class
+ │ ├── [ 702] JarURLConnection$1.class
+ │ ├── [4.2K] JarURLConnection$JarEntryName.class
+ │ ├── [9.6K] JarURLConnection.class
+ │ ├── [3.5K] StringSequence.class
+ │ └── [1.8K] ZipInflaterInputStream.class
+ └── [ 96] util
+ └── [5.1K] SystemPropertyUtils.class
+
+22 directories, 93 files
+
+```
+
+相比于`FAT JAR`的解压目录,`War`增加了`WEB-INF/lib-provided`,并且该目录仅有一个 jar 文件,即`spring-boot-test-2.1.1.RELEASE.jar`,这正是我们在 pom.xml 文件中设置的`scope`为`provided`的 jar 包。
+
+由此可以得出结论:**`WEB-INF/lib-provided`存放的是`scope`为`provided`的 jar 包**。
+
+我们现来看下`META-INF/MANIFEST.MF`的内容:
+
+```
+$ cat META-INF/MANIFEST.MF
+Manifest-Version: 1.0
+Built-By: fangchengyan
+Start-Class: com.gitee.funcy.maven.war.Main
+Spring-Boot-Classes: WEB-INF/classes/
+Spring-Boot-Lib: WEB-INF/lib/
+Spring-Boot-Version: 2.1.1.RELEASE
+Created-By: Apache Maven 3.6.0
+Build-Jdk: 1.8.0_222
+Main-Class: org.springframework.boot.loader.WarLauncher
+
+```
+
+可以看到,该文件与 jar 包中的`META-INF/MANIFEST.MF`很相似,在文件中同样定义了`Main-Class`与`Start-Class`,这也说明了该 war 可以使用`java -jar xxx.jar`和`java org.springframework.boot.loader.WarLauncher`启动,这也与我们的验证结果一致。
+
+### 4\. tomcat 等外部容器启动 war 包
+
+在 springboo 刚开始推广的时候,我们还是习惯于将项目打成 war 包,然后部署到 tomcat 等 web 容器中运行。那 springboot 的 war 包是如何做到既能用 java 命令启动,又能放在 tomcat 容器中启动呢?这就是之前提到的`WEB-INF/lib-provided`目录的功能了。
+
+传统的`servlet`应用的`class path`路径仅关注`WEB-INF/classes/`和`WEB-INF/lib/`,`WEB-INF/lib-provided/`目录下的 jar 包将被`servlet`容器忽略,如`servlet api`,该 api 由`servlet`容器提供。我们在打包时,可以把`servlet`相关 jar 包的`scope`设置成`provided`,这样就完美实现了`servlet`容器启动与`java`命令启动的兼容:
+
+* 当部署到`servlet`容器中时,`WEB-INF/lib-provided/`目录下的 jar 包就被容器忽略了(由于`servlet`容器本身就提供了`servlet`的相关 jar 包,如果不忽略,就会出现 jar 包重复引入问题);
+* 当使用`java`命令执行时,此时无`servlet`容器提供`servlet`的相关 jar 包,而`WarLauncher`在运行过程中会加载`WEB-INF/lib-provided/`目录下的 jar 包。
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/@SpringBootApplication\346\263\250\350\247\243.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/@SpringBootApplication\346\263\250\350\247\243.md"
new file mode 100644
index 0000000..dd72d1f
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/@SpringBootApplication\346\263\250\350\247\243.md"
@@ -0,0 +1,382 @@
+springboot ϻעһע⣺`@SpringBootApplication`˽Դ עá
+
+`@SpringBootApplication` £
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@SpringBootConfiguration
+@EnableAutoConfiguration
+@ComponentScan(excludeFilters = {
+ @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
+ @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
+public @interface SpringBootApplication {
+
+ /**
+ * ԶװҪų࣬ @EnableAutoConfiguration
+ */
+ @AliasFor(annotation = EnableAutoConfiguration.class)
+ Class>[] exclude() default {};
+
+ /**
+ * ԶװҪų @EnableAutoConfiguration
+ */
+ @AliasFor(annotation = EnableAutoConfiguration.class)
+ String[] excludeName() default {};
+
+ /**
+ * ɨİ @ComponentScan
+ */
+ @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
+ String[] scanBasePackages() default {};
+
+ /**
+ * ɨclassclassڵİᱻɨ裬 @ComponentScan
+ */
+ @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
+ Class>[] scanBasePackageClasses() default {};
+
+ /**
+ * Ƿ @Bean @Configuration
+ */
+ @AliasFor(annotation = Configuration.class)
+ boolean proxyBeanMethods() default true;
+
+}
+
+```
+
+1. `@SpringBootApplication` һע⣬ `@SpringBootConfiguration``@EnableAutoConfiguration``@ComponentScan` עĹܣ
+2. `@SpringBootApplication` ҲṩһЩԣЩע⡣
+
+ע÷ֱʲô
+
+### 1. `@SpringBootConfiguration`
+
+ `@SpringBootConfiguration`£
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Configuration
+public @interface SpringBootConfiguration {
+
+ @AliasFor(annotation = Configuration.class)
+ boolean proxyBeanMethods() default true;
+
+}
+
+```
+
+עȽϼ `@Configuration`Ȼһ `proxyBeanMethods()` `@Configuration`ˣ`@SpringBootConfiguration` ûʲôֻǽ `@Configuration` ʹ `@Configuration` Ĺܡ
+
+ `@Configuration` springܱ spring ʶΪ `Component` `proxyBeanMethods != false` ʱᱻ spring Ϊ `Full` ࣬ںе `@Bean` ʱ cglib ⷽݣɲο [ConfigurationClassPostProcessor @Bean ע](https://my.oschina.net/funcy/blog/4492878).
+
+### 2. `@EnableAutoConfiguration`
+
+`@EnableAutoConfiguration` Ҫ Զװ书ܣ£
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+// Զװİ
+@AutoConfigurationPackage
+// Զװ
+@Import(AutoConfigurationImportSelector.class)
+public @interface EnableAutoConfiguration {
+
+ String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
+
+ /**
+ * жųԶװ
+ */
+ Class>[] exclude() default {};
+
+ /**
+ * жųԶװ
+ */
+ String[] excludeName() default {};
+
+}
+
+```
+
+ӴпԿ
+
+1. ע `@AutoConfigurationPackage` עĹܣעָԶװİ
+2. עͨ `@Import` עһ `AutoConfigurationImportSelector`ԶװĹؼ
+3. עṩãųָԶװ࣬Ըų (`Class` )ҲԸ (`.`) ų
+
+ע `@AutoConfigurationPackage` `AutoConfigurationImportSelector`
+
+#### 2.1 `@AutoConfigurationPackage`
+
+`@AutoConfigurationPackage` ָԶװİ£
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@Import(AutoConfigurationPackages.Registrar.class)
+public @interface AutoConfigurationPackage {
+
+}
+
+```
+
+עݷdzʹ `@Import` ע `AutoConfigurationPackages.Registrar`ݣ
+
+```
+public abstract class AutoConfigurationPackages {
+
+ private static final String BEAN = AutoConfigurationPackages.class.getName();
+
+ static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
+
+ /**
+ * ImportBeanDefinitionRegistrar Ĵspring registerBeanDefinitions() ע
+ */
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata metadata,
+ BeanDefinitionRegistry registry) {
+ register(registry, new PackageImport(metadata).getPackageName());
+ }
+
+ @Override
+ public Set