环境配置及项目部署
1 profiles切换环境
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
2.2 切换环境:application.yml
dev:指的是application-dev.yml文件名中的dev
spring:
profiles:
active: dev
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
3 单元测试及断言
3.1 单元测试
- @Test :表示方法是测试方法。
- @ParameterizedTest :表示方法是参数化测试,下方会有详细介绍
- @RepeatedTest :表示方法可重复执行,下方会有详细介绍
- @DisplayName :为测试类或者测试方法设置展示名称
- @BeforeEach :表示在每个单元测试之前执行
- @AfterEach :表示在每个单元测试之后执行
- @BeforeAll :表示在所有单元测试之前执行
- @AfterAll :表示在所有单元测试之后执行
- @Tag :表示单元测试类别,类似于JUnit4中的@Categories
- @Disabled :表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
- @Timeout :表示测试方法运行如果超过了指定时间将会返回错误
- @ExtendWith :为测试类或测试方法提供扩展类引用
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"; }
其他及总结(了解)
1 SpringBoot生命周期
1.1 生命周期阶段
- 引导阶段
- starting 启动
- enviromentPrepared 环境准备
- 启动阶段
- contextPrepared 创建IOC容器对象
- contextLoaded IOC加载信息,并未刷新
- started ioc刷新,创建Bean组件
- ready ioc刷新,runner调用完成
- 运行阶段
- context.isRunning 运行中
starting之后的任何一个阶段出现问题,都会出发failed 启动失败,感知包含的6个过程的错误
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 的生命周期有助于开发人员更好地设计和优化应用程序。通过合理利用生命周期中的各个阶段,可以确保应用按预期顺序启动和关闭,同时也能有效地管理资源,提高系统的稳定性和性能。
2 九大监听事件
| 系统九大事件 |
|---|
| ApplicationStartingEvent 应用正在启动事件 |
| ApplicationEnvironmentPreparedEvent 环境准备就绪事件 |
| ApplicationContextInitializedEvent IOC容器初始化事件 |
| ApplicationPreparedEvent IOC加载信息, 未刷新Bean 事件 |
| ApplicationStartedEvent IOC刷新Bean , Bean创建完成时间 |
| AvailabilityChangeEvent 存活探针 |
| ApplicationReadyEvent 应用就绪事件 |
| AvailabilityChangeEvent 就绪探针 |
| ApplicationFailedEvent 启动失败事件 |
3 事件驱动方式开发监听器
3.1 场景描述
用户登录成功后,自动给用户发放优惠券,自动增加用户积分
3.2 开发监听事件
// 定义一个登录成功事件
package com.mytest.springboot04lifecycle.event;
import lombok.Data;
@Data
public class LoginSuccessEvent {
private String username;
public LoginSuccessEvent(String username) {
this.username = username;
}
}
3.3 开发Controller层代码
package com.mytest.springboot04lifecycle.controller;
import com.mytest.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 "登录成功";
}
}
3.4 服务层监听事件,执行服务
package com.mytest.springboot04lifecycle.service;
import com.mytest.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.mytest.springboot04lifecycle.service;
import com.mytest.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+"增加积分");
}
}
3.5 配置类/启动类开启异步编程
package com.mytest.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);
}
}