了解自动配置原理
# 40.了解自动配置原理
通过上文的介绍,相信大家都知道使用SpringBoot是很方便的,这基于SpringBoot提供的两大特性:依赖管理,自动配置。
# 依赖管理
- 父项目做依赖管理
- 无需关注版本号,自动版本仲裁。也可以修改版本号
- 开发导入starter场景启动器
- ....
# 父项目做依赖管理
在Maven中,父项目常用做依赖管理。我们只需引入一个SpringBoot的父项目,就不用关心版本问题了。后续我们引入starter,都不用写版本号。
我们可以在IDEA中按住ctrl,然后点pom.xml文件中的父项目,可以看到父项目的内容:可以看到其还有一个父项目spring-boot-dependencies
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
2
3
4
5
# 版本号
我们再点进去,可以看到里面配置了很多properties:这就是配置了常用框架的版本号,包括Spring的,所以这也就是我们不用写版本号的原因。
<properties>
<activemq.version>5.15.13</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.82</appengine-sdk.version>
<artemis.version>2.12.0</artemis.version>
<aspectj.version>1.9.6</aspectj.version>
<assertj.version>3.16.1</assertj.version>
<atomikos.version>4.0.6</atomikos.version>
<awaitility.version>4.0.3</awaitility.version>
............
2
3
4
5
6
7
8
9
10
一般来说,这些配置好的版本号,也是SpringBoot支持的版本号;但开发中,有时候要改版本号(例如漏洞更新),怎么改呢?
- 首先查看spring-boot-dependencies中配置的版本号是什么,使用的是什么标签
- 在项目的pom.xml中配置properties标签,里面写上版本号即可。
例如使用MySQL5的驱动,可以搜到spring-boot-dependencies是通过<mysql.version>
这个标签来配置的,我们也使用该标签来改配置:
<properties>
<mysql.version>5.1.43</mysql.version>
</properties>
2
3
# starter场景启动器
有时候我们web开发,使用SpringMVC时,不仅仅要引入SpringMVC的框架,还要Spring的依赖,日志的依赖等等;
在SpringBoot中,将所有web开发场景的依赖都整合到了一起,也就是starter
。所以我们上一篇博客的案例,只引入spring-boot-starter-web
,就能将web开发所需要的依赖都引入!
在SpringBoot中,有很多这样的starter,官网 (opens new window)是这样说的:
Starters are a set of convenient dependency descriptors that you can include in your application. You get a one-stop shop for all the Spring and related technologies that you need without having to hunt through sample code and copy-paste loads of dependency descriptors. For example, if you want to get started using Spring and JPA for database access, include the
spring-boot-starter-data-jpa
dependency in your project.大意:Starters是一个集合,包含了某个场景的依赖。
一般来说,官方的starter都是spring-boot-starter-*
开头的,*
就代表着某种场景。
只要引入starter,这个场景的所有常规需要的依赖我们都自动引入。其实原理也很简单,就是该starter项目里,引入了一些依赖而已,这是Maven的依赖传递。
在文档下方,还列出了所有starter:几乎所有场景,SpringBoot都有对应的starter
Name | Description |
---|---|
spring-boot-starter | Core starter, including auto-configuration support, logging and YAML |
spring-boot-starter-activemq | Starter for JMS messaging using Apache ActiveMQ |
spring-boot-starter-amqp | Starter for using Spring AMQP and Rabbit MQ |
spring-boot-starter-aop | Starter for aspect-oriented programming with Spring AOP and AspectJ |
spring-boot-starter-artemis | Starter for JMS messaging using Apache Artemis |
spring-boot-starter-batch | Starter for using Spring Batch |
..... | ..... |
如果不满足你的需求,也可以自己写一个starter:Creating Your Own Starter (opens new window),一般命名为thirdpartyproject-spring-boot-starter
,当然一般用不上。
注意,所有starter的父项目都是spring-boot-starter
,这是SpringBoot自动配置的核心依赖
# 自动配置
通过上篇博客的案例,我们知道SpringBoot帮我们配置了很多东西,例如:
- 自动配好Tomcat
- 自动配好SpringMVC
- 自动配好Web常见功能(例如字符串编码)
- 默认的包结构
- 各种配置都有默认值
- 按需加载所有自动配置项
- .....
# 自动配好Tomcat
以Tomcat为例,自动配置,简单来说分为2步
- 引入Tomcat依赖
- 配置Tomcat
例如,spring-boot-starter-web
里,有这样的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
2
3
4
5
6
至于第二步怎么配置的,我们后续再说
# 自动配好SpringMVC
同理,spring-boot-starter-web
里,也有SpringMVC的依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.9.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
<scope>compile</scope>
</dependency>
2
3
4
5
6
7
8
9
10
11
12
我们之前使用SpringMVC,都要配置dispatcherServlet和characterEncodingFilter,那么SpringBoot有没配置呢?有的。我们修改下主程序,打印IoC容器里的内容:
package com.peterjxl.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/**
* 主程序类
* @SpringBootApplication 这是一个SpringBoot应用程序
*/
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
// 1.返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
// 2.查看容器里面的组件
String[] names = run.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
然后在打印的内容里,是能搜到dispatcherServlet和characterEncodingFilter的。
我们修改下controller,试着返回中文:
package com.peterjxl.boot.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController // @RestController = @Controller + @ResponseBody
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "你好, Spring Boot 2!";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
试着访问:
同理,还配置了viewResolver和multipartResolver等等组件。
# 默认的包结构
- 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来,无需以前的包扫描配置
- 想要改变扫描路径:
@SpringBootApplication(scanBasePackages="com.atguigu")
,或者用@ComponentScan
指定扫描路径
@SpringBootApplication
// 等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.peterjxl.boot")
2
3
4
5
When a class does not include a
package
declaration, it is considered to be in the “default package”. The use of the “default package” is generally discouraged and should be avoided. It can cause particular problems for Spring Boot applications that use the@ComponentScan
,@ConfigurationPropertiesScan
,@EntityScan
, or@SpringBootApplication
annotations, since every class from every jar is read................
he following listing shows a typical layout:
com +- example +- myapplication +- MyApplication.java | +- customer | +- Customer.java | +- CustomerController.java | +- CustomerService.java | +- CustomerRepository.java | +- order +- Order.java +- OrderController.java +- OrderService.java +- OrderRepository.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 各种配置都有默认值
举个例子,要配置上传文件的大小:
spring.servlet.multipart.max-file-size=10MB
我们可以按住ctrl 点进该配置项,可以看到其对应一个类:
@ConfigurationProperties(
prefix = "spring.servlet.multipart",
ignoreUnknownFields = false
)
public class MultipartProperties {
private DataSize maxFileSize = DataSize.ofMegabytes(1L);
.....
2
3
4
5
6
7
配置文件的值最终会绑定每个类上,这个类会在容器中创建对象(例如我们刚刚打印的内容中,就有MultipartProperties对象):
# 按需加载所有自动配置项
SpringBoot有很多的starter,难道全部都会加载配置吗?当然不是,引入了的starter,该starter的自动配置才会开启
每个starter都依赖于spring-boot-starter
,而其又依赖于spring-boot-autoconfigure
,(可以通过看pom.xml文件分析出),所有自动配置的功能就是由autoconfigure
来实现的
我们可以看这个jar包中的内容:
可以看到,这些就是各个starter的配置,例如amqp,cache等。
# 源码
已将本文源码上传到Gitee (opens new window)或GitHub (opens new window) 的分支demo2,读者可以通过切换分支来查看本文的示例代码