第1章 SpringBoot入门
1.1 SpringBoot概述
1.1.1 SpringBoot简介
Spring Boot 是由 Pivotal 团队提供的全新框架,旨在简化基于 Spring 框架的开发。它通过提供开箱即用的配置、自动配置和依赖管理等功能,使得开发者能够快速构建独立的、生产级别的基于 Spring 的应用程序。
设计理念
- 约定优于配置:遵循最佳实践,默认情况下使用推荐的设置,只有当需要自定义行为时才进行显式配置。
- 易于上手:降低了学习曲线,即使是对 Spring 不熟悉的开发者也能迅速掌握并开始开发工作。
- 模块化设计:允许开发者根据实际需求选择性地引入特定功能模块,避免不必要的依赖。
适用场景
- 微服务架构:Spring Boot 非常适合构建微服务,因为它简化了服务之间的集成,并且容易与 Spring Cloud 结合使用以实现分布式系统。
- RESTful API 开发:内置对构建 RESTful Web 服务的支持,配合 Spring MVC 可以轻松创建高效、可扩展的 API。
- 企业级应用开发:凭借其强大的生态系统和丰富的插件,Spring Boot 成为了开发复杂业务逻辑的企业级应用的理想选择。
- 快速原型开发:对于想要快速迭代和测试新想法的团队来说,Spring Boot 的快速启动能力和简洁的配置使其成为理想的开发平台。
1.1.2 SpringBoot特性
核心特性
- 自动化配置:Spring Boot 提供了大量“开箱即用”的默认配置选项,这些配置可以满足大多数应用场景的需求,减少了手动配置的工作量。
- 启动器依赖(Starter Dependencies):Spring Boot 提供了一组方便使用的依赖管理工具——起步依赖包,它们将常见的库组合在一起,并预设了合理的版本号。例如
spring-boot-starter-web
包含了构建 Web 应用所需的所有依赖。- 内嵌容器:支持直接嵌入 Tomcat、Jetty 或 Undertow 等 Servlet 容器,无需单独部署到外部服务器中,从而简化了应用的启动过程。
- 开发工具(DevTools):包括热部署、自动重启等特性,极大地提高了开发效率。
优势
- 提高生产力:通过减少样板代码和简化配置,让开发者更专注于业务逻辑的实现。
- 社区支持广泛:拥有庞大的开发者社区和技术文档资源,遇到问题时可以获得及时的帮助和支持。
- 持续更新和发展:Pivotal 和广大贡献者不断改进和完善 Spring Boot,确保其紧跟技术潮流并适应新的挑战。
总结:简化开发,简化配置,简化整合,简化部署,简化监控,简化运维。
1.2 SpringBoot之Helloworld(快速入门)
-
新建工程:导入启动器
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter-test</artifactId> <version>3.0.3</version> <scope>test</scope> </dependency> </dependencies>
-
编写配置文件:application.properties
#设置数据库连接 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/0923_demo?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=root #mybatis mybatis.mapper-locations=classpath:mappers/*.xml mybatis.configuration.map-underscore-to-camel-case=true #设置自动映射full(selectAllEmpAndDeptAssociation) mybatis.configuration.auto-mapping-behavior=full #开启延迟加载(懒加载) mybatis.configuration.lazy-loading-enabled=true mybatis.configuration.aggressive-lazy-loading=false mybatis.type-aliases-package=com.atguigu.pojo logging.level.com.atguigu.mapper=debug #服务器端口号(默认值8080) server.port=8080 #配置上下文路径(默认值/) server.servlet.context-path=/ #静态资源路径(默认值:) spring.web.resources.static-locations=classpath:/static/
-
启动类启动服务器
1.3 SpringBoot场景启动器
1.3.1 启动器概念
Spring Boot 场景启动器(Starter)是 Spring Boot 提供的一种简化依赖管理和配置的方式。每个 Starter 都是一个 Maven 或 Gradle 项目,它包含了构建特定类型应用程序所需的所有依赖项和自动配置。通过使用这些 Starter,开发者可以快速搭建出功能完整的应用程序,而无需手动添加和配置大量的库。
总结:场景启动器是SpringBoot针对于特定的开发场景,而设置的一整套所需的jar包及配置文件的合集
场景启动器一般分为官方启动器和第三方启动器
- 官方启动器名称规范: spring-boot-starter-*
- 第三方启动器名称规范: *-spring-boot-starter
1.3.2 场景启动器作用
-
所有SpringBoot项目都继承一个父工程
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.6</version> <relativePath/> <!-- lookup parent from repository --> </parent>
-
父工程主要作用:导入配置文件
-
父工程的父工程:定义常用坐标的版本号并导入当前工程
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>3.3.5</version> </parent>
-
-
所有SpringBoot项目都导入一个场景启动器:基启动器
- 基启动器主要作用:导入"一篮子"坐标,详情如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot</artifactId> <version>3.3.5</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>3.3.5</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> <version>3.3.5</version> <scope>compile</scope> </dependency> <dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <version>2.1.1</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>6.1.14</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>2.2</version> <scope>compile</scope> </dependency> </dependencies>
1.3.2 常用场景启动器
-
SpringBoot基启动器
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
-
SpringBoot整合MVC
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
-
SpringBoot整合Mybatis
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter-test</artifactId> <version>3.0.3</version> <scope>test</scope> </dependency>
1.3.4 场景启动器小结
-
SpringBoot的父项中定义了大量的jar包及版本号,尽量使用这些默认的版本号的jar包和启动器
-
每个场景启动器都会导入一个spring-boot-starter ,这个启动器称之为基启动器,包含了启动器的基础依赖
-
基启动器中包含了基本的配置信息文件,基本属性类和基本的配置类,这些配置类在开发某些特定场景的时候才会生效
-
场景启动器中也会包含了针对于某个场景的默认配置信息,属性类和配置类
-
启动器中携带的配置信息如果不满足项目需要,则需要再application.properties或者application.yml中进行配置即可
-
启动器中的****Properties类,可以称之为属性类,配置文件中的信息一般都会读取进入这些类作为属性值进行存储
-
启动器中的****Configuration类,称之为配置类,读取属性类中的信息,动态判断这些配置是否生效
-
属性类中的属性值,先使用场景启动器里的 additional-spring-configuration-metadata.json中的配置信息,这个配置文件中放入的都是默认的配置信息
-
如果我们的application.properties中也配置了同名的配置信息,则使用我们配置信息
-
原则上,能使用启动器中的默认配置信息解决问题,就不需要我们自己再指定配置信息,就是"约定大于配置的含义"
第2章 SpringBoot配置文件详解
SpringBoot配置文件必须是:application*.properties或application*.yml或application*.yaml
SpringBoot配置文件中支持自定义配置及内置配置
- 内置配置特点:会自带提示
- 自定义配置特点:默认不会提示,也可以配置属性类使用@ConfigurationProperties注解添加提示
2.1 SpringBoot配置文件类型
- springboot配置支持配置文件:properties或yml(yaml)
- 优先级:properties>yml>yaml
2.2 yml配置文件语法
application.yml
是 Spring Boot 中常用的配置文件格式之一,它使用 YAML(YAML Ain’t Markup Language)语法来定义应用程序的配置项。相比传统的application.properties
文件,YAML 语法更加简洁、层次分明,特别适合表达嵌套结构。以下是关于application.yml
文件中 YAML 语法的详细解析:
键值对:YAML 文件中的每一行通常表示一个键值对,格式为
key: value
。注意:
后必须有空格缩进:YAML 使用缩进来表示层级关系,每个层级的缩进通常是两个空格(不是 Tab),不同的缩进级别表示不同级别的嵌套。
注释:以
#
开头的行是注释,不会被解析。多级配置:YAML 支持多级配置,通过缩进来表示父子关系。例如:
spring: datasource: url: jdbc:mysql://localhost:3306/mydb username: root password: secret driver-class-name: com.mysql.cj.jdbc.Driver
数组和列表:可以使用
-
来定义列表或数组元素,也可以直接用方括号表示:myapp: servers: - server1.example.com - server2.example.com - server3.example.com #或 myapp: servers: [server1.example.com, server2.example.com, server3.example.com]
数字和日期:直接写入即可,YAML 会自动识别
myapp: timeout: 30000 # 整数 date: 2024-01-01 # 日期
空值:可以通过
null
或者~
来表示空值myapp: optional: ~
2.3 案例代码
2.3.1 yml配置
2.3.2 yml读取
第3章 @ConfigurationProperties注解详解
3.1 配置属性注解:@ConfigurationProperties简介
@ConfigurationProperties
注解是 Spring 框架中用于将配置文件中的属性绑定到 Java Bean 的一种方式。它使得你可以轻松地从外部配置源(如application.properties
或application.yml
文件)读取配置信息,并将其映射为应用程序中的对象结构。以下是关于@ConfigurationProperties
注解的详细解析:
- 基本概念
- 作用:
@ConfigurationProperties
用于标注一个类,表示该类是一个配置属性的载体,可以自动从配置文件中加载对应的属性值。- 前缀:通常需要指定一个
prefix
属性来定义这些配置项在配置文件中的前缀,确保它们能够正确映射到相应的字段上。
- 使用场景
当你有多个相关的配置项时,
@ConfigurationProperties
可以帮助你将它们组织成一个结构化的对象模型,而不是分散在整个应用程序的不同地方。这不仅提高了代码的可维护性,也便于管理复杂的配置逻辑。
3.2 @ConfigurationProperties注解基本使用
SpringBoot环境中默认的数据源对象是:com.zaxxer.hikari.HikariDataSource
当我们需要DruidDataSource时,需要配置德鲁伊数据源
3.2.1 准备环境
-
导入DruidDataSource依赖坐标
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency>
-
编写配置文件:application.yml
#配置数据源信息(第三方) jdbc: datasource: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/0923_demo username: root password: root #注意:下方是HikariDataSource默认数据源配置(暂时不用) spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/0923_demo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: rootn
3.2.2 定义属性类
package com.atguigu.properties;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "jdbc.datasource") //注意:prefix属性值与配置文件中前缀一致
public class JdbcProperty {
private String driverClassName;
private String url;
private String username;
private String password;
}
3.2.3 配置类中综合应用
package com.atguigu.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.atguigu.properties.JdbcProperty;
import com.zaxxer.hikari.util.DriverDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class MybatisConfig {
//注意:使用属性类,代替下方各属性
@Autowired
private JdbcProperty jdbcProperty;
// private String driverClassName;
// @Value("${jdbc.datasource.url}")
// private String url;
// @Value("${jdbc.datasource.username}")
// private String username;
// @Value("${jdbc.datasource.password}")
// private String password;
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(jdbcProperty.getDriverClassName());
dataSource.setUrl(jdbcProperty.getUrl());
dataSource.setUsername(jdbcProperty.getUsername());
dataSource.setPassword(jdbcProperty.getPassword());
return dataSource;
}
}
3.3 注意事项
- 启用配置处理:为了使
@ConfigurationProperties
生效,你需要确保项目中包含了spring-boot-configuration-processor
依赖。这对于生成元数据文件非常重要,有助于 IDE 提供更好的代码补全和支持。 - 注册为 Bean:虽然可以直接在组件上使用
@Component
和@ConfigurationProperties
,但推荐的做法是通过@EnableConfigurationProperties
或者@Import
将配置类注册为 Spring 管理的 Bean。 - 默认值设置:可以通过构造函数或直接在字段上赋值的方式来提供属性的默认值。
- 安全性考虑:对于敏感信息(如密码),建议不要直接暴露在配置文件中,而是采用加密存储或其他安全措施。
- 配置更新监听:如果需要在配置更新时做出响应,可以实现
ApplicationListener<ConfigurationPropertiesBindingEvent>
接口。
第4章 @SpringBootApplication注解详解
4.1 @SpringBootApplication注解简介
4.1.1 @SpringBootApplication源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AliasFor;
@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 {
@AliasFor(
annotation = EnableAutoConfiguration.class
)
Class<?>[] exclude() default {};
@AliasFor(
annotation = EnableAutoConfiguration.class
)
String[] excludeName() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackageClasses"
)
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "nameGenerator"
)
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
4.1.2 @SpringBootApplication作用
-
@SpringBootApplication
:实际上是以下三个注解的组合- @SpringBootConfiguration:标识该类为一个配置类,可以使用 Java 配置来定义组件(例如通过
@Bean
注解)。 - @EnableAutoConfiguration:启用 Spring Boot 的自动配置机制,根据类路径中的依赖自动配置 Spring 应用程序。它会尝试猜测并配置你可能需要的 Bean,从而减少了大量的手动配置工作。
- @ComponentScan:自动扫描并注册带有 @Component、@Service、@Repository 和 @Controller 等注解的类作为 Spring Beans。默认情况下,它会从声明 @SpringBootApplication 的类所在的包及其子包中查找组件。
- @SpringBootConfiguration:标识该类为一个配置类,可以使用 Java 配置来定义组件(例如通过
-
@SpringBootApplication
使用场景- @SpringBootApplication 通常被放置在应用程序的主类上,也就是包含 public static void main(String[] args) 方法的那个类。这样做的好处是可以让整个应用程序的所有配置都集中在这个主类中,便于管理和维护。
-
@SpringBootApplication
自定义配置-
虽然 @SpringBootApplication 提供了一套合理的默认设置,但你可以根据需要对其进行自定义。比如,如果你想改变组件扫描的基础包或者关闭某些自动配置,可以通过如下方式实现:
-
自定义
@ComponentScan
的基础包@SpringBootApplication(scanBasePackages = {"com.example.package1", "com.example.package2"}) public class MyApplication { // ... }
-
禁用特定的自动配置:如果你不想使用某些自动配置,可以通过
exclude
参数来排除它们@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class MyApplication { // ... }
-
-
4.2 @ComponentScan注解详解
@ComponentScan
注解是 Spring 框架中的一个重要组件,用于指定哪些包应该被扫描以查找带有特定注解(如@Component
、@Service
、@Repository
和@Controller
)的类,并将这些类注册为 Spring 容器中的 Bean。通过使用@ComponentScan
,你可以自动发现并配置应用程序中的组件,而无需手动在 XML 文件中定义每个 Bean。以下是关于@ComponentScan
注解的详细解析:
4.2.1 基本概念
- 作用:
@ComponentScan
主要用于启动组件扫描机制,让 Spring 自动寻找和注册组件。 - 默认行为:当
@ComponentScan
被应用到一个配置类上时,默认情况下它会从该配置类所在的包开始递归扫描所有子包。
4.2.2 常用属性
basePackages
或value
:指定需要扫描的基础包路径,可以是一个或多个包名,用逗号分隔。例如:
@ComponentScan(basePackages = {"com.example.package1", "com.example.package2"})
public @interface SpringBootApplication {}
-
basePackageClasses
:通过提供具体类来确定基础包,Spring 将从这些类所在的包开始扫描。这比直接指定包名更加灵活,尤其是在模块化项目中。例如:@ComponentScan(basePackageClasses = {MyClass1.class, MyClass2.class}) public @interface SpringBootApplication {}
-
includeFilters
和excludeFilters
:允许你自定义过滤规则来包含或排除某些类型的组件。每个过滤器都是一个FilterType
枚举值加上相应的模式匹配表达式。例如:@ComponentScan( includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = MyCustomAnnotation.class), excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MyExcludedClass.class) ) public @interface SpringBootApplication {}
4.3 @SpringBootConfiguration注解详解
4.3.1 源码
package org.springframework.boot;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Indexed;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
4.3.2 @SpringBootConfiguration注解简介
@SpringBootConfiguration
注解是 Spring Boot 提供的一个专门用于标识配置类的注解。它实际上是@Configuration
注解的一个变体,主要用于避免与其他框架或库中的@Configuration
注解发生冲突。以下是关于@SpringBootConfiguration
注解的详细解析:
- 基本概念
- 作用:
@SpringBootConfiguration
标识一个 Java 类为 Spring 的配置类,意味着该类中可以包含使用@Bean
注解的方法来定义和初始化 Spring 容器中的 Bean。- 区别于
@Configuration
:虽然@SpringBootConfiguration
和@Configuration
在功能上几乎相同,但前者是专门为 Spring Boot 应用程序设计的,以确保不会与其他框架的@Configuration
注解产生混淆。
- 自动应用
在大多数情况下,你不需要显式地使用
@SpringBootConfiguration
,因为:
@SpringBootApplication
注解已经隐含了@SpringBootConfiguration
的功能。当你在一个主应用程序类上添加@SpringBootApplication
时,实际上等于同时应用了@SpringBootConfiguration
、@EnableAutoConfiguration
和@ComponentScan
。
4.4 @EnableAutoConfiguration注解详解
4.4.1 @EnableAutoConfiguration注解简介
@EnableAutoConfiguration
是 Spring Boot 提供的一个注解,用于启用 Spring Boot 的自动配置机制。Spring Boot 的设计初衷是为了简化 Spring 应用的创建过程,特别是针对那些有常见模式的应用程序(如嵌入式服务器、安全性、数据库连接等)。自动配置是 Spring Boot 的一个核心特性,它试图根据你的类路径和配置来猜测并自动配置你应用程序的 bean。以下是
@EnableAutoConfiguration
注解的一些关键点:
自动检测依赖:当在应用程序中使用
@EnableAutoConfiguration
时,Spring Boot 会扫描类路径上的 jar 包,并尝试根据它们的内容来推断应该应用哪些自动配置。排除特定自动配置:有时你可能不希望某些自动配置生效。你可以通过
exclude
属性来排除不需要的自动配置类,例如:java深色版本
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
排除名称空间:如果你知道要排除的自动配置类的名称,但不想直接引用它们,可以使用
excludeName
属性,例如:java深色版本
@EnableAutoConfiguration(excludeName={"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"})
与@SpringBootApplication的关系:通常情况下,你不会直接使用
@EnableAutoConfiguration
,而是使用@SpringBootApplication
注解。@SpringBootApplication
是一个组合注解,它包含了@EnableAutoConfiguration
、@ComponentScan
和@Configuration
的功能。条件化配置:自动配置类通常是条件化的,这意味着它们只有在满足一定条件时才会被应用。比如,只有在没有检测到用户定义的相同类型的 bean 时,自动配置类才会起作用。
自定义配置优先:如果开发者自己定义了配置,那么这些配置会覆盖自动配置。这允许开发者保持对应用程序配置的完全控制。
总之,
@EnableAutoConfiguration
是 Spring Boot 简化开发体验的关键部分,它使得开发者能够快速启动和运行应用程序,同时仍然保留足够的灵活性来自定义配置。
4.4.2 @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 {};
}
4.4.3 自动配置原理
Spring Boot 的自动配置原理依赖于 Spring 框架的核心特性,如条件化配置(Conditional Configuration)、Bean 定义、以及对类路径和环境的检测。以下是 Spring Boot 自动配置的主要工作原理:
- 条件化注解
自动配置广泛使用了
@Conditional
注解及其变种,例如@ConditionalOnClass
、@ConditionalOnMissingBean
等等。这些条件化注解使得特定的配置只在满足一定条件下才会生效。比如,只有当类路径中存在某些类时,或者当容器中不存在某个类型的 Bean 时,自动配置才会起作用。
- 自动配置类
Spring Boot 提供了一组自动配置类,它们通常位于
org.springframework.boot.autoconfigure
包下。每个自动配置类都针对某一特定技术或功能模块(如数据源配置、模板引擎配置、安全配置等)进行配置。这些类会根据应用程序的类路径和配置文件来决定是否应用配置。
spring.factories
文件Spring Boot 使用
META-INF/spring.factories
文件来加载自动配置类。这个文件列出了所有可用的自动配置类,并允许第三方库向 Spring Boot 注册自己的自动配置类。启动时,Spring Boot 会读取该文件并加载其中定义的自动配置类。
- 类路径扫描
Spring Boot 会扫描类路径中的 jar 包,查找是否存在与特定功能相关的类或库。如果找到,它会尝试通过自动配置类为这些功能提供默认配置。
- 属性覆盖
尽管有自动配置,开发者仍然可以通过在
application.properties
或application.yml
文件中定义属性来覆盖默认设置。这允许开发者根据需要自定义配置。
- 启用自动配置
要启用自动配置,通常只需要添加
@EnableAutoConfiguration
或者更常见的@SpringBootApplication
注解到主应用程序类上。@SpringBootApplication
实际上是三个注解的组合:
@Configuration
:将该类标记为一个配置类。@ComponentScan
:启用组件扫描,以便发现和注册其他带有@Component
、@Service
、@Repository
和@Controller
等注解的类。@EnableAutoConfiguration
:启用自动配置机制。
- 应用程序上下文事件
在应用程序启动过程中,Spring Boot 发布了一系列的应用上下文事件,允许开发者在不同阶段响应或修改自动配置行为。
总之,Spring Boot 的自动配置是一种灵活且强大的方式,它简化了应用程序的配置过程,同时保持了足够的灵活性以适应不同的需求。通过这种方式,开发者可以专注于业务逻辑,而不必花费太多时间在基础架构配置上。
第5章 自定义启动器
5.1 功能描述
场景:抽取聊天机器人场景,它可以打招呼。
效果:任何项目导入此starter
都具有打招呼功能,并且问候语中的人名需要可以在配置文件中修改
- 创建
自定义starter
项目,引入spring-boot-starter
基础依赖 - 编写模块功能,引入模块所有需要的依赖。
- 编写
xxxAutoConfiguration
自动配置类,帮其他项目导入这个模块需要的所有组件 - 编写配置文件
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
指定启动需要加载的自动配置 - 其他项目引入即可使用
5.2 自定义启动器
5.2.1 创建自定义启动器
工程导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.5</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 导入配置处理器,配置文件自定义的properties配置都会有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
5.2.2 创建属性类及业务类
(1)RobotProperties
@ConfigurationProperties(prefix = "robot") //此属性类和配置文件指定前缀绑定
@Component
@Data
public class RobotProperties {
private String name;
private String age;
private String email;
}
(2)RobotService
@Service
public class RobotService {
@Autowired
RobotProperties robotProperties;
public String sayHello(){
return "你好:名字:【"+robotProperties.getName()+"】;年龄:【"+robotProperties.getAge()+"】";
}
}
5.2.3 提取公共配置类
自己写一个
RobotAutoConfiguration
,给容器中导入这个场景需要的所有组件
- 为什么这些组件默认不会扫描进去?
- starter所在的包和 引入它的项目的主程序所在的包不是父子层级
别人引用这个
starter
,直接导入这个RobotAutoConfiguration
,就能把这个场景的组件导入进来
//给容器中导入Robot功能要用的所有组件
@Import({RobotProperties.class, RobotService.class})
@Configuration
public class RobotAutoConfiguration {}
5.2.4 自定义@EnableXXX机制(可选)
他人引入
starter
可以使用@EnableRobot
开启自动配置功能
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import(RobotAutoConfiguration.class)
public @interface EnableRobot {}
5.2.5 使用配置文件开启自动配置
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中编写好我们自动配置类的全类名即可
- com.atguigu.RobotAutoConfiguration
- 如引入自定义启动器工程与当前自定义启动器不在同一目录下:需要将spring_starter项目进行install,并导入当前工程操作
5.3 应用自定义启动器
5.3.1 在使用的工程中引入自定义启动器项目依赖
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>spring_starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
5.3.2 使用@EnableRobot注解开启自动配置
- application.properties配置文件
robot.name=lucy
robot.age=20
robot.email=java@atguigu.com
- 启动类代码
@SpringBootApplication
@EnableRobot
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
5.3.3 Controller中测试
启动测试,访问路径:http://localhost:8080/robot/hello
@RestController
public class HelloController {
@Autowired
private RobotService robotService;
@GetMapping("/hello")
public String hello(){
System.out.println(robotService.sayHello());
return "Hello,Spring Boot 3!";
}
}
第6章 SpringBoot日志应用
6.1 SpringBoot中日志简介
6.1.1 日志作用
- 记录程序的运行过程,为调试和错误分析提供依据
- 为数据分析提供原始材料
6.1.2 日志介绍
在 Spring Boot 中,日志框架的配置和使用是十分灵活且强大的。Spring Boot 默认集成了多种流行的日志框架,并提供了统一的日志抽象层(
spring-jcl
或spring-logback
),使得开发者可以方便地选择和切换不同的日志实现。
日志抽象层
Spring Boot 使用 SLF4J (Simple Logging Facade for Java) 作为其日志抽象层,这意味着你可以使用任何支持 SLF4J 的日志框架,如 Logback、Log4j2 或 Java Util Logging。默认情况下,Spring Boot 使用 Logback 作为日志框架。
默认配置
默认日志级别:Spring Boot 默认设置的日志级别为
INFO
,这对于大多数生产环境来说是合适的。不过,你可以通过配置文件来改变这一设置。控制台输出:默认情况下,日志信息会打印到控制台上。这对于开发和调试非常有用。
日志格式:Spring Boot 提供了默认的日志格式,包含了时间戳、日志级别、线程名称、类名以及日志消息等信息。
6.2 SpringBoot中Logback基本使用
6.2.1 日志级别
Logback(以及 SLF4J 和其他许多日志框架)支持以下标准日志级别,从低到高排序:
- TRACE:最详细的日志信息,通常只在调试问题时启用。这包括了系统运行的每一步细节。
- DEBUG:比 TRACE 级别少一些,主要用于开发阶段的调试,记录程序执行过程中的重要信息。
- INFO:一般用于确认应用程序按预期工作,比如服务启动、关闭或处理请求等重要事件。
- WARN:警告信息,表示可能存在潜在的问题,但还不至于影响系统的正常运行。
- ERROR:错误信息,表示发生了严重的错误,可能导致某些功能无法正常使用。
日志级别优先级
- 日志级别具有严格的优先级顺序,即
TRACE < DEBUG < INFO < WARN < ERROR
。这意味着如果将某个 logger 的日志级别设置为INFO
,那么只有INFO
、WARN
和ERROR
级别的日志会被输出;而DEBUG
和TRACE
级别的日志则不会被记录。设置日志级别
你可以通过配置文件来设置全局或者特定包/类的日志级别。例如,在
logback-spring.xml
或者application.properties
文件中进行如下配置:
logback-spring.xml 示例
<configuration> <!-- 全局日志级别 --> <root level="INFO"> <appender-ref ref="STDOUT" /> </root> <!-- 特定包的日志级别 --> <logger name="com.example.myapp" level="DEBUG" additivity="false"> <appender-ref ref="FILE" /> </logger> </configuration>
application.properties 示例
# 设置全局日志级别为 WARN logging.level.root=WARN # 设置特定包的日志级别为 DEBUG logging.level.org.springframework.web=DEBUG logging.level.com.example.myapp=DEBUG
6.2.2 使用LoggerFactory构建日志记录器
@SpringBootTest(classes = Day21SsmApplication.class)
public class TestSlf4j {
//内置的日志记录器:log
Logger log = LoggerFactory.getLogger(TestSlf4j.class);
@Test
public void testSlf4j(){
// 创建日志记录器
log.info("日志记录器创建成功");
// 记录日志
log.trace("追踪信息trace");
log.debug("调试信息debug");
log.info("普通信息info");
log.warn("警告信息warn");
log.error("错误信息error");
}
}
6.2.3 使用@Slf4j注解
@Slf4j
@SpringBootTest(classes = Day21SsmApplication.class)
public class TestSlf4j {
@Test
public void testSlf4j(){
// 创建日志记录器
log.info("日志记录器创建成功");
// 记录日志
log.trace("追踪信息trace");
log.debug("调试信息debug");
log.info("普通信息info");
log.warn("警告信息warn");
log.error("错误信息error");
}
}
6.3 设置日志分组
6.3.1 日志分组基本概念
在 Logback 中设置日志分组可以通过使用
logger
和appender
的组合来实现。日志分组指的是将某些特定的日志信息定向到不同的输出目标(如文件、控制台等),这通常用于将不同模块或类别的日志分离,以便更方便地管理和查看。每个
logger
可以关联一个或多个appender
,而appender
负责实际的日志输出。通过为不同的logger
指定不同的appender
,你可以有效地实现日志分组。
6.3.2 实现日志分组
-
logback.xml方式
<configuration> <!-- 定义 appender --> <appender name="FILE-A" class="ch.qos.logback.core.FileAppender"> <file>logs/app-a.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <appender name="FILE-B" class="ch.qos.logback.core.FileAppender"> <file>logs/app-b.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 设置 logger --> <logger name="com.example.app.moduleA" level="DEBUG"> <appender-ref ref="FILE-A" /> </logger> <logger name="com.example.app.moduleB" level="INFO"> <appender-ref ref="FILE-B" /> </logger> <!-- 根 logger --> <root level="WARN"> <appender-ref ref="STDOUT" /> </root> </configuration>
-
application.properties方式
#设置日志分组 logging.group.model=com.atguigu.service,com.atguigu.mapper logging.group.controller=com.atguigu.controller #设置分组后日志级别 logging.level.model=debug logging.level.controller=info
6.4 设置日志以文件形式存储
将日志以文件形式存储是 Logback 中非常常见的需求。通过正确配置
FileAppender
或其子类(如RollingFileAppender
),你可以确保应用程序的日志信息被记录到指定的文件中,同时还可以根据需要设置日志滚动策略、归档旧日志等高级功能。
6.4.1 logback.xml
<configuration>
<!-- 定义 FileAppender -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>logs/application.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 设置 root logger -->
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
6.4.2 application.properties
设置以文件形式存储:logging.file.name或logging.file.path
- 注意:设置文件名称或设置文件路径,应该二选一即可
#设置日志文件(默认文件名:spring.log)
logging.file.path=e:/atguigu_240923/logs222/
logging.file.name=./ssm222.log
6.5 日志的归档与切割
配置项 | 描述 |
---|---|
logging.logback.rollingpolicy.file-name-pattern | 日志存档的文件名格式 默认值:${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz |
logging.logback.rollingpolicy.clean-history-on-start | 应用启动时是否清除以前存档; 默认值:false |
logging.logback.rollingpolicy.max-file-size | 每个日志文件的最大大小; 默认值:10MB |
logging.logback.rollingpolicy.total-size-cap | 日志文件被删除之前,可以容纳的最大大小 默认值:0B。 设置1GB则磁盘存储超过 1GB 日志后就会删除旧日志文件 |
logging.logback.rollingpolicy.max-history | 日志文件保存的最大天数; 默认值:7 |
6.5.1 设置归档切割方式
#设置日志文件(默认文件名:spring.log)
logging.file.path=e:/atguigu_240923/logs222/
#logging.file.name=./ssm222.log
#设置单个日志文件大小
logging.logback.rollingpolicy.max-file-size=1MB
6.5.2 测试及效果
@Test
public void testSlf4j22() throws InterruptedException {
int i = 0;
while(true){
log.info("循环添加日志信息...i"+(++i));
Thread.sleep(1);
}
}
6.6 切换log4j2日志框架
6.6.1 调整依赖坐标
排除spring-boot-starter中的spring-boot-starter-logging
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!--排除默认的日志依赖-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--手动导入日志依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
6.6.2 添加log4j2.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="File" fileName="logs/app.log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>
第7章 SpringBoot整合SSM
7.1 新建工程导入依赖
7.1.1 新建工程
7.1.2 导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>3.0.3</version>
<scope>test</scope>
</dependency>
</dependencies>
7.2 编写配置文件
#配置数据源(Hikari)
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/0923_demo
username: root
password: root
#mvc配置
# web:
# resources:
# static-locations: classpath:/webapp/
#mybatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.atguigu.pojo
configuration:
map-underscore-to-camel-case: true
auto-mapping-behavior: full
7.3 整合MVC注意事项
7.3.1 静态资源加载问题
WebProperties源代码中默认解析静态路径:classpath:/META-INF/resources/", “classpath:/resources/”, “classpath:/static/”, "classpath:/public/
springboot支持自定义静态资源路径,一旦定义静态资源路径,默认静态资源路径失效
-
自定义静态资源路径
spring: web: resources: static-locations: classpath:/webapp/
7.3.2 注册拦截器问题
package com.atguigu.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/interceptorController/testInterceptor");
}
}
7.4 整合Mybatis注意事项
@Mapper注解:为当前接口生成代理对象
@MapperScan注解:为当前包下所有Mapper接口生成代理对象
@Configuration
@MapperScan("com.atguigu.mapper")
public class MybatisConfig {
}
第8章 Banner及其他启动方式
8.1 banner设置
banner生成器:https://www.bootschool.net/ascii
自定义banner
编写配置文件:application.properties
spring.banner.location=classpath:banner.txt
8.2 其他启动方式
8.2.1 方式一
public static void main(String[] args) {
//方式一:默认
ConfigurableApplicationContext ioc
= SpringApplication.run(Day20SpringbootsmApplication.class, args);
}
8.2.2 方式二
// 方式2
SpringApplication springApplication = new SpringApplication(SpringBoot01ConfigApplication.class);
// 设置参数
springApplication.setBannerMode(Banner.Mode.OFF);
//springApplication.setEnvironment();
//springApplication.addListeners();
// 运行项目
springApplication.run(args);
8.2.3 方式三
// 方式3
SpringApplicationBuilder springApplicationBuilder = new SpringApplicationBuilder();
springApplicationBuilder
.sources(SpringBoot01ConfigApplication.class)
// 设置参数
.bannerMode(Banner.Mode.OFF)
//.environment()
//.listeners()
// 启动
.run(args);
第9章 环境配置及项目部署
9.1 profiles切换环境
9.1.2 定义环境
-
application-dev.yml
#配置springboot数据源(Druid) jdbc: datasource: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/0923_demo_dev username: root password: root server: port: 8088
-
application-test.yml
#配置springboot数据源(Druid) jdbc: datasource: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/0923_demo_test username: root password: root server: port: 8098
9.2.2 切换环境:application.yml
dev:指的是application-dev.yml文件名中的dev
spring:
profiles:
active: dev
9.2 项目部署
SpringBoot中默认集成Tomact,不用将项目打成war包,打成jar包即可
使用
java -jar
命令运行一个打包好的 Spring Boot 或其他 Java 应用程序时,可以通过命令行参数传递配置信息给应用程序。这种做法在部署和调试过程中非常有用,因为它允许你在不修改应用程序代码或配置文件的情况下动态调整应用行为。语法如下:
java -jar <application>.jar --<property>=<value>
<application>.jar
:这是你想要运行的 JAR 文件的名称。--<property>=<value>
:这是你想要传递给应用程序的配置项。<property>
是属性名,<value>
是对应的值。
-
案例代码
java -jar myapp.jar --server.port=8081 --spring.datasource.url=jdbc:mysql://localhost:3306/mydb
9.3 单元测试及断言
9.3.1 单元测试
@Test :表示方法是测试方法。
@ParameterizedTest :表示方法是参数化测试,下方会有详细介绍
@RepeatedTest :表示方法可重复执行,下方会有详细介绍
@DisplayName :为测试类或者测试方法设置展示名称
@BeforeEach :表示在每个单元测试之前执行
@AfterEach :表示在每个单元测试之后执行
@BeforeAll :表示在所有单元测试之前执行
@AfterAll :表示在所有单元测试之后执行
@Tag :表示单元测试类别,类似于JUnit4中的@Categories
@Disabled :表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
@Timeout :表示测试方法运行如果超过了指定时间将会返回错误
@ExtendWith :为测试类或测试方法提供扩展类引用
9.3.2 断言
断言(Assertions)是一种编程工具,用于在开发和测试期间验证程序的内部状态是否符合预期。它们可以帮助开发者快速定位和修复错误,确保代码按照设计的方式运行。在 Java 中,断言通过
assert
关键字实现,并且可以用来检查前置条件、后置条件以及不变量。断言的应用场景
- 前置条件:在方法开始执行之前,确保传入的参数满足某些条件。
- 后置条件:在方法结束之后,确保返回的结果符合预期。
- 不变量:在类的整个生命周期中,确保某些条件始终成立,如对象的状态保持一致。
- 调试和测试:帮助开发者发现潜在的问题,特别是在单元测试中。
断言 vs 异常处理
虽然断言和异常处理都可以用来捕捉错误,但它们有不同的用途:
- 断言:主要用于开发和测试阶段,帮助开发者验证程序逻辑正确性。它们不应该被用来处理正常的业务逻辑错误。
- 异常处理:适用于生产环境中,用于处理可能发生的错误情况,并提供恢复机制。
方法 | 说明 |
---|---|
assertEquals | 判断两个对象或两个原始类型是否相等 |
assertNotEquals | 判断两个对象或两个原始类型是否不相等 |
assertSame | 判断两个对象引用是否指向同一个对象 |
assertNotSame | 判断两个对象引用是否指向不同的对象 |
assertTrue | 判断给定的布尔值是否为 true |
assertFalse | 判断给定的布尔值是否为 false |
assertNull | 判断给定的对象引用是否为 null |
assertNotNull | 判断给定的对象引用是否不为 null |
assertArrayEquals | 数组断言 |
assertAll | 组合断言 |
assertThrows | 异常断言 |
assertTimeout | 超时断言 |
fail | 快速失败 |
-
案例代码
@DisplayName("测试方法1") @Test public void testMethod1(){ log.info("==>testMethod1"); // String rs = retrunNull(); //断言方法返回null // Assertions.assertNull(retrunNull()); //断言方法返回success Assertions.assertEquals("success",retrunNull(),"断言失败,字符串不是:success"); } public String retrunNull(){ return "Success"; }
第10章 其他及总结
10.1 SpringBoot生命周期
10.1.1 生命周期阶段
引导阶段
- starting 启动
- enviromentPrepared 环境准备
启动阶段
- contextPrepared 创建IOC容器对象
- contextLoaded IOC加载信息,并未刷新
- started ioc刷新,创建Bean组件
- ready ioc刷新,runner调用完成
运行阶段
- context.isRunning 运行中
starting之后的任何一个阶段出现问题,都会出发failed 启动失败,感知包含的6个过程的错误
10.1.2 生命周期详解
Spring Boot 的生命周期管理是其核心特性之一,它确保了应用程序组件能够按照预期顺序初始化、运行和销毁。了解 Spring Boot 的生命周期对于开发人员优化应用程序行为、实现自定义逻辑以及处理资源管理至关重要。以下是 Spring Boot 生命周期的详细解析。
1. 应用启动过程
Spring Boot 应用启动时会经历以下几个主要阶段:
1.1. 初始化
ApplicationContext
- 创建上下文:当应用启动时,首先会创建一个
ApplicationContext
实例(通常是AnnotationConfigServletWebServerApplicationContext
对于 Web 应用)。- 加载配置类:根据
@SpringBootApplication
或其他配置类中的注解来加载相应的配置。1.2. 加载 Bean 定义
- 扫描组件:通过
@ComponentScan
注解自动扫描并注册组件。- 解析配置:解析配置类中的
@Bean
方法和其他配置元数据。1.3. 预初始化 Bean
- 调用 Aware 接口方法:如果某些 Bean 实现了
Aware
接口(如ApplicationContextAware
),则在预初始化期间设置相应的属性。- 调用
InitializingBean.afterPropertiesSet()
:如果 Bean 实现了InitializingBean
接口,则调用此方法。1.4. 启动应用事件监听器
- 发布
ApplicationStartingEvent
:通知所有监听器应用即将开始启动。- 发布
ApplicationEnvironmentPreparedEvent
:环境准备完毕后发布该事件。- 发布
ApplicationPreparedEvent
:应用上下文准备好但尚未刷新时发布。1.5. 刷新
ApplicationContext
- 初始化单例 Beans:此时所有的非懒加载单例 Bean 将被实例化。
- 调用
@PostConstruct
方法:对于使用了@PostConstruct
注解的方法,在 Bean 初始化完成后执行。- 调用
@Bean(initMethod = "methodName")
:如果有指定的初始化方法,则在此阶段调用。1.6. 发布
ApplicationStartedEvent
- 应用已经启动但还未运行:此时可以进行一些额外的初始化操作。
1.7. 启动 Web 服务器(针对 Web 应用)
- 启动嵌入式服务器:例如 Tomcat、Jetty 或 Undertow。
1.8. 发布
ApplicationReadyEvent
- 应用完全准备好:表示应用已经可以接受请求。
2. 运行期间
在应用正常运行期间,Spring Boot 会持续管理和监控 Bean 的状态,并响应各种请求和服务调用。此外,开发者还可以利用
@Scheduled
来安排定时任务,或通过@EventListener
监听特定事件。3. 应用关闭过程
当应用需要关闭时,Spring Boot 会触发一系列有序的销毁动作:
3.1. 发布
ApplicationStoppedEvent
- 停止服务:通知所有监听器应用正在停止。
3.2. 销毁 Bean
- 调用
@PreDestroy
方法:对于使用了@PreDestroy
注解的方法,在 Bean 销毁前执行。- 调用
@Bean(destroyMethod = "methodName")
:如果有指定的销毁方法,则在此阶段调用。- 调用
DisposableBean.destroy()
:如果 Bean 实现了DisposableBean
接口,则调用此方法。3.3. 关闭 Web 服务器(针对 Web 应用)
3.4. 发布
ApplicationClosedEvent
- 应用已关闭:表示应用已经完全关闭。
4. 生命周期回调接口和注解
为了更方便地参与到生命周期的不同阶段,Spring 提供了一些常用的接口和注解:
ApplicationListener
:用于监听应用事件。SmartLifecycle
:提供了对生命周期更细粒度的控制。CommandLineRunner
和ApplicationRunner
:允许在应用启动完成后执行特定代码。@PostConstruct
和@PreDestroy
:分别用于标记初始化和销毁方法。@EventListener
:用于监听并响应特定的应用事件。总结
理解 Spring Boot 的生命周期有助于开发人员更好地设计和优化应用程序。通过合理利用生命周期中的各个阶段,可以确保应用按预期顺序启动和关闭,同时也能有效地管理资源,提高系统的稳定性和性能。
10.2 九大监听事件
系统九大事件 |
---|
ApplicationStartingEvent 应用正在启动事件 |
ApplicationEnvironmentPreparedEvent 环境准备就绪事件 |
ApplicationContextInitializedEvent IOC容器初始化事件 |
ApplicationPreparedEvent IOC加载信息, 未刷新Bean 事件 |
ApplicationStartedEvent IOC刷新Bean , Bean创建完成时间 |
AvailabilityChangeEvent 存活探针 |
ApplicationReadyEvent 应用就绪事件 |
AvailabilityChangeEvent 就绪探针 |
ApplicationFailedEvent 启动失败事件 |
事件与监听器对应关系
10.3 事件驱动方式开发监听器
10.3.1 场景描述
用户登录成功后,自动给用户发放优惠券,自动增加用户积分
10.3.2 开发监听事件
// 定义一个登录成功事件
package com.atguigu.springboot04lifecycle.event;
import lombok.Data;
@Data
public class LoginSuccessEvent {
private String username;
public LoginSuccessEvent(String username) {
this.username = username;
}
}
10.3.3 开发Controller层代码
package com.atguigu.springboot04lifecycle.controller;
import com.atguigu.springboot04lifecycle.event.LoginSuccessEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class UserController {
// 注入事件发布器
@Autowired
private ApplicationEventPublisher publisher;
@RequestMapping("/login")
public String loginIn(String username,String password) {
log.info("用户"+username+"登录成功");
// 发放优惠卷和增加积分 发布用户登录成功事件
publisher.publishEvent(new LoginSuccessEvent(username));
// 登录成功的后续工作
log.info("登录成功后的其他内容");
return "登录成功";
}
}
10.3.4 服务层监听事件,执行服务
package com.atguigu.springboot04lifecycle.service;
import com.atguigu.springboot04lifecycle.event.LoginSuccessEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class CouponService {
// 监听用户登录成功事件
@Async // 设置异步处理事件
@EventListener(LoginSuccessEvent.class)
public void listenLoginSuccess(LoginSuccessEvent event){
log.info("CouponService监听到用户登录成功事件");
addCoupon(event.getUsername());
}
public void addCoupon(String username){
log.info("给用户"+username+"发放优惠券");
}
}
package com.atguigu.springboot04lifecycle.service;
import com.atguigu.springboot04lifecycle.event.LoginSuccessEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class PointService {
// 监听用户登录成功事件
@Async // 设置异步处理事件
@EventListener(LoginSuccessEvent.class)
public void listenLoginSuccess(LoginSuccessEvent event){
log.info("PointService监听到用户登录成功事件");
addPoint(event.getUsername());
}
public void addPoint(String username){
log.info("给用户"+username+"增加积分");
}
}
10.3.5 配置类/启动类开启异步编程
package com.atguigu.springboot04lifecycle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@Slf4j
@SpringBootApplication
@EnableAsync // 开启异步事件处理注解
public class Springboot04LifecycleApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot04LifecycleApplication.class, args);
}
}
text.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class CouponService {
// 监听用户登录成功事件
@Async // 设置异步处理事件
@EventListener(LoginSuccessEvent.class)
public void listenLoginSuccess(LoginSuccessEvent event){
log.info("CouponService监听到用户登录成功事件");
addCoupon(event.getUsername());
}
public void addCoupon(String username){
log.info("给用户"+username+"发放优惠券");
}
}
package com.atguigu.springboot04lifecycle.service;
import com.atguigu.springboot04lifecycle.event.LoginSuccessEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class PointService {
// 监听用户登录成功事件
@Async // 设置异步处理事件
@EventListener(LoginSuccessEvent.class)
public void listenLoginSuccess(LoginSuccessEvent event){
log.info("PointService监听到用户登录成功事件");
addPoint(event.getUsername());
}
public void addPoint(String username){
log.info("给用户"+username+"增加积分");
}
}
### 10.3.5 配置类/启动类开启异步编程
package com.atguigu.springboot04lifecycle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@Slf4j
@SpringBootApplication
@EnableAsync // 开启异步事件处理注解
public class Springboot04LifecycleApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot04LifecycleApplication.class, args);
}
}