Spring Boot 是一套 Java 开发框架,可以快速构建基于 Spring 生态的 Java Application,实现自动配置,作为 Java 领域最火的技术栈,我们有必要搞清楚 Spring Boot 的底层原理,今天楠哥就带大家一探究竟。
Spring Boot 核心配置
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
spring-boot-starter 是 Spring Boot 提供的场景启动器,通过 starter 导入不同场景下所需要的 jar 包,如 web、dao 等。
spring-boot-starter-{name} 是 Spring 官方提供的启动器,如 spring-boot-starter-parent,{name}-spring-boot-starter 是第三方提供的启动器,如 mybatis-spring-boot-starter。
spring-boot-starter-parent 是 Spring Boot 的父级启动器,Spring Boot 相当于一个大的组件集合,将 Spring 家族组件及第三方组件全部进行了集成,开发者只需要通过配置 spring-boot-starter 就可以将所需组件配置到项目中,直接使用,这就是开箱即用。
打开 spring-boot-starter-parent 源码,可以看到 resource 中配置了 Spring Boot 默认会读取的资源文件。
<resource>
<filtering>true</filtering>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>**/application*.yml</include>
<include>**/application*.yaml</include>
<include>**/application*.properties</include>
</includes>
</resource>
所以 Spring Boot 默认加载的配置文件是 src/main/resources 路径下名为 application 的 yml、yaml、properties 文件。
同时 spring-boot-starter-parent 中又引入了 spring-boot-dependencies 依赖。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
打开源码,如下所示。
<properties>
<activemq.version>5.15.11</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.77</appengine-sdk.version>
<artemis.version>2.10.1</artemis.version>
<aspectj.version>1.9.5</aspectj.version>
......
</properties>
可以看到 Spring Boot 2.2.2 版本自动集成的各种组件的版本,对应的 jar 依赖都会自动导入到当前工厂,starter 就这样帮助我们非常方便的引入了项目所需要的各种 jar 包。
Spring Boot 自动配置类
传统的 Spring 应用中,各个组件对象的管理全部交给 Spring IoC 容器,我们需要在 application.xml 中配置多个 bean,以完成组件对象的注入。
而在 Spring Boot 中,这些配置是自动注入的,并不需要开发者配置任何一个 bean,如何实现?定义一个自动配置的类,通过加载这个类来读取各种配置信息,用来替代 XML 的配置文件,这里用到两个核心注解 @Configuration 和 @Bean。
@Configuration 注解标明该类是一个配置类,@Bean 注解表示该方法返回的对象就是一个要交给 Spring IoC 容器管理的 bean 实例。
一个 @Bean 就相当于传统的 application.xml 中配置的一组 <bean/> 。
XML 配置方式
1、实体类。
@AllArgsConstructor
public class User {
private Integer id;
private String name;
}
2、配置文件。
<beans>
<bean id="user" class="com.southwind.entity.User">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
</bean>
</beans>
3、获取 bean。
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
}
基于配置类的方式
1、创建配置类。
@Configuration
public class MyConfiguration {
@Bean(name = "user")
public User getUser(){
return new User(1,"张三");
}
}
2、获取 Bean。
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfiguration.class);
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
}
Spring Boot 源码解析
Spring Boot 自动装配主要完成两件事:
1、自动装置开发者自定义的业务组件(Handler、Service、Repository 等 bean)。
2、根据开发者的设置进行自动配置(比如集成 MyBatis,自动配置 DataSource、SqlSessionFactory 等 bean)。
Spring Boot 最大的特点就是可以完成自动配置,简单讲就是之前需要开发者手动配置的各种 bean,现在 Spring Boot 全部自动完成,并且是基于 JavaConfig 的形式,即用标注了 @Configuration 的类来替代 XML,Spring Boot 最核心的注解是 @SpringBootApplication。
@SpringBootApplication 注解
该注解实际由 3 个核心注解组成:
1、@SpringBootConfiguration
2、@EnableAutoConfiguration
3、@ComponentScan
@SpringBootConfiguration 实际上还是使用了 @Configuration,Spring 官方推荐使用 @Configuration 配置类的形式来替代 XML 的配置方式,启动类标注了 @Configuration 注解之后,也就成为了 IoC 的配置类。
@ComponentScan 这个注解的功能是自动扫描并加载符合条件的组件(比如开发者自定义的业务组件,@Component 和 @Repository等),可以通过 basePackages 属性来制定扫描的范围,如果不指定,默认从 @ComponentScan 所在类的 package 向下进行扫描。
@EnableAutoConfiguration 就是完成自动配置的,会根据类路径中引入的 jar 依赖为项目自动配置,比如添加了 spring-boot-starter-web 依赖,Spring Boot 就会自动添加 Spring MVC 相关 jar,并且会自动对 Spring MVC 进行配置(DispatcherServlet、ViewResolver )。
@EnableAutoConfiguration 是如何完成自动配置的呢?
核心注解是 @Import(EnableAutoConfigurationImportSelector.class),具体流程如下:
1、EnableAutoConfigurationImportSelector 中返回符合条件的 @Configuration 类信息。
2、@Import 通过加载 EnableAutoConfigurationImportSelector,将所有符合条件的 @Configuration 配置都加载到当前 Spring Boot 创建并使用的 IoC 容器中。
我们通过一个例子来搞清楚 @Import 的使用。
User
package org.southwind.entity;
@Data
public class User {
@Value("1")
private Integer id;
@Value("张三")
private String name;
}
MyImportSelector
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"org.southwind.entity.User"};
}
}
MyImportConfig
@Import(MyImportSelector.class)
public class MyImportConfig {
}
Test
public class Test {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MyImportConfig.class);
System.out.println(context.getBean("org.southwind.entity.User"));
}
}
运行结果如图所示。
可以得出结论,Spring Boot 自动配置的类都是通过 EnableAutoConfigurationImportSelector 获取的,那么问题来了,EnableAutoConfigurationImportSelector 是如何返回 Spring Boot 所需要的 @Configuration 类呢?
这里需要使用 SpringFactoriesLoader 来完成,SpringFactoriesLoader 属于 Spring 框架私有的一种扩展方案,其主要功能就是从指定的配置文件 META-INF/spring.factories 加载配置。
它在这里的工作是通过 @EnableAutoConfiguration 的完整类名 org.springframework.boot.autoconfigure.EnableAutoConfiguration 作为 Key,在 META-INF/spring.factories 查找对应的一组 @Configuration 类。
通过这种方式,让 Spring Boot 读取到所有符合条件的 @Configuration 配置类,并通过反射机制实例化 bean 并加载到 IoC 容器中,这样就实现了自动配置。
推荐阅读
1、一次性把JVM讲清楚,别再被面试官问住了
2、学会GC,直接吊打面试官
3、一文搞懂前后端分离
4、快速上手Spring Boot+Vue前后端分离
博主简介:楠哥,资深 Java 工程师,《Java 零基础实战》一书作者,今日头条认证大 V,GitChat 认证作者,B 站 UP 主(楠哥教你学 Java),微信号 nnsouthwind,致力于帮助万千 Java 学习者持续成长。
有收获,就点个在看