参考资料运行环境一、SpringBoot 监听机制二、SpringBoot 原理分析
3.1 init初始化3.2 run 三、 SpringBoot 监控概述
3.1 SpringBoot 监控 - Spring Boot Admin3.2 使用 Admin 案例3.3 查看监控信息3.4 查看访问次数3.5 查看注入Spring容器的Bean3.6 查看部署项目线程实时的运行情况3.7 IDEA 提供的监控可视化 四、SpringBoot 项目部署
4.1 Jar4.2 war 五、收获与总结
参考资料视频资料
运行环境windows10JDK 8IDEA 专业版SpringBoot 2.5.6 一、SpringBoot 监听机制
SpringBoot的监听机制,其实是对Java提供的事件监听机制的封装
Java中的事件监听机制定义了以下几个角色:
事件:Event,继承 java.util.EventObject类的对象事件源:Source,任意对象 Object监听器:Listener,实现 java.util.EventListener接口的对象
在 SpringBoot项目启动时,会对几个监听器进行回调,我们可以实现这些监听器接口,在项目启动时完成一些操作
ApplicationContextInitializerSpringApplicationRunListenerCommandLineRunnerApplicationRunner
测试的项目结构:
spring.factories 用于指定springboot容器的监听类
org.springframework.context.ApplicationContextInitializer=com.uni.listener.MyApplicationContextInitializer org.springframework.boot.SpringApplicationRunListener=com.uni.listener.MySpringApplicationRunListener
MyApplicationContextInitializer.java
package com.uni.listener;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("ApplicationContextInitializer....initialize");
}
}
MyApplicationRunner.java
package com.uni.listener;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner...run");
System.out.println(Arrays.asList(args.getSourceArgs()));
}
}
MyCommandLineRunner.java
package com.uni.listener;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner...run");
System.out.println(Arrays.asList(args));
}
}
MySpringApplicationRunListener.java
package com.uni.listener;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.stereotype.Component;
import java.time.Duration;
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
public MySpringApplicationRunListener(SpringApplication application, String[] args) {
}
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
System.out.println("starting...项目启动中");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
System.out.println("environmentPrepared...环境对象开始准备");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("contextPrepared...上下文对象开始准备");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("contextLoaded...上下文对象开始加载");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timetaken) {
System.out.println("started...上下文对象加载完成");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("failed...项目启动失败");
}
}
运行结果:
二、SpringBoot 原理分析图片来自视频资料:链接
在SpringBoot启动类的run方法处打一个断点进行调试
接下来进入到第一层,SpringApplication.java 执行了 run方法,不过是调用类本身的重载run方法
另一个run方法又通过 SpringApplication类调用了run方法,注意这里传入了primarySource参数,即启动类的字节码
接着查看类SpringApplication.java的构造方法,并在255行设置断点,接着恢复程序(F9)
逐行查看(F8),观察它的构造顺序
通过257行可以看到,SpringBoot启动类,被划分成数组后转化成了linkedHashSet类型的哈希集合
至此,SpringBoot项目启动的初始化部分了解完毕。
3.2 run和之前类似,这次在SpringApplication.java类的289行处打一个断点进行调试
下图是上图293行的方法实现,这里是遍历了所有的启动依赖
这一步则是准备环境的方法实现,检查是否有配置的准备环境的监听类
准备环境之后,来到了Banner对象,这里就是打印SpringBoot图标的过程
打印图标
Banner是一个接口,通过查看其相关的类SpringApplicationBannerPrinter.java可以观察到一些默认的参数
根据上图的参数,SpringBoot会扫描 resources/banner.txt里的内容作为启动信息,若没有则会默认输出Spring字样,现可以:
更换SpringBoot的启动提示
_ooOoo_
o8888888o
88" . "88
(| -_- |)
O = /O
____/`---'____
. ' \| |// `.
/ \||| : |||//
/ _||||| -:- |||||-
| | \ - /// | |
| _| ''---/'' | |
.-__ `-` ___/-. /
___`. .' /--.-- `. . __
."" '< `.____<|>_/___.' >'"".
| | : `- `.;` _ /`;.`/ - ` : | |
`-. _ __ /__ _/ .-` / /
======`-.____`-.________/___.-`____.-'======
`=---='
.............................................
佛祖保佑 永无BUG
将文本的内容放在resources / banner.txt里,没有则创建,然后启动项目,替换成功~
Spring启动源码
SpringApplication.java
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
Duration timetakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timetakenToStartup);
}
listeners.started(context, timetakenToStartup);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timetakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timetakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
三、 SpringBoot 监控概述
SpringBoot 自带监控功能 Actuator, 一帮助实现对程序内部运行情况监控,比如监控状况,Bean加载情况、配置属性、日志信息等。
使用步骤:导入起步依赖坐标即可
pom.xml
org.springframework.boot spring-boot-starter-actuator
访问:http://localhost:8080/acruator
返回结果是一个JSON格式的数据,health表示SpringBoot项目里的application所有health字段的内容
接着手动打开配置项目的health监控
application.properties
# 开启健康检查的完整信息 management.endpoint.health.show-details=always
启动项目后访问:http://localhost:8080/acruator/health
现在添加Redis依赖,同时本机不启动Redis,再查看监控的内容
pom.xml
org.springframework.boot spring-boot-starter-data-redis
启动项目,访问 http://localhost:8080/actuator/health,将结果在 https://www.json.cn 里格式化后:
{
"status":"DOWN",
"components":{
"diskSpace":{
"status":"UP",
"details":{
"total":296022437888,
"free":128095268864,
"threshold":10485760,
"exists":true
}
},
"ping":{
"status":"UP"
},
"redis":{
"status":"DOWN",
"details":{
"error":"org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to localhost:6379"
}
}
}
}
可以观察到,导入Redis起步依赖后,SpringBoot能自动监听Redis的启动情况。
显示所有的监控 endpoint
application.properties
# 显示所有的监控 endpoint management.endpoints.web.exposure.include=*
启动项目,访问 http://localhost:8080/actuator
网址里提供了许多其他的监控地址,这里查看一下bean的监控地址:http://localhost:8080/actuator/beans
http://localhost:8080/actuator/mappings 显示监控SpringBoot项目中类的调用信息
3.1 SpringBoot 监控 - Spring Boot AdminSpring Boot Admin 是一个开源社区项目,用于管理和监控 SpringBoot 应用程序Spring Boot Admin 有两个角色,客户端(Client)和服务端(Server)应用程序作为Spring Boot Admin Client 向为 Spring Boot Admin Server 注册Spring Boot Admin Server 的UI界面将 Spring Boot Admin Client 的 Actuator Endpoint 上的一些监控信息 3.2 使用 Admin 案例
使用步骤:
admin-server:
- 创建 admin-server 模块导入依赖坐标 admin-starter-server
pom.xml(部分)
1.8 2.6.0 org.springframework.boot spring-boot-starter-web de.codecentric spring-boot-admin-starter-server org.springframework.boot spring-boot-starter-test test de.codecentric spring-boot-admin-dependencies ${spring-boot-admin.version} pom import
- 在引导类上启动监控功能@EnableAdminServer
admin-client:
- 创建 admin-client 模块导入依赖坐标 admin-starter-client
pom.xml
1.8 2.6.0 org.springframework.boot spring-boot-starter-web de.codecentric spring-boot-admin-starter-client org.springframework.boot spring-boot-starter-test test de.codecentric spring-boot-admin-dependencies ${spring-boot-admin.version} pom import
- 配置相关信息:server地址等
服务端配置 application.properties
server.port=9000
客户端配置 application.properties
# 执行 admin.server 地址 spring.boot.admin.client.url=http://localhost:9000 management.endpoint.health.show-details=always management.endpoints.web.exposure.include=*
- 启动server和client服务,访问server
访问:http://localhost:9000/applications,查看监控信息
3.4 查看访问次数UserController.java
package com.uni;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/findAll")
public String findAll() { return "success"; }
}
访问客户端访问三次:http://localhost:8080/user/findAll
访问服务端,并查看请求结果
3.5 查看注入Spring容器的Bean 3.6 查看部署项目线程实时的运行情况 3.7 IDEA 提供的监控可视化 四、SpringBoot 项目部署SpringBoot项目开发完毕后,支持两种方式部署到服务器:
jar包(官方推荐)war包 4.1 Jar
默认模式,创建SpringBoot项目后打包默认为Jar包
在IDEA中通过Maven插件进行打包
然后在终端运行jar包
java -jar *.jar4.2 war
pom.xml
war
SpringBoot启动类需要继承 SpringBootServletInitializer类并重写一个配置的方法
package com.uni;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class SpringbootDeployApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SpringbootDeployApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringbootDeployApplication.class);
}
}
然后使用 Maven打包成war包
若要指定包名则在 pom.xml 里的
将war包配置到外部的Tomcat
启动 Tomcat
访问网址:http://localhost:8080/springboot
五、收获与总结通过本次的学习,了解到了SpringBoot的四个监听机制,同时跟着视频资料对SpringBoot项目启动的过程进行了简单的调试,通过打断点来观察其运行的原理,调用了哪些类,然后调用了哪些方法,方法的作用等等。
第一次了解到SpringBoot的监听机制,这使笔者想到上学期刚学过的web里面servlet的监听器listener,可以监听servlet或者变量之类的。
通过这几天的学习,现在可以简单的使用SpringBoot进行开发,比如写一个web后端页面,使用全注解开发,然后配置的话只需要在application前缀的配置文件里进行修改,springboot的起步依赖机制真的太方便了,希望在以后的学习与实践中能够熟练运用。



