介绍
? Spring boot用于简化Spring应用的开发。因为使用spring需要定义很多样板化的配置随着项目的增大,那么配置信息会变得越来越多,从而导致项目越来越难以维护。所以就出现了spring boot用于解决这个问题。spring boot基于习惯优于配置的理念由Spring 扩展而来。使用spring boot之后我们需要什么功能那么我们只需要通过maven导入相应的组件依赖,也就是一个个的spirng-boot-starter-xxx 。那么大量的配置就都会给我们配置好,这些spirng-boot-starter会给我们提供对应的自动配置类,然后这些自动配置类会根据当前环境向容器注入一些列配置好的bean。当然如果默认配置生成的bean中的某些属性不符合我们的要求那么我们可以在配置文件中对对应的属性进行修改,因为自动配置模块中通常都会有相应的Properties属性配置类,这些属性配置类会自动注入配置文件中对应的配置。而自动配置类向容器注入bean的时候会将属性配置类中的属性设置到对应的bean中。
spring boot自动配置原理
在springboot项目的主程序类中,我们都会加上一个@SpringBootApplication 注解,这个注解主要由3个注解组成,分别是
@SpringBootConfiguration :他其实就是一个@Configuration 注解,所以springboot的主程序类也是一个配置类。@ComponentScan :用于组件扫描,默认情况下会扫描当前包及其子包中所有的组件@EnableAutoConfiguration :启用自动配置,在这个注解中会通过@Import 导入AutoConfigurationImportSelector 。在IOC容器初始化的过程中(调用BeanDefinition后置处理器的时候)springboot2.0系列及以下的版本会调用AutoConfigurationImportSelector 的selectImports 方法,而springboot2.1系列及以上版本会调用getAutoConfigurationEntry 方法。虽然他们调用的方法不同但是最终都是去所有jar包中读取META-INF/spring.factories 文件中EnableAutoConfiguration所对应的值。这些值就是starter中提供的自动配置类的类名。然后再根据当前的环境对自动配置类进行过滤,从而获取到当前需要启用的自动配置类。最后通过自动配置类向容器中注入一系列配置好的bean。
META-INF/spring.factories 文件是通过类加载器进行加载的,类加载器可以直接加载资源路径中的资源- 过滤自动配置类的时候他同样会去
META-INF/spring.factories 文件中获取key为AutoConfigurationImportFilter 所对应的过滤器,因为在编写自动配置类的时候我们会在自动配置类上添加Condition相关注解来指定在什么情况下使用自动配置。所以过滤器就可以根据这些注解进行过滤 - 自动配置类提供的bean通常都会有对应的
Properties 属性配置类。这些属性配置类会注入配置文件中对应的值。所以当自动配置的属性不符合我们要求的时候我们可以直接在配置文件中进行修改。
spring boot启动流程
- 当我们在主程序类中调用SpringApplication的run方法之后,他会先创建SpringApplication对象,然后再调用对象的run方法
- 创建SpringApplication对象的时候他会获取当前项目的类型,然后读取所有jar包中的
META-INF/spring.factories 文件中定义的ApplicationContextInitializer 和ApplicationListener 所对应的类,之后再设置对应的初始化器以及监听器 - 在SpringApplication的run方法中首先会获取事件然后发布相关事件,此时在创建SpringApplication时添加的监听就会被触发
- 然后再创建并配置当前应用的环境(Environment),Environment中包含profile以及properties等等。创建Environment之后后面就可以从Environment中获取资源了
- 然后打印输出当前项目的Banner图标
- 在根据是否是web项目,来创建不同的ApplicationContext容器。如果是web项目创建的ApplicationContext容器为
AnnotationConfigServletWebServerApplicationContext ,否则创建AnnotationConfigApplicationContext - 然后获取异常报告事件监听,在对容器进行配置,包括将前面创建的Environment设置给容器,调用所有ApplicationContextInitializer的
initialize() 方法,以及发布相关事件等等 - 之后在刷新容器,刷新容器就是执行
AbstractApplicationContext 中的refresh() 方法。spring 容器初始化的时候也是调用这个方法。
- 在方法中他会加载BeanDefinition,注册并调用所有的BeanFactoryPostProcessors、BeanPostProcessors。发布一系列事件以及实例化非延迟加载的单例bean等等。
- 其中在refresh方法中他会调用
onRefresh 方法,这个方法用于让对应的ApplicationContext实现类进行其他操作,在springboot中ApplicationContext的实例属于AnnotationConfigServletWebServerApplicationContext 。而他的onRefrsh方法定义在他的父类也就是ServletWebServerApplicationContext 中。在ServletWebServerApplicationContext 的onRefresh中会创建并启动servlet容器,默认的servlet容器为内置的tomcat - 最后获取并执行容器中的Runner(包括ApplicationRunner和CommandLineRunner),以及触发相关事件
以上是我对于Spring Boot的理解的简单概述,具体可以参考源码或官网中的介绍
使用
引入spring boot
在maven中引入spring boot,我们只需要创建好maven项目然后再pom文件引入spring boot的依赖,然后再添加一个项目入口就行了,当然我们还可以借助spring boot的官网工具直接创建项目。
其中spring-boot-starter-parent的作用是:
- 定义了一些规范,例如指定jdk版本,字符编码等等
- 定义了spring-boot-starter-xxx的版本
- 打包操作配置、资源过滤配置以及插件配置等等
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>javaspringboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
@SpringBootApplication
public class JavaspringbootApplication {
public static void main(String[] args) {
SpringApplication.run(JavaspringbootApplication.class, args);
}
}
当如果我们项目需要继承多个pom,那么就不能在使用parent 标签,而应该使用<scope>import</scope> 的方式导入依赖,这样就可以实现多继承了
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Starters
spring boot中提供了很多的starter依赖项,在starter中引入了相关技术所需的相关依赖以及跟spring整合后的初始化配置。
其中官方发布的starter依赖项命名格式都是spring-boot-starter-项目名称 。而第三方发布的starter的命名格式都是第三方项目-spring-boot-starter 。官方提供了哪些starter可以参考官网,而第三方提供的starter可以参考spring官方统计,当然这个并不是完整的。因为第三方的start实在太多了
SpringApplication
SpringApplication用于在main方法中启动spring应用程序。我们可以直接通过他的静态run方法来启动,也可以创建SpringApplication对象然后再调用run方法来启动。并且创建对象后我们还可以手动设置一些特性
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(JavaspringbootApplication.class);
springApplication.run(args);
}
SpringApplication可以设置的特性包括
- 将所有的bean设置为懒加载,可以调用SpringApplication的
setLazyInitialization(true) 。当然也可以通过配置文件中的属性设置spring.main.lazy-initialization=true - 设置项目启动时的Banner也就是项目启动是控制台中的文字logo。不过这个也可以通过配置文件的
spring.banner.location 设置。他默认会加载资源路径下名为banner.txt 的文件作为启动时的文字logo,当然存在这个文件才会使用,不存在就默认用springboot的logo - SpringApplication会根据当前环境引入的start选择合适的ApplicationContext(IOC容器)。
- 如果存在spring mvc,ApplicationContext为
AnnotationConfigServletWebServerApplicationContext - 如果不存在spring mvc但是存在Spring WebFlux,ApplicationContext为
AnnotationConfigReactiveWebServerApplicationContext - 其他情况下ApplicationContext为
AnnotationConfigApplicationContext - 当然我们也可以通过SpringApplication的
setWebApplicationType(WebApplicationType) 来设置想要的ApplicationContext - 如果我们想要访问
springApplication.run(args) 中传递的参数,我们可以注入ApplicationArguments对象 - 如果我们想要在SpringApplication执行run方法后运行某些特定代码。那么我们可以实现 ApplicationRunner 或 CommandLineRunner 接口。 这两个接口的工作方式相同,并提供一个 run 方法,该方法在
SpringApplication.run(... ) 完成之前调用
详细参考官网
外部化配置
在spring boot中可以使用外部化配置,以便在不同环境中使用相同的应用程序代码。我们可以通过配置文件(.properties或.yml)、环境变量和命令行参数来进行外部化配置。配置的属性值可以通过@Value 注释直接注入到 bean的属性中,通过 Spring 的 Environment 抽象访问,或者通过 @ConfigurationProperties 绑定到结构化对象。
在spring boot中通常我们都是通过java的方式进行配置。不过如果我们要-使用xml的配置也是可以的,使用xml配置文件我们只需要在@Configuration 类上额外添加@ImportResource 注解来加载xml配置文件即可,例如@ImportResource("classpath:/spring/spring-config.xml")
配置加载位置
外部配置可以从多个位置读取,具体可以参考官网中列出的顺序,越先列出的优先级越高。
常用的包括,优先级由低到高:
- 项目中application.properties或application.yml中定义的配置
- 项目中application-{profile}.properties 和 application-{profile}.yml定义的配置
- Java 系统属性,也就是
java -D 传递的参数
- 例如:
java -DtestBean.id='123' -jar myapp.jar - 通过spring.application.json传递的json格式参数,可以通过环境变量、系统属性或命令行方式传递
- 例如系统属性方式传递:
java -Dspring.application.json='{"name":"test"}' -jar myapp.jar - 例如命令行方式传递:
java -jar myapp.jar --spring.application.json='{"name":"test"}' - 命令行属性,命令行属性就是通过
-- 传递的属性
- 例如:
java -jar myapp.jar --server.port=9000
application配置文件
application配置文件有两种可以是一个.properties 文件也可以是.yml 文件。为了更方便通常采用的都是.yml 文件
并且配置文件中可以通过${} 来引用当前文件中定义的属性
application配置文件位置
application配置文件的位置会影响他的优先级,高优先级的会覆盖低优先级的配置。
springboot中默认会加载配置名称为application.properties或application.yml的配置文件。加载的位置为,优先级由高到低:
- 项目根目录(与src平级)下
config 文件夹中的配置文件 - 项目根目录(与src平级)中的配置文件
- classpath下
config 文件夹中的配置文件 - classpath中的配置文件
如果我们想改变配置文件的名称,我们可以通过spring.config.name 进行修改。或者通过spring.config.location 来指定加载的文件(多个用逗号分隔)或目录(目录中的所有文件)。或通过spring.config.additional-location 来指定额外的配置文件。不过需要注意的是这些配置得在命令行中设置。在配置文件中配置无效,因为他读取配置文件之后属性就无效了。不过修改配置文件的名称通常不怎么常用
profile环境配置
profile环境配置有两种实现方法,一种是启动时指定application-{profile}文件。一种是使用.yml格式的文件并定义多段profile。当然使用的时候最好不要两种混合使用
- 启动时指定application-{profile}文件
- 我们可以根据不同的环境定义多个application-{profile}文件,然后启动时我们可以通过在命令行中或application文件中设置
spring.profiles.active=profile 来加载指定的application-{profile}文件。并且application-{profile}文件的位置加载顺序跟application的位置一致,application-{profile}中的属性会覆盖原有application中的属性,如果application-{profile}中的属性没有定义则会使用application中的属性 - .yml格式定义多段profile
- 在yaml配置文件中可以通过
--- 来将文件分割为多段。默认会使用第一段配置。除了第一段其他的配置段可以通过spring.profiles 来指定当前配置段的标识,并且spring.profiles 的值还支持&,|,! 的逻辑运算,当然通常不会使用逻辑运算。之后我们可以在第一配置段中通过spring.profiles.active 指定需要启用的配置段的标识。 - 当第一配置段中没有通过
spring.profiles.active 指定需要启用的配置段的标识。那么就会默认启用一个spring.profiles=default 的配置段,相当于默认进行了这个配置。并且当启用其他配置段之后,如果其他配置段中定义的属性跟第一配置段中定义的属性一致,那么其他配置段的属性就会将第一配置段中的属性覆盖,具体合并规则可以参考官网。根据官网的介绍对象和map类型只需要属性相同就覆盖否则合并,而对于集合会将整个集合覆盖而集合中的元素不会合并 - 当使用环境配置之后如果我们想让某些bean只在对应的环境启用,那么我们可以通过
@Profile("pro") 来标注bean
注入配置外部化配置
要将外部化配置注入bean中,我们可以通过@Value("${property}") 或通过@ConfigurationProperties("配置前缀") 来实现。
其中@Value("${property}") 直接添加在bean的属性上,而@ConfigurationProperties("配置前缀") 添加在类上。不过需要注意的是@Value("${property}") 无法注入对象引用类型的值,而@ConfigurationProperties("配置前缀") 可以
abean:
id: 1
name: 111
bbean:
id: 2
name: 222
@Component
public class Abean {
@Value("${abean.id}")
private Integer id;
@Value("${abean.name}")
private String name;
private Bbean bbean;
}
使用@ConfigurationProperties("配置前缀") 的时候还可以让属性通过构造函数注入。让配置类通过构造函数注入属性那么我们提供对应的构造函数后,在类或构造器上额外添加@ConstructorBinding 注解就可以了。并且在构造器的参数列表中还可以通过@DefaultValue("valueStr") 注解指定默认值,其中valueStr为一个字符串他会根据参数类型自动进行转换。
不过需要注意的是如果要使用构造函数进行注入,那么这个类就不能通过@Component 或@Bean 注解交给spring容器管理。要使用构造函数注入,必须使用@enableconconfigurationproperties 或配置属性扫描@ConfigurationPropertiesScan 来启用类
并且@ConfigurationProperties 还可以跟@Bean 方法一起使用。这通常用于设置第三方类的属性。当@ConfigurationProperties 跟@Bean 一起使用后会将配置文件中配置的属性注入到方法返回的对象属性中。
@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
...
}
创建配置类
当一个类添加@ConfigurationProperties 就可以将配置文件中定义的值注入到对应的属性中了。而实例化标注了@ConfigurationProperties 的类可以有多种方式,其中包括:
- 在配置类上添加
@Component 或交给@Bean 实例化并加入spring 容器。不过如果使用这种方式那么就无法使用构造函数进行配置属性注入 - 在
@Configuration 类上添加@ConfigurationPropertiesScan(包名) 来扫描对应的包。如果包下的类添加了@ConfigurationProperties 那么就会将这个类实例化并加入spring容器 - 在
@Configuration 类上添加@EnableConfigurationProperties(.class) 来指定实例化对应的配置类。 - 不过需要注意的是:使用
@ConfigurationPropertiesScan() 或@EnableConfigurationProperties() 来实例化配置类,默认实例化后bean的名称为@ConfigurationProperties 中指定的前缀-类全路径名
属性转换
时间转换
在spring boot中支持通过java.time.Duration 表示时间(也可以说是时间段,jdk8新增的时间类型)。所以对于时间段的值我们可以在配置中将类型定义为java.time.Duration 。单位默认为毫秒。如果我们想定义其他类型那么可以通过@DurationUnit 注解进行修改
@ConfigurationProperties("app.system")
public class AppSystemProperties {
private Duration readTimeout = Duration.ofMillis(1000);
@DurationUnit(ChronoUnit.SECONDS)
private Duration sessionTimeout = Duration.ofSeconds(30);
}
配置文件中定义时间段的值
app:
system:
read-timeout: 100
session-timeout: 10s
在配置文件中如果不带单位则使用配置类中指定的单位。如果带单位那么就使用指定的单位。并且获取属性的时候可以直接通过Duration类型获取各种单位的值。
其中配置文件中单位的简写为:
ns 纳秒us 微秒ms 毫秒s 秒m 分h 时d 天
数据大小转换
跟时间转换类似spring boot中对于数据大小我们可以通过org.springframework.util.unit.DataSize 来表示。单位默认为byte字节。如果我们想定义其他单位类型可以通过@DataSizeUnit 来修改
@ConfigurationProperties("app.io")
public class AppIoProperties {
private DataSize sizeThreshold = DataSize.ofBytes(512);
@DataSizeUnit(DataUnit.MEGABYTES)
private DataSize bufferSize = DataSize.ofMegabytes(2);
}
在配置文件中我们可以添加单位也可以不添加单位,添加后就使用指定单位,不添加则使用默认的。其中配置文件中支持的单位包括:
B 字节 bytesKB 千字节 kilobytesMB 兆字节 megabytesGB 千兆字节 gigabytesTB 兆兆字节 terabytes
日志
java中日志框架有很多种,而每一种的使用方法都不相同。为了解决这个问题,就抽象出了一套接口规范例如像slf4j,jcl之类的,他们的实现也有很多例如log4j,logback之类的,我们在开发的时候就只需要导入相应接口以及实现就可以了,如果到时候需要换别的日志框架,那就把以前的日志的实现包给换掉,并且如果有需要还可以添加原有接口和新增日志框架的转换包就可以了
? Spring boot所使用的日志框架默认是slf4j和logback的组合。因为Spring boot要和其他的框架整合,那就会出现一个问题。就是spring boot用的日志框架实现是logback,而其他框架用的又是其他框架的实现。这样就不能统一日志记录了。为了解决这个问题。Spring boot给了一个方案就是,如果导入的框架使用了和spring boot不同的日志实现。那么在导入其他框架的时候先将这个框架中依赖的日志框架实现给剔除然后替换为一个原有日志门面和slf4j的转换中间包。这样其他框架在调用日志记录的时候实际调用的就是slf4j,然后再通过slf4j调用logback,这样就可以统一日志记录了。当然如果你不想要logback作为日志实现,只需要在maven依赖中将logback剔除导入其他的日志实现以及他和slf4j的中间包就可以了。
spring boot中默认的日志级别为Info并输出日志到控制台。如果想输出更多spring boot的日志我们可以通过在配置文件中设置debug=true 来输出更多的spring boot日志。但是这个设置并不会影响我们程序的日志他只会影响spring boot的内部日志。
如果我们想让日志输出到日志文件中,那么我们可以设置logging.file.name 指定日志文件名称或 logging.file.path 指定日志文件路径。来将日志记录到对应的文件中。当然还可以设置更多的规则,例如设置日志在指定大小后将日志输出到另一个文件中,具体可以参考官网
日志设置
因为配置文件中debug=true 只能设置spring boot内部日志的级别,如果我们想配置我们应用程序的日志级别可以通过logging.level.*=level 来进行配置,其中* 可以是一个包路径也可以是root(root表示全局),level 为设置的日志级别,例如logging.level.org.springboot.test=debug
日志级别有6个,从低到高分别是:track、debug、info、warn、error、fatal 。在设置某个级别后低于这个级别的日志将不会输出。
当我们需要给多个包设置相同的日志级别,我们可以先将这些包进行分组,然后再对每个组设置日志级别。分组我们可以通过logging.group.name 来设置,其中name为组名称我们可以自定义。例如
# 将几个包名分成一组
logging.group.tomcat=org.apache.catalina, org.apache.coyote, org.apache.tomcat
# 根据组设置日志级别
logging.level.tomcat=DEBUG
自定义日志
spring boot中除了使用默认提供的日志,我们还可以自定义日志配置文件实现自定义日志。具体可以参考日志博文或官网文档。其中日志博文中记录了自定义logback的配置。
使用自定义日志配置,我们只需要在资源文件路径下提供指定名称的配置文件就可以了,这些配置文件会被spring boot自动加载
Spring MVC
spring boot中默认会对spring mvc进行了一些自动配置,例如对静态资源以及webjars的支持、自动注册了Converter和Formatter相关的bean等等。
在spring boot的自动配置中。如果我们想添加其他的MVC配置(拦截器,格式化处理器,视图控制器等)。可以添加自己的WebMvcConfigurer 类型的@Configuration类。
如果希望使用自定义的RequestMappingHandlerMapping,RequestMappingHandlerAdapter,或ExceptionHandlerExceptionResolver,我们可以声明一个WebMvcRegistrations 类型的实例提供这些组件
如果想全面控制Spring MVC,可以添加自己的@Configuration,并使用@EnableWebMvc注解。所以一旦使用了@EnableWebMvc注解那么spring boot提供的自动配置将会失效。不过通常直接使用spring boot提供的spring mvc的配置就可以了
静态资源
默认情况下spring mvc会在classpath下的/META-INF/resources/、/resources/、/static/、/public/ 中匹配静态资源。而静态资源匹配规则为/** 也就是匹配所有请求。
如果我们需要修改静态资源的位置可以通过spring.resources.static-locations 属性进行修改。不过由于修改会替换原有的路径所以我们通常的做法是在原来的基础上添加我们的自定义位置,也就是把原有的位置写一遍,例如:spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:/mypath
如果需要修改静态资源匹配规则可以通过spring.mvc.static-path-pattern 修改
webjars
在spring boot中提供webjars用于直接在java中导入静态,也就是通过maven导入静态资源例如jquery之类的(仓库位置)。例如导入jquery
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
那么我们访问的时候直接通过/webjars/jquery/3.6.0/jquery.min.js 就可以直接访问了。
如果我们不想在url中写版本那么我们可以额外导入webjars-locator-core 依赖。导入依赖后url就变成了/webjars/jquery/jquery.min.js
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
<version>0.46</version>
</dependency>
不过需要注意的是在jboss中导入的是webjars-locator-jboss-vfs
错误处理
Spring Boot默认提供一个/error映射用来以合适的方式处理所有的错误,并将它注册为servlet容器中全局的错误页面。对于浏览器客户端返回返回一个错误页面,而对于其他客户端他会返回json格式的错误信息。
如果我们想自定义json格式的错误信息可以通过spring mvc的@ExceptionHandler 全局异常处理然后自定义返回的json数据。
如果我们想自定义错误页面只需要在静态资源文件夹下/error 文件夹中创建对应的状态码.html 就可以了,当然不一定必须是html,当使用模板引擎后可以是模板文件
嵌入式servlet容器
spring boot中支持的嵌入式servlet容器有三种分别是:Tomcat, Jetty, Undertow。如果需要对他们进行切换只需要修改maven的依赖就行了,如果要对他们进行属性的配置,那么可以在配置文件中进行配置,配置属性为:server.xxx ,当然配置的时候也可以通过编程的方式进行配置,不过通常都是基于配置文件进行配置,具体可以参考官网
spring boot默认使用的嵌入式servlet容器为Tomcat。如果要替换为其他的直接修改maven依赖就行,例如替换为Jetty
<!‐‐ 引入web模块 ‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring‐boot‐starter‐tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!‐‐引入其他的Servlet容器‐‐>
<dependency>
<artifactId>spring‐boot‐starter‐jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
注册Servlet组件
在spring boot的嵌入式servlet容器中注册Servlet、Filter 或 Listener。我们可以通过ServletRegistrationBean 、FilterRegistrationBean 和 ServletListenerRegistrationBean 进行注册以及配置。如果我们直接将Servlet、Filter 或 Listener提供给spring 容器那么他们将会被自动注册。但是自动注册通常不符合我们的要求,所以注册的时候建议通过前面提到的xxxRegistrationBean 进行注册。
例如
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter());
registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
return registrationBean;
}
还有一种注册方法是通过注解方式进行注册,其中包括@WebServlet, @WebFilter, @WebListener ,然后再配置类中通过@ServletComponentScan 进行扫描
使用外部servlet容器
spring boot默认使用的是嵌入式的servlet容器,不过嵌入式的servlet容器spring boot只提供了三种。当我们想要使用其他的servlet容器,例如jboss或weblogic,那么就可以使用外部servlet容器。
使用外部的servlet容器我们需要:
- 将项目的打包方式改为war
- 修改tomcat starter也就是
spring-boot-starter-tomcat 依赖的作用域为provided - 编写一个
SpringBootServletInitializer 的子类,并在重写的configure方法中通过SpringApplicationBuilder调用sources方法传入spring boot的主程序类
在springboot中使用jar包和使用war包的启动方式是不同的
- 使用jar包形式应用启动流程:执行springboot主类的main方法—>启动IOC容器—>创建嵌入式servlet容器
- 使用war包形式应用启动流程:启动servlet服务器—>服务器启动springboot应用—>创建IOC容器
缓存
? 要使用spring boot的缓存只需要引入缓存的依赖spring-boot-starter-cache 然后在配置类上添加@EnableCaching 就可以了,他使用spring的缓存抽象来统一不同的缓存技术。并支持使用缓存注解简化我们开发;他就类似于jdbc统一了数据库的操作。在spring的缓存抽象中包括cacheManager缓存管理器和Cache组件。其中cacheManager用于管理Cache组件,而Cache组件则用于具体的缓存操作。
? 如果在springboot中使用了缓存但是不对cache做任何配置spring boot默认使用的自动配置类是SimpleCacheConfiguration,而他使用的cacheManager是ConcurrentMapCacheManager,这个manager创建的cache组件是ConcurrentMapCache,然后在通过ConcurrentMapCache对ConcurrentMap进行一系列操作。
? 如果我们不想使用他默认的缓存,例如我们想要使用redis,那么我们只需要引入redis的start(spring-boot-starter-redis ),并且把redis配置好就可以使用了。使用redis那么他使用的manager就是redisCacheManager,然后创建的cache组件就是RedisCache,然后再通过RedisCache对redis数据库进行一系列操作。当然默认情况下使用redis它使用的序列化为jdk的序列化方式,所以在redis中没法正常查看存储的数据。如果我们想让他以json字符串的格式存储那么可以自己创建一个RedisCacheManager并修改他的序列化方式
其中缓存注解是spring提供的并不是spring boot提供的其中缓存注解包括:
- @CacheConfig:用于类上进行一些公共的缓存配置
- @Cacheable:能够根据方法的请求参数对其结果进行缓存
- @CachePut:用于更新缓存
- @CacheEvict:用于删除缓存
- @Catching:用于组合多个缓存
自定义starter自动配置类
在编写自定义starter的时候spring boot官方的建议是一个自定义starter应该包含一个starter 模块和一个autoconfigure 模块,其中starter模块用于包含autoconfigure模块以及其他所需包的依赖。而autoconfigure模块则用于提供具体的自动配置。所以导入我们自定义的starter只需要导入starter模块的依赖就可以了。
autoconfigure模块中主要的功能就是向spring容器中注册AutoConfiguration自动配置类,然后自动配置类用于向spring容器中注册各种bean(所以自动配置类其实就是一个@Configuration注释的配置类),并且在向spring容器中注册自动配置类或其他bean的时候我们可以通过Condition相关注解来定义一些条件。从而实现只有在满足条件的情况下才向容器中注册对应的bean,这样就可以实现根据我们的环境启用或禁用自动配置功能了。当然为了让我们可以通过配置文件修改默认的自动配置属性,我们还可以定义相关的Properties 属性配置类来读取配置文件中定义的属性。当自动配置属性不符合我们要求的时候只需要在配置文件中定义相关的属性值替换默认属性就可以了。
最后就是让spring容器自动加载我们的AutoConfiguration自动配置类。让spring容器自动加载我们的AutoConfiguration自动配置类,我们只需要在autoconfigure模块中的META-INF下面创建一个spring.factories 文件,然后在文件中把我们的自动配置类添加到EnableAutoConfiguration 键所对应的值中就可以了。当然其实我们在配置类中直接通过@Import 导入对应的自动配置类也是可以的,不过不能使用@Bean 因为使用@Bean 就一定会new,那么自动配置类上的Condition相关注解就失效了
常用的Condition相关注解包括:
- Class Conditions:根据class类进行判断
@ConditionalOnClass :包含指定类时启用@ConditionalOnMissingClass :不包含指定类时启用- 注意这种注解不适用于@Bean方法,因为通常返回类型是条件的目标时,在方法的Conditions条件应用之前,JVM会加载类并可能处理方法引用,如果类不存在,这些引用将失败。对于这种情况,我们可以添加一个静态内部类,在静态内部类中使用@Bean方法,然后将这种注解应用在静态内部类上
- Bean Conditions:根据bean进行判断
@ConditionalOnBean :包含指定bean时启用@ConditionalOnMissingBean :不包含指定bean时启用 - Property Conditions:根据配置文件中的属性进行判断
@ConditionalOnProperty :判断配置文件中是否包含某个属性值以及是否为指定值 - Resource Conditions:根据资源判断
@ConditionalOnResource :判断是否包含指定资源 - Web Application Conditions:根据当前容器判断
@ConditionalOnWebApplication :判断当前容器是否为web容器@ConditionalOnNotWebApplication :判断当前容器是否不是web容器
|