https://cloud.baidu.com/article/3318850https://blog.csdn.net/Andya_net/article/details/131188311
❤ SpringBoot 的启动流程
启动类的 main 方法
- 首先,从一个标注了 @SpringBootApplication 的 main 方法开始
- 运行 run() 方法,把主类,和 args 参数传递进去
@SpringBootApplication
public class KafkaApplication {
public static void main(String[] args) {
SpringApplication.run(KafkaApplication.class, args);
}
}创建 ApplicationContext
根据应用类型,创建相应的 ApplicationContext
刷新 ApplicationContext
加载并初始化所有的 Bean
自动配置
根据依赖,和 application 配置文件进行自动配置
启动内嵌服务器
如果是 Web 应用,则启动
执行 CommandLineRunner 和 ApplicationRunner
ApplicationRunner 是 SpringBoot 的启动运行器,它会在应用程序启动完成后执行一些初始化操作
@Component
public class KafkaProducerConfig {
// 在启动时,执行一些操作
@Bean
public ApplicationRunner runner(KafkaTemplate<String, String> kafkaTemplate) {
return args -> {
kafkaTemplate.send("TopicTwo", "Hello World");
};
}
}❤️ 环境上下文
SpringBoot 在启动后,在不同的运行阶段会设置扩展点,我们可以根据需求在指定阶段,执行自定义的代码
ApplicationContext
[!quote]
ApplicationContext【应用上下文】ApplicationContext是 Spring 核心接口之一,是 Spring 中实现 IOC 和 DI 的容器,用于存储应用程序运行时所需的各种 Bean 对象,并负责实例化,配置,组装这些 Bean【当一个 Bean 需要另一个 Bean 作为依赖时,ApplicationContext就会负责寻找和注入相应的 Bean】
一旦 `ApplicationContext` 已经刷新,Bean 的定义就不能再被修改了,**但是,你应该尽量避免在运行时修改 Bean 的定义,而是应该在配置阶段就确定好 Bean 的定义**
ApplicationContext 包含一个 Environment,这个 Environment 保存了所有跟应用程序运行环境有关的属性【系统环境变量,JVM 系统属性,命令行参数,应用程序配置文件……】
ApplicationContextInitializer
[!quote]
ApplicationContextInitializerApplicationContextInitializer就是 SpringBoot 众多扩展点中的一个,在 IOC 容器创建完成后,ApplicationContext刷新前【完全初始化 Bean 之前】执行
[!hint]
ApplicationContextInitializer的作用对上下文环境做一些操作:
- 动态改变 Spring 配置属性【修改 Bean 定义】
- 修改
ApplicationContext的环境属性你可以根据运行环境的不同,动态地修改应用程序的配置【你可能在开发环境和生产环境中使用不同的数据库配置,或者在不同的服务器上运行时使用不同的服务端口 ……】
具体实现 :
- 创建一个类,实现
ApplicationContextInitializer接口,并继承initialize 方法
package com.example.web_2.initializer;
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// 准备属性
Map<String, Object> myMap = new HashMap<>();
myMap.put("applicationName", "big-events");
// 获取环境对象
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 获取属性源
MutablePropertySources propertySources = environment.getPropertySources();
// 添加属性
propertySources.addLast(new MapPropertySource("myPropertySource", myMap));
}
}- 在
META-INF/spring.factories中注册这个初始化器
# 接口的全类名=实现类的全类名
org.springframework.context.ApplicationContextInitializer=com.example.web_2.initializer.MyApplicationContextInitializer- 测试一下
@SpringBootApplication
public class Web2Application {
public static void main(String[] args) {
// 获取上下文对象
ConfigurableApplicationContext run = SpringApplication.run(Web2Application.class, args);
String applicationName = run.getEnvironment().getProperty("applicationName");
System.out.println("applicationName = " + applicationName);
}
}
---
applicationName = big-events❤ 禁用依赖
有时我们想快速启动项目,不使用某些在 Maven 中引入的依赖,比如数据库,消息队列 …… ,我们可以直接禁用掉用到这些依赖的 Bean 加载
- 在启动类加上
exclude,就能快速禁用某些依赖的自动加载
@SpringBootApplication(exclude = {RocketMQAutoConfiguration.class})- 禁用了 RocketMQ Bean 的初始化后,我们还要对用到这个 Bean 的地方进行
@Lazy懒加载,让其不会因为缺失 Bean 而报错
public class MQProducer {
@Autowired
@Lazy
private RocketMQTemplate rocketMQTemplate;
}❤️ 线程池
NOTE
Spring 默认有一个 main 主线程,这个线程是用来启动 Spring 和初始化 App 资源的。Spring 主要依靠 Servlet 容器中的线程池来处理大量的并发用户请求
如果你需要执行异步任务,但是你又不单独配置异步线程池,那么异步任务就会和 Servlet 容器中的线程抢夺资源
💛 异步线程池
异步执行线程池只专注于异步任务执行,需要加上 @EnableAsync
@Configuration
public class AsyncTaskConfig {
@Bean(name = "myAsyncExecutorThreadPool")
public Executor myAsyncExecutorThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(30); // 核心线程数
executor.setMaxPoolSize(50); // 最大线程数
executor.setQueueCapacity(100); // 队列容量
executor.setThreadNamePrefix("MyAsyncExecutorThreadPool - ");
executor.initialize();
return executor;
}
}// 使用
@Async("myAsyncExecutorThreadPool")
public Future<String> asyncTask() {
// 模拟耗时任务
Thread.sleep(2000);
System.out.println("异步任务执行完毕");
return new AsyncResult<>("Task Completed");
}❤️ 虚拟线程
❤️ 其他操作
将 tomcat 改为 undertow :undertow 比 tomcat 更适合高并发
- 更新依赖
<dependencies>
<!-- 移除 Spring Boot 默认的 tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加 Undertow -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
</dependencies>- yml 配置
server:
port: 8080
undertow:
io-threads: 8
worker-threads: 64
buffer-size: 1024
direct-buffers: true