什么是 Spring Boot
Spring Boot 基本上是 Spring 框架的扩展,它消除了设置 Spring 应用程序所需的复杂例行配置。我们在使用 Spring 框架的时候,我们接触得比较多的应该是 Spring MVC、 IOC 、 DI 、AOP 等等,而这些框架在使用的过程中会需要配置大量的 XML,或者需要做很多繁琐的配置。Spring Boot 可以帮助我们快速搭建一个基于 Spirng 框架以及 Spring 生态体系的应用解决方案。

- 创建独立的 Spring 应用程序
- 直接嵌入Tomcat,Jetty 或 Undertow(无需部署 WAR 文件),java -jar 就可以运行
- 提供 starter 依赖来简化你自己的配置
- 自动装配 Spring 和第三方的依赖只要可能
- 提供可用于生产的功能,例如指标,运行状况检查和外部化配置,比如 Actuator
- 完全没有代码生成,也不需要 XML 配置
看了上面这么多主要有两点,约定大于配置 和 自动装配。
约定大于配置
约定优于配置的体现主要是
1、 maven 的目录结构,默认有 resources 文件夹存放配置文件,默认打包方式为 jar
2、 spring-boot-starter-web 中默认包含 spring mvc 相关依赖以及内置的 tomcat 容器,使得构建一个 web 应用更加简单
3、 默认提供 application.properties/yml 文件
4、 默认通过 spring.profiles.active 属性来决定运行环境时读取的配置文件
5、 EnableAutoConfiguration 默认对于依赖的 starter 进行自动装配
自动装配
讲自动装配首先从注解开始,我们从 @SpringBootApplication 点进去

1、 @Configuration
2、 @EnableAutoConfiguration
3、 @ComponentScan
我们可以直接用这三个注解也可以启动 Spring Boot 应用,只是每次配置三个注解比较繁琐,所以直接用一个复合注解更方便些。下面是官网的截图,刚兴趣的小伙伴可自行翻译。
@Configuration
@Configuration 这个注解大家应该都用过,它是 JavaConfig 形式的基于 Spring IOC 容器的配置类使用的一种注解。所以在启动类里面标注了 @Configuration,意味着它其实也是一个 IoC 容器的配置类。
传统意义上的 Spring 应用都是基于 xml 形式来配置 bean 的依赖关系。但是从 Spring3 开始,Spring 就支持了两种 bean 的配置方式,一种是基于 xml 文件方式,另一种就是 JavaConfig,任何一个标注了@Configuration 的 Java 类定义都是一个JavaConfig 配置类。而在这个配置类中,任何标注了@Bean 的方法,它的返回值都会作为 Bean 定义注册到 Spring 的 IoC 容器,方法名默认成为这个 Bean 的 id。然后通过 spring 容器在启动的时候,把 Bean 进行初始化并且,如果 Bean 之间存在依赖关系,则分析这些已经在 IoC 容器中的 Bean 根据依赖关系进行组装。
@ComponentScan
@ComponentScan 这个注解大家也用过,这个很简单,就是扫包,相当于 xml 配置文件中的
< context:component-scan > 。 它的主要作用就是扫描指定路径下的标识了需要装配的类,自 动装配到 Spring 的 IoC 容器中。
标识需要装配的类的形式主要是:@Component、@Repository、@Service、@Controller这类的注解标识的类。(注:@Repository、@Service、@Controller 的底层还是 @Component)。 ComponentScan 默认会扫描当前 package 下的的所有加了相关注解标识的类到 IoC 容器中。
@EnableAutoConfiguration
好,主角登场了,@EnableAutoConfiguration 是 Spring Boot 的灵魂,是重中之重。从 Spring3.1 开始,提供了一系列的 @Enable 开头的注解,它是在 JavaConfig 框架上更进一步的完善,使用户在使用 Spring 相关的框架避免配置大量的代码从而降低使用的难度。
比如常见的一些 Enable 注解:@EnableWebMvc、@EnableScheduling、@EnableAsync 等等。 每一个涉及到 Enable 开头的注解,都会带有一个 @Import 的注解, @EnableAutoConfiguration 也不例外,我们点进去发现如红框所示。

1、 普通 Bean 或者带有 @Configuration 的配置文件
2、 实现 ImportSelector 接口进行动态注入
3、 实现 ImportBeanDefinitionRegistrar 接口进行动态注入
这里导入的是第二种 importSelector,这是一种动态注入 Bean 的技术,我们把AutoConfigurationImportSelector 点进去,发现它实现了 ImportSelector 接口。

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
再从 getAutoConfigurationEntry 方法点进去,这里面做了许多事情,就是把找到的 Bean 进行排除、过滤、去重,我们可以看到 removeDuplicates、remove、filter 等方法。






| Conditions | 描述 |
|---|---|
| @ConditionalOnBean | 在存在某个 bean 的时候 |
| @ConditionalOnMissingBean | 不存在某个 bean 的时候 |
| @ConditionalOnClass | 当前 classpath 可以找到某个类型的类时 |
| @ConditionalOnMissingClass | 当前 classpath 不可以找到某个类型的类时 |
| @ConditionalOnResource | 当前 classpath 是否存在某个资源文件 |
| @ConditionalOnProperty | 当前 jvm 是否包含某个系统属性为某个值 |
| @ConditionalOnWebApplication | 当前 spring context 是否是 web 应用程序 |
好,有了上面这么多预备知识后,就可以开始手写一个我们自己的 starter 了。
手写 starter
starter 工程的命名
starter 是一个开箱即用的组件,减少不必要的重复代码,重复配置。例如,如果要使用 Spring 和 JPA 进行数据库访问,在项目中引用spring-boot-starter-data-jpa 即可。
Spring 官方定义的 starter 通常命名遵循的格式为 spring-boot-starter-{name},例如 spring-boot-starter-web。非官方 starter 命名应遵循 {name}-spring-boot-starter 的格式,例如,dubbo-spring-boot-starter。
需求
写一个序列化的插件,并且可以自由的选择 fastjson 还是 gson,如果没选的情况下默认选择fastjson。
步骤
1、 创建一个Spring Boot项目,这里项目名字叫 jackformat-spring-boot-starter
2、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 这个是用来提示用的-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
3、先定义一个格式化的接口,分别写两个实现类
public interface FormatProcessor {
/**
* 定义一个格式化的方法
*
* @param obj
* @param <T>
* @return
*/
<T> String format(T obj);
}





测试
1、将自己的 starter 项目进行 install 打包

3、写一个controller,一个测试类,并把 formatTemplate 注入进来
4、设置我们需要制定的序列化方式,这里选用 fastjson





后记
小伙伴们,Spring Boot 的使用中极大的简化了我们的使用,我也是14年毕业就开始用 SSM,那时候各种配置各种依赖,各种 XML 很是恶心。但是现在有了 Spring Boot 在几分钟内就可以让我们快速搭建一个项目跑起来,时代在变迁,也感谢让我们越来越便利,在便利的过程中,我们还是要对底层的原理有一点的了解,而不是浮在上面只会使用,否则一但有问题找起来也不方便。
本文带大家对 Spring Boot 底层入了个门,还有 SringApplication 实例创建,设置初始化器和监听器,以及 run 方法里干的一些事,内置 Tomcat 如何实现的,由于篇幅有限都没有讲,留给小伙伴自行研究。最后原创不易,如果觉得写得不错,请点一个赞!








