目录
spring-boot-starter-* 是官方的命名规范,其他第三方依赖 thirdpartyproject-spring-boot-starter
classpath 等价于 main/java + main/resources + 第三方 jar 包的根目录
classpath*:不仅包含 class 路径,还包括 jar 文件中(class路径)进行查找。而且不仅限于 classes 当前目录下,也会对其子目录进行搜索。
file: 作为URL从文件系统中加载,这种方式通常配置相对路径,相对于当前 jar 包所在路径。另外 file:/// 通常表示的是本地文件的绝对路径
@Value不能注入static字段,可通过setter方法注入// yml文件:config.jwt.expire: 1000 * 60 * 60 * 24 * 7
public static long expire; // 过期时间,单位毫秒
public static String secret; // 密钥长度≥4
// #用于注入Spel表达式,$是占位符,字符串替换
("#{${config.jwt.expire}}")
public void setExpire(long expire){
JwtUtils.expire = expire;
}
("${config.jwt.secret}")
public void setSecret(String secret){
JwtUtils.secret = secret;
}
类上需有 @Component 注解,将类交由 Spring 容器管理
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
当你创建一个Bean定义时,你创建了一个“配方”,用于创建该Bean定义(definition)是所定义的类的实际实例
在容器本身中,这些Bean定义被表示为 BeanDefinition 对象,它包含(除其他信息外)以下元数据。
当容器被创建时,Spring容器会验证每个Bean的配置。然而,在实际创建Bean之前,Bean的属性本身不会被设置。当容器被创建时,那些具有单例作用域并被设置为预实例化的Bean(默认)被创建。作用域在 Bean Scope 中定义。否则,Bean只有在被请求时才会被创建。
默认情况下,ApplicationContext 的实现会急切地创建和配置所有的 单例 Bean,作为初始化过程的一部分。一般来说,这种预实例化是可取的,因为配置或周围环境中的错误会立即被发现。懒加载的 bean 告诉IoC容器在第一次被请求时创建一个bean实例,而不是在启动时。这种行为是由 元素上的 lazy-init 属性控制的,<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
| Scope | 说明 |
|---|---|
| singleton | (默认情况下)为每个Spring IoC容器将单个Bean定义的Scope扩大到单个对象实例。 |
| prototype | 将单个Bean定义的Scope扩大到任何数量的对象实例。 |
| request | 将单个Bean定义的Scope扩大到单个HTTP请求的生命周期。也就是说,每个HTTP请求都有自己的Bean实例,该实例是在单个Bean定义的基础上创建的。只在Web感知的Spring ApplicationContext 的上下文中有效。 |
| session | 将单个Bean定义的Scope扩大到一个HTTP Session 的生命周期。只在Web感知的Spring ApplicationContext 的上下文中有效。 |
| application | 将单个Bean定义的 Scope 扩大到 ServletContext 的生命周期中。只在Web感知的Spring ApplicationContext 的上下文中有效。 |
| websocket | 将单个Bean定义的 Scope 扩大到 WebSocket 的生命周期。仅在具有Web感知的 Spring ApplicationContext 的上下文中有效。 |
为了与容器对Bean生命周期的管理进行交互,你可以实现Spring InitializingBean 和 DisposableBean 接口
为同一个Bean配置的多个生命周期机制,具有不同的初始化方法,其调用方式如下。
当类A实现ApplicationContextAware接口时,Spring的ApplicationContext会在该类实例化之后,自动将自己(即整个应用上下文ApplicationContext)的引用注入到这个类中
public class MyBean implements ApplicationContextAware {
private ApplicationContext context;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
// 使用context来获取其他Bean或配置信息
当Spring创建了一个实现了 BeanNameAware 接口的对象时,它会自动为这个对象提供一个指向该对象在容器中定义的名字的引用。这样,该对象就可以知道自己在Spring容器中的名字,并根据这个名字来做相应的处理。
Spring还提供了一系列的 Aware 回调接口,让Bean向容器表明它们需要某种基础设施的依赖性。一般来说,名称表示依赖关系的类型
当你需要向容器索取一个实际的 FactoryBean 实例而不是它产生的Bean时,在调用 ApplicationContext 的 getBean() 方法时,在 Bean 的 id 前加上安培符号(&)。因此,对于一个 id 为 myBean 的 FactoryBean,在容器上调用 getBean("myBean") 会返回 FactoryBean 的产物,而调用 getBean("&myBean") 会返回 FactoryBean 实例本身。
Spring BeanPostProcessor 在幕后使用一个 ConversionService 来处理将 @Value 中的 String 值转换为目标类型的过程。如果你想为你自己的自定义类型提供转换支持,你可以提供你自己的 ConversionService Bean实例,如下例所示。
public class AppConfig {
public ConversionService conversionService() {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(new MyCustomConverter());
return conversionService;
}
}
ApplicationContext 创建之前就被触发了,不能在这些事件上注册监听器,可以通过 SpringApplication.addListeners(…) 和 SpringApplicationBuilder.listeners(…) 创建。还可以在 META-INF/spring.factories 中添加监听器 org.springframework.context.ApplicationListener=com.example.project.MyListenerApplicationStartingEvent:在运行时的任何进程之前发生,除了监听器和初始化器除外ApplicationEnvironmentPrepareEvent:当 Environment 在 Context 已知但尚未创建之前使用的时候ApplicationContextInitializedEvent:当 ApplicationContext 准备好,并且 ApplicationContextInitializers 被调用但任何 bean 的定义被加载之前ApplicationPreparedEvent:仅在 refresh 开始前且 bean 的定义加载后ApplicationStartedEvent:在 context 刷新之后,且任何 application 和 command-line runners 调用之前AvailabilityChangeEvent:在 LivenessState.CORRECT 指明应用存活之后ApplicationFailedEvent:有在启动阶段有异常发生之后WebServerInitializedEvent:WebServer 就绪。ContextRefreshedEvent:当 ApplicationContext 刷新之后CommandLineRunner 和 ApplicationRunner 组件执行,而不是使用 Spring 组件生命周期回调,如 @PostConstruct。CommandLineRunner 和 ApplicationRunner。ApplicationArguments 访问传递给 main 函数的参数 String[] argsCommandLineRunner 和 ApplicationRunner 接口。非常适合在应用程序启动后但在开始接受流量之前运行的任务。他们中声明了一个 run 方法。多个实现的话需要 org.springframework.core.Ordered 接口或 org.springframework.core.annotation.Order 注解指定顺序。import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setApplicationStartup(new BufferingApplicationStartup(2048));
application.run(args);
}
}
FlightRecorderApplicationStartup 可以记录 JVM 事件,例如分配,GC,类加载,java -XX:StartFlightRecording:filename=recording.jfr,duration=10s -jar demo.jar 记录SpringApplication.setDefaultProperties@PropertySource 注解,用在 @Configuration 的类上。不能用在 Environment 上application.propertiesRandomValuePropertySource 的属性仅为 random.*。System.getProperties()java:com/envServletContext 初始化参数ServletConfig 初始化参数SPRING_APPLICATION_JSON 的属性(嵌入在环境变量或系统属性中的内联 JSON)。test 中的 properties 属性,@DynamicPropertySource、@TestPropertySource$HOME/.config/spring 引导目录中的 Devtools 全局设置属性。application.properties 和 YAML (properties 优先于 YAML)application-{profile}.properties 和 YAML application.properties 和 YAML application-{profile}.properties 和 YAML --server.port=9000 转换为 properties 并添加到 Spring Environment,SpringApplication.setAddCommandLineProperties(false) 禁止添加到 Spring Environmentmy.name=test 等价于 $ java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar 和 $ java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}'java -Dspring.xxx -jar xxx.jar D 用于配置系统属性(JVM属性),这些属性可以在 Java 应用程序中通过 System.getProperty() 方法获取java -jar xxx.jar --spring.xxx 用于直接传递应用程序的配置参数,使用 @Value 或 environment.getProperty("spring.profiles.active") 获取/config 包、当前目录、当前目录的 config/ 子目录、config/ 子目录的直接子目录myproject.properties:$ java -jar myproject.jar --spring.config.name=myproject$ java -jar myproject.jar --spring.config.location=optional:classpath:/default.properties, optional:classpath:/override.properties,使用前缀 optional:如果位置是可选的,并且您不介意它们不存在。application.properties 使用 #--- or !--- 区分多个配置环境my
secret"${random.value}"
number"${random.int}"
bignumber"${random.long}"
uuid"${random.uuid}"
number-less-than-ten"${random.int(10)}"
number-in-range"${random.int[1024,65536]}"
ApplicationContext 是 BeanFactory 的子接口,BeanFactory 提供了配置框架和基础功能,ApplicationContext 提供了更多企业特定功能。
在 Spring 中,构成应用程序骨干并由 Spring IoC 容器管理的对象称为 bean,bean 是由 Spring IoC 容器实例化、组装和管理的对象。
容器通过读取配置元数据来获取关于实例化、配置和组装哪些对象的指令。配置元数据以XML、Java注释或Java代码表示。它允许您表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。
在容器本身中,这些 bean 定义表示为 BeanDefinition 对象,其中包含(除其他信息外)以下元数据:
bean 的实际实现类。依赖注入:对象定义依赖关系有以下几种方式:
当创建 bean 的时候容器注入这些依赖,而不用显示的去初始化等操作,也不需要指定类的位置,解耦程序
// 直接创建对象,耦合度高
class A{
B b = new B();
}
// 依赖注入,通过构造函数,此时A不需要关注如何创建对象,只需要会使用就可以
class A{
private B b;
// 使用 spring 直接注入
A(B b){
this.b = b;
}
}
bean 就是已经初始化的对象,交给容器管理bean 在被注入前肯定是一个完备的状态自动装配有四种模式:
no:默认值,不自动装配byName:容器找与属性同名的 bean 注入byType:通过类型查找,如果存在多个同类型的 bean 则发生异常constructor:类似于 byType 但是通过构造函数注入bean 的范围
singleton:单例prototype:原型,每次调用 applicationContext.getBean 都返回不同的实例。spring 不会管理原型 bean 的生命周期,通常需要自定义 bean 的销毁方法以清理资源request:在每个请求是单例的session:在每个会话中是单例的application:在一个 ServletContext 是单例的,ServletContext 的范围是整个 Web 应用,其范围大于 ApplicationContxtwebsocket:在一个 WebSocket 周期内是单例的bean 初始化和销毁时执行 InitializingBean 接口的 afterPropertiesSet() 方法和 DisposableBean 接口的 destory() 方法完成指定的操作。或者使用 @PostConstruct 和 @PreDestory 注解。还可使用 @Bean 的 initMethod 和 destroyMethod 属性BeanPostProcessor 实现来处理它能找到的任何回调接口,并调用相应的方法。类似的还有 Lifecycle 接口bean 实例只有在从 @PostConstruct 方法返回后才被视为完全初始化并准备好发布给其他人。XXXAware 接口通常是让 bean 意识到 XXX 存在,例如 ApplicationContextAware 接口定义了一个 setApplicationContext(ApplicationContext applicationContext) 让 bean 可以获得 applicationContext 的引用。BeanNameAware 获得 beanName 的引用bean 的实例化、配置和初始化后实现一些自定义逻辑,你可以插入一个或多个自定义 BeanPostProcessor 接口实现(也是作为一个 bean,容器会自动调用其方法)。BeanPostProcessor 提供了两种方法来扩展 Spring 的 bean 生命周期:postProcessBeforeInitialization(Object bean, String beanName): 在bean初始化之前调用。postProcessAfterInitialization(Object bean, String beanName): 在bean初始化之后调用。bean 定义(即定义bean的蓝图),您需要使用 BeanFactory PostProcessor 接口,PropertyOverrideConfigurer 和 PropertySourcesPlaceholderConfigurer 是预定义的两个子接口FactoryBean<T> 是自定义 bean 实例化的回调接口,提供三个方法:T getObject() 返回对象的实例,boolean isSingleton() 返回是否为单例,默认为 true,Class<?> getObjectType() 返回对象的类型,或 nullFactoryBean 实例本身而不是它生成的 bean时,在调用 ApplicationContext 的g etBean() 方法时,在 bean 的 id 前加上与号(&)。因此,对于 id 为 myBean 的给定 FactoryBean,在容器上调用 getBean("myBean") 会返回 FactoryBean 产生的 bean,而调用 getBean("&myBean") 则返回 FactoryBean 实例本身。@Autowired 用于众所周知的可解析依赖关系的接口:BeanFactory、ApplicationContext、Environment、ResourceLoader、ApplicationEventPublisher和MessageSource。@Configuration 中的 @Bean 会被 CGLIB 代理,交由容器管理@Configuration 主要目的是作为 bean 定义的来源。@Configuration 配置类允许通过调用同一类中的其他 @Bean 方法来定义 bean 之间的依赖关系。@Bean 方法在没有用 @Configuration 注释的类中声明时,它们被称为以 “lite” 模式处理。@DependsOn("myBean") 注解用于表示当前 bean 要在 myBean 初始化完成之后才能开始初始化ContextRefreshedEvent:当 ApplicationContext 被初始化或刷新时发布此事件。
ContextStartedEvent:当通过 ConfigurableApplicationContext 接口上的 start() 方法启动 ApplicationContext 时发布此事件。
ContextStoppedEvent:当通过 ConfigurableApplicationContext 接口上的 stop() 方法停止 ApplicationContext 时发布此事件
ContextClosedEvent:当通过 ConfigurableApplicationContext 接口上的 close() 方法关闭 ApplicationContext 或者通过 JVM 关闭钩子关闭时发布此事件。
RequestHandledEvent:这是一个特定于Web应用的事件,用于告诉所有 bean 一个 HTTP 请求已被服务。此事件在请求完成后发布。此事件仅适用于使用 Spring 的 DispatcherServlet 的Web应用程序。
ServletRequestHandledEvent:这是 RequestHandledEvent 的子类,增加了与 Servlet 相关联的上下文信息。这使得事件携带者可以包含更多的细节,如请求和响应对象,这对于某些需要访问请求特定信息的场景非常有用。
通过实现 ApplicationListener<ApplicationEvent> 接口并重写 onApplicationEvent(ApplicationEvent event) 方法,开发者可以订阅这些事件并做出相应的处理。
bean 实现 ApplicationListener 接口,当事件发布到 ApplicationContext 时,就会通知 bean 执行预定义的操作。目前也有基于注解的实现方式,不再需要继承 ApplicationEvent。
在方法上使用 @EventListener,方法参数中使用 ApplicationEvent,或者同时监听多个事件,使用非参数化的方式 @EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})。也可使用条件属性:@EventListener(condition = "#blEvent.content == 'my-event'")。更改方法签名,可以在响应 A 事件后再发布新的 B 事件:BEvent do(AEvent){}
使用 @Async 结合 @EventListener 发布异步事件
使用 @Order(n) 确定监听器执行顺序
topic,如果需要发送到 queue 可以使用 @SendTo 或 SimpMessagingTemplate)一般订阅topic和queue,不同的消息代理对不同的地址前缀有不同的行为,对于RabbitMQ,参考该连接 https://www.rabbitmq.com/docs/stomp#d
/queue/<name>:对于SUBSCRIBE帧,会创建一个名为 <name> 的队列,用于存储订阅者信息。对于SEND帧,只有在第一次发送时才会创建名为 <name> 的队列,消息被发送到默认交换机(amq.topic)以 <name> 作为绑定键。可以在发送帧时指定队列的参数,默认创建的是持久化、非排他、非自动删除的队列。/topic/<name>:对于SEND帧,消息被发送到默认交换机(amq.topic)以 <name> 作为路由键。对于SUBSCRIBE帧,创建一个非持久化、自动删除的队列,绑定到默认交换机(amq.topic)以 <name> 作为路由键。可以在发送帧时指定队列的参数。对于应用而言,发送SUBSCRIBE时应该使用topic和queue地址,发送SEND帧时,以app为地址。
当订阅 /user/queue/position-updates 时,代理中继内部的 UserDestinationMessageHandler 会将该地址转换成 /queue/position-updates-user123 与用户会话相关联的独一无二的地址,避免订阅通用地址时的冲突问题。
客户端发送消息是在@MessageMapping处理,订阅是目的地(destination)
前端的stompClient应该全局的,放在pinia中
两个问题:
订阅:/user/exchange/chat
发送:/app/privateMessage,数据是MessageDto,后端在发送到/exchange/chat地址,用户flm
遇到的问题:订阅/user/exchange,并没有新建队列
SimpMessagingTemplate发送非指定用户并没有反应
| 注解 | 用途 | 绑定来源 | 典型 Content-Type | 是否支持文件 |
|---|---|---|---|---|
| @RequestParam | 绑定 表单字段 或 URL 查询参数 | application/x-www-form-urlencoded 或 multipart/form-data 中的 字段名 | application/x-www-form-urlencoded, multipart/form-data | ✅ 可绑定 MultipartFile(当字段是文件时) |
| @RequestBody | 绑定 整个请求体 为一个对象(通常 JSON) | 请求体的原始字节流,经 HttpMessageConverter(如 Jackson)反序列化 | application/jsonapplication/xml 等 | ❌ 不支持文件(因为文件不是结构化文本) |
| @RequestPart | 用于 multipart/form-data 中的 复杂部分(如 JSON 对象或文件) | multipart 请求中的某一个 part(可包含 JSON 或二进制) | multipart/form-data | ✅ 支持文件,也支持 JSON part |
为什么 @RequestBody 和 MultipartFile 不能共用?
Content-Type@RequestBody 要求请求体是 纯 JSON → Content-Type 必须是 application/jsonmultipart/form-data → 这是一种多部分混合格式,包含文本字段和二进制数据前端传参时使用 FormData,重要:不要手动设置 Content-Type,否则浏览器不会生成正确的 boundary,导致后端解析失败。浏览器会自动设置 boundary
Swagger(OpenAPI)常用注解说明

@RequestPart 使用方式,用于复杂对象,平常可使用 @RequestParam 接收json字符串,后端转为对象
(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> upload(
("file") MultipartFile file,
("user") User user) { // ← 关键:直接绑定为对象
System.out.println("文件名: " + file.getOriginalFilename());
System.out.println("用户名: " + user.getName());
System.out.println("年龄: " + user.getAge());
return ResponseEntity.ok("上传成功");
}
public class User {
private String name;
private int age;
// getter/setter/toString
}
// 前端传参
const user = { name: "张三", age: 25 };
// 创建一个 Blob,内容是 JSON 字符串,类型是 application/json
const userBlob = new Blob([JSON.stringify(user)], {
type: 'application/json'
});
const formData = new FormData();
formData.append('file', document.querySelector('#fileInput').files[0]);
formData.append('user', userBlob); // ← 注意:不是 append('user', JSON.stringify(...))
fetch('/api/upload', {
method: 'POST',
body: formData
// 不要设置 headers! 浏览器会自动设置 multipart 和 boundary
});
// 场景 1️⃣:接收复杂对象集合(如 List<User>)
("/users/batch")
public ResponseEntity<?> createUsers( List<User> users) {
// users 是 List<User>,User 包含 name, age 等字段
return ResponseEntity.ok(users);
}
const users = [
{ name: "张三", age: 25 },
{ name: "李四", age: 30 }
];
// ✅ 前端 AJAX(必须用 JSON)
fetch('/api/users/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(users) // ← 整个请求体就是数组
});
// 场景 2️⃣:接收简单类型集合(如 List<Long>、String[])
// 方式 A:作为 查询参数(Query Parameter)
("/users")
public List<User> getUsersByIds( List<Long> ids) {
return userService.findByIds(ids);
}
// 方式1:重复参数名(Spring 默认支持)
fetch('/api/users?ids=1&ids=2&ids=3')
// 方式2:用逗号分隔(需配置)
fetch('/api/users?ids=1,2,3')
方式 B:作为 表单字段(Form Data)
(value = "/delete", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public void deleteUsers( List<Long> ids) {
// ...
}
const formData = new URLSearchParams();
formData.append('ids', '1');
formData.append('ids', '2'); // 重复 append
fetch('/api/delete', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: formData
});


initialize方法。这个接口的主要目的是在 Spring 应用上下文初始化的早期阶段进行一些配置或调整,以便在上下文加载后可以使用这些配置。public class EnvironmentInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
environment.setActiveProfiles("development");
System.out.println("配置文件设置为development");
}
}
public class CustomBeanFactoryPostProcessorInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
// 添加自定义的 BeanFactoryPostProcessor
System.out.println("添加了自定义BeanFactory后处理器...");
});
}
}
public class PropertySourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
public void initialize(ConfigurableApplicationContext applicationContext) {
MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
propertySources.addFirst(new MapPropertySource("customPropertySource", Collections.singletonMap("customKey", "customValue")));
System.out.println("已添加自定义属性源");
}
}
// 1. 手动调用的setXXX方法添加
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
// Add initializer
context.addApplicationListener(new TestApplicationContextInitializer());
// Set config locations and refresh context
context.setConfigLocation("classpath:applicationContext.xml");
context.refresh();
// Use the context
// ...
context.close();
// 2. Spring 的 XML 配置文件中注册
<context:initializer class="com.seven.springsrpingbootextentions.extentions.TestApplicationContextInitializer"/>
// 3. web.xml 文件配置
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.seven.springsrpingbootextentions.extentions.TestApplicationContextInitializer</param-value>
</context-param>
public class TestApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
public void initialize(ConfigurableApplicationContext applicationContext) {
MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
// 创建自定义的属性源
Map<String, Object> customProperties = new HashMap<>();
customProperties.put("custom.property", "custom value");
MapPropertySource customPropertySource = new MapPropertySource("customPropertySource", customProperties);
// 将自定义属性源添加到应用程序上下文的属性源列表中
propertySources.addFirst(customPropertySource);
}
}
// 在启动类中用springApplication.addInitializers(new TestApplicationContextInitializer())语句加入
public class MySpringExApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MySpringExApplication.class);
application.addInitializers(new TestApplicationContextInitializer()); // 直接在SpringApplication中添加
application.run(args);
}
}
// 2. application配置文件 配置 com.seven.springsrpingbootextentions.extentions.TestApplicationContextInitializer
# application.yml文件
context:
initializer:
classes: com.seven.springsrpingbootextentions.extentions.TestApplicationContextInitializer
// 3. Spring SPI扩展,在spring.factories中加入(官方推荐):
com.seven.springsrpingbootextentions.extentions.TestApplicationContextInitializer
public class PropertyModifierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myBean");
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
propertyValues.addPropertyValue("propertyName", "newValue");
}
}
public class ConditionalBeanRegistrar implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (someCondition()) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MyBean.class);
beanFactory.registerBeanDefinition("myConditionalBean", beanDefinitionBuilder.getBeanDefinition());
}
}
private boolean someCondition() {
// 自定义条件逻辑
return true;
}
}
public class ScopeModifierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myBean");
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
}
}
public class CustomPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
throws BeansException {
super.processProperties(beanFactory, props);
// 自定义属性处理逻辑
}
}
public class BeanDefinitionModifier implements BeanDefinitionRegistryPostProcessor {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("在 postProcessBeanDefinitionRegistry 中修改现有的 BeanDefinition");
if (registry.containsBeanDefinition("myExistingBean")) {
BeanDefinition beanDefinition = registry.getBeanDefinition("myExistingBean");
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
propertyValues.add("propertyName", "newValue");
}
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 此方法可以留空或用于进一步处理
}
}
public class ConditionalBeanRegistrar implements BeanDefinitionRegistryPostProcessor {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("在 postProcessBeanDefinitionRegistry 中根据条件注册 Bean");
if (someCondition()) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(ConditionalBean.class)
.getBeanDefinition();
registry.registerBeanDefinition("conditionalBean", beanDefinition);
}
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 此方法可以留空或用于进一步处理
}
private boolean someCondition() {
// 自定义条件逻辑
return true;
}
}
public class CustomAnnotationBeanRegistrar implements BeanDefinitionRegistryPostProcessor {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("在 postProcessBeanDefinitionRegistry 中扫描并注册自定义注解的 Bean");
// 自定义扫描逻辑,假设找到一个类 MyAnnotatedBean
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(MyAnnotatedBean.class)
.getBeanDefinition();
registry.registerBeanDefinition("myAnnotatedBean", beanDefinition);
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 此方法可以留空或用于进一步处理
}
}
public class AppConfig {
public static BeanDefinitionRegistryPostProcessor customBeanDefinitionRegistryPostProcessor() {
return new BeanDefinitionRegistryPostProcessor() {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("在 postProcessBeanDefinitionRegistry 中根据条件注册缓存实现类");
try {
// 检查 Redis 依赖是否存在
Class.forName("redis.clients.jedis.Jedis");
System.out.println("检测到 Redis 依赖,注册 RedisCacheService");
AbstractBeanDefinition redisCacheBeanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(RedisCacheService.class)
.getBeanDefinition();
registry.registerBeanDefinition("cacheService", redisCacheBeanDefinition);
} catch (ClassNotFoundException e) {
System.out.println("未检测到 Redis 依赖,注册 LocalCacheService");
AbstractBeanDefinition localCacheBeanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(LocalCacheService.class)
.getBeanDefinition();
registry.registerBeanDefinition("cacheService", localCacheBeanDefinition);
}
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 此方法可以留空或用于进一步处理
}
};
}
}
MapperScannerConfigurer 的主要功能是通过扫描指定的包路径,找到所有标注了 @Mapper 注解(或其他指定注解)的接口,并将这些接口注册为 Spring 的 BeanDefinition。这样,Spring 容器在启动时会自动创建这些 Mapper 接口的代理对象,并将其注入到需要的地方。// org.mybatis.spring.mapper.MapperScannerConfigurer#postProcessBeanDefinitionRegistry
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
private String basePackage;
private ApplicationContext applicationContext;
public void setBasePackage(String basePackage) {
this.basePackage = basePackage;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
//设置其资源加载器为当前的 ApplicationContext
scanner.setResourceLoader(this.applicationContext);
scanner.registerFilters();
//调用 scanner.scan(this.basePackage) 方法,扫描指定的包路径,找到所有符合条件的 Mapper 接口,并将它们注册为 Spring 的 BeanDefinition。
scanner.scan(this.basePackage);
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 此方法可以留空或用于进一步处理
}
}
BeanFactoryPostProcessor是BeanDefinitionRegistryPostProcessor的父类,因此实现BeanDefinitionRegistryPostProcessor这个接口,也可以重写其父类。但实现了BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法会先执行,再执行实现了BeanFactoryPostProcessor的postProcessBeanFactorypostProcessBeforeInitialization:在 Bean 初始化方法(如 @PostConstruct、InitializingBean.afterPropertiesSet 或自定义初始化方法)调用之前执行;返回的对象将是实际注入到容器中的 Bean,如果返回 null,则该 Bean 不会被注册。可用于创建代理类postProcessAfterInitialization:初始化bean之后,返回的对象将是实际注入到容器中的 Bean,如果返回 null,则该 Bean 不会被注册。
public class CustomBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
System.out.println("bean初始化前: " + beanName);
((MyBean) bean).setName("Modified Name Before Initialization");
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
System.out.println("bean初始化后: " + beanName);
}
return bean;
}
}
public class ProxyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(bean.getClass());
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method: " + method.getName());
return result;
}
});
return enhancer.create();
}
return bean;
}
}
public class LoggingBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("开始初始化bean: " + beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化bean结束: " + beanName);
return bean;
}
}
public class AutowireBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(AutowireCustom.class)) {
field.setAccessible(true);
try {
field.set(bean, "Injected Value");
} catch (IllegalAccessException e) {
throw new BeansException("Failed to autowire field: " + field.getName(), e) {};
}
}
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
(RetentionPolicy.RUNTIME)
public @interface AutowireCustom {
}
public class MyBean {
private String customField;
public MyBean() {
}
public String toString() {
return "MyBean{customField='" + customField + "'}";
}
}
该接口继承了BeanPostProcessor接口,因为InstantiationAwareBeanPostProcessor也属于Bean级的后置处理器,区别如下:BeanPostProcess接口只在bean的初始化阶段进行扩展(注入spring上下文前后),而InstantiationAwareBeanPostProcessor接口在此基础上增加了3个方法,把可扩展的范围增加了实例化阶段和属性注入阶段。
该类主要的扩展点有以下6个方法,其中有两个是BeanPostProcessor的扩展,主要在bean生命周期的两大阶段:实例化阶段和初始化阶段,按调用顺序为:
postProcessBeforeInstantiation:在Bean实例化之前调用,如果返回null,一切按照正常顺序执行;如果返回的是一个实例的对象,那么postProcessAfterInstantiation()会执行,其他的扩展点将不再触发。
postProcessAfterInstantiation:在Bean实例化之后调用,可以对已实例化的Bean进行进一步的自定义处理。
postProcessPropertyValues(方法在spring5.1版本后就已弃用):bean已经实例化完成,在属性注入时阶段触发,@Autowired,@Resource等注解原理基于此方法实现;可以修改Bean的属性值或进行其他自定义操作,当postProcessAfterInstantiation返回true才执行。
postProcessBeforeInitialization(BeanPostProcessor的扩展):初始化bean之前,相当于把bean注入spring上下文之前;可用于创建代理类,如果返回的不是 null(也就是返回的是一个代理类) ,那么后续只会调用 postProcessAfterInitialization() 方法
postProcessAfterInitialization(BeanPostProcessor的扩展):初始化bean之后,相当于把bean注入spring上下文之后;返回值会影响 postProcessProperties() 是否执行,其中返回 false 的话,是不会执行。
postProcessProperties():在 Bean 设置属性前调用;用于修改 bean 的属性,如果返回值不为空,那么会更改指定字段的值
InstantiationAwareBeanPostProcessor和 BeanPostProcessor 是可以同时被实现的,并且也会同时生效,但是InstantiationAwareBeanPostProcessor的执行时机要稍早于BeanPostProcessor
public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanClass == MyBean.class) {
System.out.println("实例化之前替换 Bean: " + beanName);
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanClass);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("调用方法: " + method.getName());
return proxy.invokeSuper(obj, args);
}
});
return enhancer.create();
}
return null;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后的 Bean: " + beanName);
return bean;
}
}
public class DependencyInjectionControlPostProcessor implements InstantiationAwareBeanPostProcessor {
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
System.out.println("实例化之后控制依赖注入: " + beanName);
return false; // 不进行默认的依赖注入
}
return true;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后的 Bean: " + beanName);
return bean;
}
}
public class PropertyModificationPostProcessor implements InstantiationAwareBeanPostProcessor {
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
System.out.println("设置属性值之前: " + beanName);
// 修改属性值的逻辑
}
return pvs;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后的 Bean: " + beanName);
return bean;
}
}
SmartInstantiationAwareBeanPostProcessor 与其他扩展点最明显的不同,就是在实际的业务开发场景中应用到的机会并不多,主要是在Spring内部应用。
该扩展接口有3个触发点方法:
predictBeanType:该触发点发生在postProcessBeforeInstantiation之前(也就是在 InstantiationAwareBeanPostProcessor的方法之前,在图上并没有标明,因为一般不太需要扩展这个点),这个方法用于预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测,则返回null;当调用BeanFactory.getType(name)时当通过bean的名字无法得到bean类型信息时就调用该回调方法来决定类型信息。
determineCandidateConstructors:该触发点发生在postProcessBeforeInstantiation之后,用于决定使用哪个构造器构造Bean,返回的是该bean的所有构造函数列表;如果不指定,默认为null,即bean的无参构造方法。用户可以扩展这个点,来自定义选择相应的构造器来实例化这个bean。
getEarlyBeanReference:该触发点发生在postProcessAfterInstantiation之后,主要用于Spring循环依赖问题的解决,如果Spring中检测不到循环依赖,这个方法不会被调用;当存在Spring循环依赖这种情况时,当bean实例化好之后,为了防止有循环依赖,会提前暴露回调方法,用于bean实例化的后置处理,会在InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法触发执行之后执行;
同InstantiationAwareBeanPostProcessor,由于SmartInstantiationAwareBeanPostProcessor 是 InstantiationAwareBeanPostProcessor的子类,因此SmartInstantiationAwareBeanPostProcessor 也同样能扩展 InstantiationAwareBeanPostProcessor的所有方法。但是如果有两个类分别重写了 SmartInstantiationAwareBeanPostProcessor 和 InstantiationAwareBeanPostProcessor 的方法,那么重写 InstantiationAwareBeanPostProcessor 的类的方法会先于重写了 SmartInstantiationAwareBeanPostProcessor的类的方法(注意,这里说的是两者都有的方法)。
public class CustomConstructorSelectionPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
if (beanClass == MyBean.class) {
System.out.println("选择自定义构造函数: " + beanName);
try {
return new Constructor<?>[] { beanClass.getConstructor(String.class) };
} catch (NoSuchMethodException e) {
throw new BeansException("找不到指定的构造函数", e) {};
}
}
return null;
}
}
public class MyBean {
private String name;
public MyBean() {
this.name = "Default Name";
}
public MyBean(String name) {
this.name = name;
}
public String toString() {
return "MyBean{name='" + name + "'}";
}
}
-解决循环依赖问题:通过提供早期 Bean 引用,解决循环依赖问题。
public class EarlyBeanReferencePostProcessor implements SmartInstantiationAwareBeanPostProcessor {
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
System.out.println("获取早期 Bean 引用: " + beanName);
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(bean.getClass());
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("调用方法: " + method.getName());
return proxy.invokeSuper(obj, args);
}
});
return enhancer.create();
}
return bean;
}
}
public class BeanTypePredictionPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
if (beanClass == MyBean.class) {
System.out.println("预测 Bean 类型: " + beanName);
return MyBean.class;
}
return null;
}
}
postProcessBeforeInitialization之前,这个类的触发点方法只有一个:setBeanName。
public class LoggingBean implements BeanNameAware {
private String beanName;
public void setBeanName(String name) {
this.beanName = name;
System.out.println("设置 Bean 名称: " + name);
}
public void doSomething() {
System.out.println("正在执行某些操作, 当前 Bean 名称: " + beanName);
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
LoggingBean loggingBean = context.getBean(LoggingBean.class);
loggingBean.doSomething();
}
}
public class ConditionalLogicBean implements BeanNameAware {
private String beanName;
public void setBeanName(String name) {
this.beanName = name;
System.out.println("设置 Bean 名称: " + name);
}
public void performAction() {
if ("conditionalLogicBean".equals(beanName)) {
System.out.println("执行特定逻辑, 因为这是 conditionalLogicBean");
} else {
System.out.println("执行普通逻辑");
}
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ConditionalLogicBean conditionalLogicBean = context.getBean(ConditionalLogicBean.class);
conditionalLogicBean.performAction();
}
}
("beanA")
public class DynamicBeanA implements BeanNameAware {
private String beanName;
public void setBeanName(String name) {
this.beanName = name;
System.out.println("设置 Bean 名称: " + name);
}
public void execute() {
System.out.println("执行 Bean: " + beanName);
}
}
("beanB")
public class DynamicBeanB implements BeanNameAware {
private String beanName;
public void setBeanName(String name) {
this.beanName = name;
System.out.println("设置 Bean 名称: " + name);
}
public void execute() {
System.out.println("执行 Bean: " + beanName);
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
DynamicBeanA beanA = (DynamicBeanA) context.getBean("beanA");
DynamicBeanB beanB = (DynamicBeanB) context.getBean("beanB");
beanA.execute();
beanB.execute();
}
}
void setBeanClassLoader(ClassLoader classLoader):在某些需要动态加载类的场景中,获取 ClassLoader 是非常有用的。
public class DynamicClassLoader implements BeanClassLoaderAware {
private ClassLoader classLoader;
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
System.out.println("已设置类加载器");
}
public void loadClass(String className) {
try {
Class<?> clazz = classLoader.loadClass(className);
System.out.println("已加载类:" + clazz.getName());
} catch (ClassNotFoundException e) {
System.out.println("类未找到:" + className);
}
}
}
public class AppConfig {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AppConfig.class, args);
DynamicClassLoader dynamicClassLoader = context.getBean(DynamicClassLoader.class);
dynamicClassLoader.loadClass("java.util.ArrayList");
dynamicClassLoader.loadClass("不存在的类");
}
}
public class ClassAvailabilityChecker implements BeanClassLoaderAware {
private ClassLoader classLoader;
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
System.out.println("已设置类加载器");
}
public boolean isClassAvailable(String className) {
try {
Class<?> clazz = classLoader.loadClass(className);
System.out.println("类可用:" + clazz.getName());
return true;
} catch (ClassNotFoundException e) {
System.out.println("类不可用:" + className);
return false;
}
}
}
public class AppConfig {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AppConfig.class, args);
ClassAvailabilityChecker checker = context.getBean(ClassAvailabilityChecker.class);
checker.isClassAvailable("java.util.HashMap");
checker.isClassAvailable("不存在的类");
}
}
public class ResourceLoader implements BeanClassLoaderAware {
private ClassLoader classLoader;
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
System.out.println("已设置类加载器");
}
public void loadResource(String resourcePath) {
InputStream inputStream = classLoader.getResourceAsStream(resourcePath);
if (inputStream != null) {
System.out.println("资源已加载:" + resourcePath);
} else {
System.out.println("资源未找到:" + resourcePath);
}
}
}
public class AppConfig {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AppConfig.class, args);
ResourceLoader resourceLoader = context.getBean(ResourceLoader.class);
resourceLoader.loadResource("application.properties");
resourceLoader.loadResource("不存在的资源");
}
}
setBeanFactory,可以拿到BeanFactory这个属性,从而能够进行更复杂的 Bean 操作。例如,动态获取其他 Bean、检查 Bean 的状态等。
public class DynamicBeanFetcher implements BeanFactoryAware {
private BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.out.println("注入 BeanFactory 实例");
}
public void fetchAndUseBean() {
MyBean myBean = beanFactory.getBean(MyBean.class);
System.out.println("获取到的 Bean 实例: " + myBean);
}
}
public class MyBean {
public String toString() {
return "这是 MyBean 实例";
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
DynamicBeanFetcher fetcher = context.getBean(DynamicBeanFetcher.class);
fetcher.fetchAndUseBean();
}
}
public class BeanStateChecker implements BeanFactoryAware {
private BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.out.println("注入 BeanFactory 实例");
}
public void checkBeanState() {
boolean exists = beanFactory.containsBean("myBean");
System.out.println("MyBean 是否存在: " + exists);
}
}
("myBean")
public class MyBean {
public String toString() {
return "这是 MyBean 实例";
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
BeanStateChecker checker = context.getBean(BeanStateChecker.class);
checker.checkBeanState();
}
}
public class ComplexBeanInitializer implements BeanFactoryAware {
private BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.out.println("注入 BeanFactory 实例");
}
public void initializeComplexBean() {
MyBean myBean = beanFactory.getBean(MyBean.class);
System.out.println("初始化复杂 Bean, 获取到的 MyBean 实例: " + myBean);
// 在这里可以执行复杂的初始化逻辑
}
}
public class MyBean {
public String toString() {
return "这是 MyBean 实例";
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ComplexBeanInitializer initializer = context.getBean(ComplexBeanInitializer.class);
initializer.initializeComplexBean();
}
}
EnvironmentAware:用于获取Enviroment的一个扩展类,这个变量非常有用, 可以获得系统内的所有参数;另外也可以通过注入的方式来获得Environment,用哪种方式需要以实现场景而决定。当然个人认为这个Aware没必要去扩展,因为spring内部都可以通过注入的方式来直接获得。
EmbeddedValueResolverAware:用于获取StringValueResolver的一个扩展类, StringValueResolver可以获取基于String类型的properties的变量;但一般我们都用@Value的方式来获取properties的变量,用哪种方式需要以实现场景而决定。如果实现了这个Aware接口,把StringValueResolver缓存起来,通过这个类去获取String类型的变量,效果是一样的。
ResourceLoaderAware:用于获取ResourceLoader的一个扩展类,ResourceLoader可以用于获取classpath内所有的资源对象。
ApplicationEventPublisherAware:用于获取ApplicationEventPublisher的一个扩展类,ApplicationEventPublisher可以用来发布事件;这个对象也可以通过spring注入的方式来获得,结合ApplicationListener来共同使用,下文在介绍ApplicationListener时会详细提到。
MessageSourceAware:用于获取MessageSource的一个扩展类,MessageSource主要用来做国际化。
ApplicationContextAware:用来获取ApplicationContext的一个扩展类,ApplicationContext就是spring上下文管理器,可以手动的获取任何在spring上下文注册的bean。较多的做法是扩展这个接口来缓存spring上下文,包装成静态方法。 同时ApplicationContext也实现了BeanFactory,MessageSource,ApplicationEventPublisher等接口,也可以用来做相关接口的事情。
postProcessBeforeInitialization之后,InitializingBean.afterPropertiesSet之前。使用@PostConstruct注解标记的方法不能有参数,除非是拦截器,可以采用拦截器规范定义的InvocationContext对象。
使用@PostConstruct注解标记的方法不能有返回值,实际上如果有返回值,也不会报错,但是会忽略掉;
使用@PostConstruct注解标记的方法不能被static修饰,但是final是可以的;
与InitializingBean#afterPropertiesSet()类似效果的是init-method,但是需要注意的是InitializingBean#afterPropertiesSet()执行时机要略早于init-method;
InitializingBean#afterPropertiesSet()的调用方式是在bean初始化过程中直接调用bean的afterPropertiesSet();
bean自定义属性init-method是通过java反射的方式进行调用 ;
public class NormalBeanA implements InitializingBean{
org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
public class ResourceInitializer implements InitializingBean {
public void afterPropertiesSet() {
// 模拟资源初始化
System.out.println("资源初始化:建立数据库连接");
}
public void performAction() {
System.out.println("资源使用:执行数据库操作");
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ResourceInitializer initializer = context.getBean(ResourceInitializer.class);
initializer.performAction();
}
}
public class InitialValueSetter implements InitializingBean {
private String initialValue;
public void afterPropertiesSet() {
initialValue = "默认值";
System.out.println("设置初始值:" + initialValue);
}
public void printValue() {
System.out.println("当前值:" + initialValue);
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
InitialValueSetter valueSetter = context.getBean(InitialValueSetter.class);
valueSetter.printValue();
}
}
public class ConfigLoader implements InitializingBean {
private String configValue;
public void afterPropertiesSet() {
// 模拟配置加载
configValue = "配置值";
System.out.println("加载配置:" + configValue);
}
public void printConfig() {
System.out.println("当前配置:" + configValue);
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ConfigLoader configLoader = context.getBean(ConfigLoader.class);
configLoader.printConfig();
}
}
afterSingletonsInstantiated,其作用是在spring容器管理的所有单例对象(非懒加载对象)初始化完成之后调用的回调接口。其触发时机为postProcessAfterInitialization之后。实现SmartInitializingSingleton接口的bean的作用域必须是单例,afterSingletonsInstantiated()才会触发;
afterSingletonsInstantiated()触发执行时,非懒加载的单例bean已经完成实现化、属性注入以及相关的初始化操作;
afterSingletonsInstantiated()的执行时机是在DefaultListableBeanFactory#preInstantiateSingletons();
public class GlobalInitializer implements SmartInitializingSingleton {
public void afterSingletonsInstantiated() {
// 模拟全局初始化操作
System.out.println("全局初始化操作:启动全局调度任务");
}
}
检查系统状态:可以用于在所有单例 Bean 初始化之后检查系统状态,确保系统运行在预期状态下。
加载全局配置:可以在所有单例 Bean 初始化后加载全局配置,如从文件或数据库中读取配置,并应用到系统中。
一般情况下,Spring通过反射机制利用bean的class属性指定支线类去实例化bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在bean中提供大量的配置信息。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占有重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。
触发点:例如其他框架技术与Spring集成的时候,如mybatis与Spring的集成,mybatis是通过SqlSessionFactory创建出Sqlsession来执行sql的,那么Service层在调用Dao层的接口来执行数据库操作时肯定得持有SqlSessionFactory,那么问题来了:Spring容器怎么才能持有SqlSessionFactory呢?答案就是SqlSessionFactoryBean,它实现了FactoryBean接口。
FactoryBean 与 BeanFactory 的区别
FactoryBean 是一个特殊的 bean,其本身是一个bean,但又可创建其他的bean,专门用于创建特定类型的 Bean,想要获取FactoryBean本身,需要在bean名称前加 &
class ComplexObject {
private String name;
private int value;
public ComplexObject(String name, int value) {
this.name = name;
this.value = value;
}
public String toString() {
return "ComplexObject{name='" + name + "', value=" + value + "}";
}
}
public class ComplexObjectFactoryBean implements FactoryBean<ComplexObject> {
public ComplexObject getObject() {
// 创建复杂对象
ComplexObject complexObject = new ComplexObject("复杂对象", 42);
System.out.println("创建复杂对象:" + complexObject);
return complexObject;
}
public Class<?> getObjectType() {
return ComplexObject.class;
}
public boolean isSingleton() {
return true;
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ComplexObject complexObject = context.getBean(ComplexObject.class);
System.out.println("获取复杂对象:" + complexObject);
}
}
interface Service {
void execute();
}
class ServiceImplA implements Service {
public void execute() {
System.out.println("执行服务实现A");
}
}
class ServiceImplB implements Service {
public void execute() {
System.out.println("执行服务实现B");
}
}
public class DynamicServiceFactoryBean implements FactoryBean<Service> {
private boolean useServiceA = true; // 可以通过配置或条件动态设置
public Service getObject() {
if (useServiceA) {
System.out.println("创建服务实现A");
return new ServiceImplA();
} else {
System.out.println("创建服务实现B");
return new ServiceImplB();
}
}
public Class<?> getObjectType() {
return Service.class;
}
public boolean isSingleton() {
return true;
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Service service = context.getBean(Service.class);
service.execute();
}
}
class LazyObject {
public LazyObject() {
System.out.println("懒对象被创建");
}
public void doSomething() {
System.out.println("懒对象执行操作");
}
}
public class LazyObjectFactoryBean implements FactoryBean<LazyObject> {
public LazyObject getObject() {
System.out.println("创建懒对象实例");
return new LazyObject();
}
public Class<?> getObjectType() {
return LazyObject.class;
}
public boolean isSingleton() {
return true;
}
}
(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println("获取懒对象实例前");
LazyObject lazyObject = context.getBean(LazyObject.class);
System.out.println("获取懒对象实例后");
lazyObject.doSomething();
}
}
这两个是Springboot中新增的扩展点,之所以将这两个扩展点放在一起,是因为它两个功能特性高度相似,不同的只是名字、扩展方法形参数类型、执行先后的一些小的不同。
这两个接口触发时机为整个项目启动完毕后,自动执行。如果有多个CommandLineRunner,可以利用@Order来进行排序。
CommandLineRunner和ApplicationRunner都有一个扩展方法run(),但是run()形参数类型不同;
CommandLineRunner.run()方法的形参数类型是String... args,ApplicationRunner.run()的形参数类型是ApplicationArguments args;
CommandLineRunner.run()的执行时机要晚于ApplicationRunner.run()一点;
CommandLineRunner和ApplicationRunner触发执行时机是在Spring容器、Tomcat容器正式启动完成后,可以正式处理业务请求前,即项目启动的最后一步;
CommandLineRunner和ApplicationRunner可以应用的场景:项目启动前,热点数据的预加载、清除临时文件、读取自定义配置信息等;
public class DataInitializer implements CommandLineRunner {
public void run(String... args) {
System.out.println("初始化数据:插入初始数据");
// 模拟插入初始数据
insertInitialData();
}
private void insertInitialData() {
System.out.println("插入数据:用户表初始数据");
}
}
public class TaskExecutor implements CommandLineRunner {
public void run(String... args) {
System.out.println("启动后执行任务:发送启动通知");
// 模拟发送启动通知
sendStartupNotification();
}
private void sendStartupNotification() {
System.out.println("通知:应用已启动");
}
}
public class CommandLineArgsProcessor implements CommandLineRunner {
public void run(String... args) {
System.out.println("处理命令行参数:");
for (String arg : args) {
System.out.println("参数:" + arg);
}
}
}
public class AppConfig {
public static void main(String[] args) {
SpringApplication.run(AppConfig.class, new String[]{"参数1", "参数2", "参数3"});
}
}
准确的说,这个应该不算spring&springboot当中的一个扩展点,ApplicationListener可以监听某个事件的event,触发时机可以穿插在业务方法执行过程中,用户可以自定义某个业务事件。但是spring内部也有一些内置事件,这种事件,可以穿插在启动调用中。我们也可以利用这个特性,来自己做一些内置事件的监听器来达到和前面一些触发点大致相同的事情。
接下来罗列下spring主要的内置事件:
ContextRefreshedEvent ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在ConfigurableApplicationContext接口中使用 refresh()方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用。
ContextStartedEvent 当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。
ContextStoppedEvent 当使用 ConfigurableApplicationContext接口中的 stop()停止ApplicationContext时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作
ContextClosedEvent 当使用 ConfigurableApplicationContext接口中的 close()方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启
RequestHandledEvent 这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件
// 定义自定义事件
class CustomEvent extends ApplicationEvent {
private final String message;
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
// 监听自定义事件
public class CustomEventListener implements ApplicationListener<CustomEvent> {
public void onApplicationEvent(CustomEvent event) {
System.out.println("监听到自定义事件:处理事件");
handleCustomEvent(event);
}
private void handleCustomEvent(CustomEvent event) {
System.out.println("处理自定义事件:" + event.getMessage());
}
}
public class EventPublisher implements ApplicationEventPublisherAware {
private ApplicationEventPublisher eventPublisher;
public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void publishCustomEvent(final String message) {
System.out.println("发布自定义事件:" + message);
CustomEvent customEvent = new CustomEvent(this, message);
eventPublisher.publishEvent(customEvent);
}
}
public class AppConfig {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AppConfig.class, args);
EventPublisher publisher = context.getBean(EventPublisher.class);
publisher.publishCustomEvent("这是自定义事件的消息");
}
}
@PreDestroy 与 @PostConstruct 一样,是 Java EE 中的一个注解,用于在 Spring 容器销毁 Bean 之前执行特定的方法。这个注解通常用于释放资源、关闭连接、清理缓存等操作。与 @PostConstruct 类似,@PreDestroy 注解的方法会在 Bean 被销毁之前被调用。使用场景与 DisposableBean 类似destroy(),其触发时机为当此对象销毁、Spring容器关闭时,会自动执行这个方法。比如说运行applicationContext.registerShutdownHook时,就会触发这个方法。这个扩展点基本上用不到DisposableBean是一个接口,为Spring bean提供了一种释放资源的方式 ,只有一个扩展方法destroy();
实现DisposableBean接口,并重写destroy(),可以在Spring容器销毁bean的时候获得一次回调;
destroy()的回调执行时机是Spring容器关闭,需要销毁所有的bean时;
与InitializingBean比较类似的是,InitializingBean#afterPropertiesSet()是在bean初始化的时候触发执行,DisposableBean#destroy()是在bean被销毁的时候触发执行
public class DatabaseConnectionManager implements DisposableBean {
public void destroy() {
System.out.println("释放数据库连接:关闭连接");
// 模拟关闭数据库连接
closeConnection();
}
private void closeConnection() {
System.out.println("数据库连接已关闭");
}
}
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");// bean 的定义
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>
// 用于实例化bean的静态工厂方法
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
<!-- the factory bean, which contains a method called createClientServiceInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
// 调用serviceLocator bean 的实例方法 createClientServiceInstance 生成 clientService bean
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
将构造函数注入用于强制依赖项,将 setter 方法或配置方法注入用于可选依赖项
@Lazy注解。但是,当延迟初始化的 bean 是未延迟初始化的单例 bean 的依赖项时,ApplicationContext 会在启动时创建延迟初始化的 bean,因为它必须满足单例的依赖项。延迟初始化的 bean 被注入到其他位置未进行延迟初始化的单例 bean 中。@DependOn 强制 Spring 容器按指定顺序初始化 Bean。
public class AppConfig {
({"beanB", "beanC"}) // 先初始化 beanB 和 beanC
public BeanA beanA() {
return new BeanA();
}
public BeanB beanB() {
return new BeanB();
}
public BeanC beanC() {
return new BeanC();
}
}
InitializingBean#afterPropertiesSet方法,在bean设置后所有属性后触发回调;实现DisposableBean#destroy方法,让 bean 在时执行某些作。推荐使用@PostConstruct和@PreDistory,更加解耦ROLE_ 前缀就是权限名,protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
// ...
try {
ModelAndView mv = null;
try {
// 获取映射关系
mappedHandler = getHandler(processedRequest);
// 获取可以处理的方法
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 调用处理方法生成视图
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
// 主要是视图解析、渲染过程
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
}
Object handler = getHandlerInternal(request); 返回 Object,只有 @RequestMapping 注解的接口才返回 HandlerMethod,其他三种返回的是类本身。HandlerMethod 表示具体处理请求的方法Map<String, Object> handlerMap 字段中取出的Map<T, MappingRegistration<T>> registry 字段取出的。解析 @RequestMapping 注解被封装成 RequestMappingInfo 对象,作为请求 registry 容器中的 key。registry 容器的 value 值就是 HandlerMethodMapping#MappingRegistration 类型实例,MappingRegistration 封装着 HandlerMethod 类型从 Handler(也就是 Controller 中对应的具体方法) + @RequestMapping 信息被封装成了一个 HandlerMethod 对象void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; 用于调用实际的处理请求的方法// 请求过来的字段和实体类里面的字段一一绑定,就是这个绑定器要干的事情
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 设置参数解析器 @RequestBody 注解有用
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
// 设置返回值解析器
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
// parameterNameDiscoverer 获取一个方法上参数名称,Spring 封装的一个工具类
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 在一次请求中共享Model 和 View 数据的临时容器,类似于 Context
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 开始去调用目标方法,并且把临时容器传进去
invocableMethod.invokeAndHandle(webRequest, mavContainer);
// 从临时容器中直接抽取出需要的 ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 获取逻辑视图名称
String viewName = mv.getViewName();
// 通过视图解析器生成视图 View
View view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
// 视图再去渲染
view.render(mv.getModelInternal(), request, response);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
org.springframework.web.servlet.function.support.RouterFunctionMapping
public class SimpleUrlConfig {
// @Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
/*
Map<String, String> urlMap = new HashMap<>();
urlMap.put("area/index", "helloSimpleController");
SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping(urlMap);
或
*/
SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
Properties properties = new Properties();
// key 就是访问路径,你自己随便定义,这里写的是 area/index
// value 值就是 Controller 类本身在 Spring 容器中的 beanName
properties.put("area/index", "helloSimpleController");
simpleUrlHandlerMapping.setMappings(properties);
return simpleUrlHandlerMapping;
}
}
// HelloSimpleController 在 Spring 中 beanName = helloSimpleController
public class HelloSimpleController extends AbstractController {
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().write("ControllerController execute..");
return null;
}
}
public class MyWebMvcConfigure implements WebMvcConfigurer {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/dist/**").addResourceLocations("classpath:/static/dist/");
registry.addResourceHandler("/theme/**").addResourceLocations("classpath:/static/theme/");
registry.addResourceHandler("/boot/*").addResourceLocations("classpath:/static/");
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
}
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/gotoJsp").setViewName("abc2");
}
}
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
public HandlerMapping resourceHandlerMapping(
("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
("mvcConversionService") FormattingConversionService conversionService,
("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
this.servletContext, contentNegotiationManager, pathConfig.getUrlPathHelper());
addResourceHandlers(registry);
AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
return handlerMapping;
}
protected AbstractHandlerMapping getHandlerMapping() {
if (this.registrations.isEmpty()) {
return null;
}
Map<String, HttpRequestHandler> urlMap = new LinkedHashMap<>();
// registry.addResourceHandler 返回的 ResourceHandlerRegistration 会被存入 this.registrations
for (ResourceHandlerRegistration registration : this.registrations) {
// 每个访问路径都是新建一个 ResourceHttpRequestHandler 对象
ResourceHttpRequestHandler handler = getRequestHandler(registration);
for (String pathPattern : registration.getPathPatterns()) {
urlMap.put(pathPattern, handler);
}
}
return new SimpleUrlHandlerMapping(urlMap, this.order);
}
}
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
public HandlerMapping viewControllerHandlerMapping(
("mvcConversionService") FormattingConversionService conversionService,
("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext);
addViewControllers(registry);
AbstractHandlerMapping handlerMapping = registry.buildHandlerMapping();
return handlerMapping;
}
protected SimpleUrlHandlerMapping buildHandlerMapping() {
if (this.registrations.isEmpty() && this.redirectRegistrations.isEmpty()) {
return null;
}
Map<String, Object> urlMap = new LinkedHashMap<>();
for (ViewControllerRegistration registration : this.registrations) {
urlMap.put(registration.getUrlPath(), registration.getViewController());
}
for (RedirectViewControllerRegistration registration : this.redirectRegistrations) {
urlMap.put(registration.getUrlPath(), registration.getViewController());
}
return new SimpleUrlHandlerMapping(urlMap, this.order);
}
}
public class ViewControllerRegistration {
private final ParameterizableViewController controller = new ParameterizableViewController();
protected ParameterizableViewController getViewController() {
return this.controller;
}
}
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
org.springframework.web.servlet.function.support.HandlerFunctionAdapter
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverbean 初始化时执行 afterPropertiesSet() 方法。而对于 @RequestMapping 注解的 handler 其类上都会有 @Controller 注解,表示是一个 bean,对于这类 handler 使用这种方式进行初始化 register 中的映射关系。protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
}
});
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
registerHandlerMethod() {this.mappingRegistry.register(mapping, handler, method);},register 方法: this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));,MappingRegistration 就是 AbstractHandlerMethodMapping 中的内部类,而 AbstractHandlerMethodMapping 类型的 Handler 是从 MappingRegistry 中的 Map<T, MappingRegistration<T>> registry 字段取出的。
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache();
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
protected final List<HttpMessageConverter<?>> getMessageConverters() {
if (this.messageConverters == null) {
this.messageConverters = new ArrayList<>();
configureMessageConverters(this.messageConverters);
if (this.messageConverters.isEmpty()) {
addDefaultHttpMessageConverters(this.messageConverters);
}
extendMessageConverters(this.messageConverters);
}
return this.messageConverters;
}
static {
ClassLoader classLoader = WebMvcConfigurationSupport.class.getClassLoader();
romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
}
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new ResourceRegionHttpMessageConverter());
try {
messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Throwable ex) {
// Ignore when no TransformerFactory implementation is available...
}
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
messageConverters.add(new AtomFeedHttpMessageConverter());
messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
}
else if (jaxb2Present) {
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
else if (gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
messageConverters.add(new JsonbHttpMessageConverter());
}
if (jackson2SmilePresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
}
if (jackson2CborPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
}
}
<mvc:annotation-driven/> 的作用仅注册核心 MVC 组件(RequestMappingHandlerMapping/HandlerAdapter/ConversionService 等),不创建 WebMvcConfigurationSupport 实例public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 资源加载器,目前为null
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 主类Set<Class?>> MyApplication
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 应用类型 WebApplicationType.SERVLET
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 引导初始化器
this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 应用上下文初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 设置主类
this.mainApplicationClass = deduceMainApplicationClass();
}
BootstrapRegistry作用:有些组件早于ApplicationContext运行,像ApplicationArguments SpringApplicationRunListener prepareEnvironment Banner等,先放在引导注册表,后面再传递给容器作为bean。用户可以在容器创建前就完成自定义组件初始化
BootstrapRegistryInitializers: 在 BootstrapRegistry 刚创建、ApplicationContext 还不存在的极早期阶段,向临时启动容器注册自定义对象(初始化BootstrapRegistry)
SpringFactoriesLoader: 读取 classpath 下所有 META-INF/spring.factories 文件,根据接口全限定名匹配并实例化对应的实现类,自动去重
// 1. 加载指定接口的所有实现(带实例化)
public static <T> List<T> loadFactories(Class<T> factoryType, ClassLoader classLoader)
// 2. 只读取配置字符串,不实例化(自动配置大量使用)
public static List<String> loadFactoryNames(Class<?> factoryType, ClassLoader classLoader)
// 根据type接口的实现类名names通过反射创建实现类对象,parameterTypes构造函数参数类型,args参数值
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names)
// 内部缓存所有实现类全限定名
static final Map<ClassLoader, Map<String, List<String>>> cache = new ConcurrentReferenceHashMap<>();
PriorityOrdered:其优先级级总是高于普通Ordered接口对象,非Ordered实现,默认具有最低优先级,使用 AnnotationAwareOrderComparator.sort(instances) 排序
ApplicationContextInitializer:ApplicationContext 创建完成、但尚未执行 refresh() 之前 的扩展回调。此时有容器,但还未创建 bean,在 prepareContext 阶段执行 applyInitializers(context);
SpringApplication、String[] 参数构造器,反射实例化需要,默认实现是 EventPublishingRunListenermain(String[] args) 原始数组做结构化解析,提供便捷 API 区分「选项参数」和「普通非选项参数」,全程在 Bootstrap 阶段就创建并存入 BootstrapRegistry,全启动流程任意阶段都能获取prepareEnvironment(listeners, bootstrapContext, applicationArguments)${xxx})PropertySource<T> 表示单个配置源抽象,代表一组 k-v 配置数据。常用实现有:创建环境 getOrCreateEnvironment() 通过 DefaultApplicationContextFactory#createEnvironment 调用 ApplicationContextFactory#createEnvironment 方法,webApplicationType 是 webApplicationType,最终得到的是 ApplicationServletEnvironment 类型,
配置环境 configureEnvironment(environment, applicationArguments.getSourceArgs()) 内部委托给 configurePropertySources(environment, args) 和 configureProfiles(environment, args)
ConfigurationPropertySources.attach(environment) 将不同的属性源包装为 ConfigurationPropertySource 属性源,对外提供通义的操作,具有最高优先级。ConfigurationPropertySource 专门解决批量绑定、宽松命名、嵌套对象、元数据校验,所有 @ConfigurationProperties 底层都依赖它
发布环境就绪事件 listeners.environmentPrepared(bootstrapContext, environment);
默认属性源放在最后 DefaultPropertiesPropertySource.moveToEnd(environment)
绑定 SpringApplication bindToSpringApplication(environment) 从 environment 中读取前缀 spring.main 开头的配置,自动绑定赋值给当前 SpringApplication 实例自身的成员变量。也就是用配置文件 / 命令行参数覆盖 SpringApplication 的内置属性。
设置忽略bean信息属性 spring.beaninfo.ignore configureIgnoreBeanInfo(environment)
打印 banner printBanner(environment)
创建容器 createApplicationContext() 具体类型是 AnnotationConfigServletWebServerApplicationContext,内部有 AnnotatedBeanDefinitionReader,ClassPathBeanDefinitionScanner,内部的 beanFactory 是 DefaultListableBeanFactory
设置应用启动 context.setApplicationStartup(this.applicationStartup);

BeanDefinition 是 Bean 的元数据描述对象,不存 Bean 实例,只存怎么创建这个 Bean 的全部配置信息;refresh() 前期只会生成、存储大量 BeanDefinition,不会实例化 Bean;等到 finishBeanFactoryInitialization 才根据 BeanDefinition 反射创建 Bean 对象。@Component、@Bean、@Configuration、@Conditional、@Scope、@Autowired 全部先解析成 BeanDefinition,再统一处理。AnnotationMetadata)@Bean 配置类工厂方法生成 Bean@Configuration、读取 @ComponentScan 的扫描包、获取 @Conditional 条件;MethodMetadata:存储 @Bean 方法信息,返回类型、方法上注解、initMethod/destroyMethod。@ComponentScan 扫描 @Component/@Service/@Repository/@Controller 时生成的 BeanDefinition。AnnotationMetadata,方便读取类上注解(如 @Conditional、@Scope)。ComponentScanAnnotationParser 扫描包后批量构建此类。ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessorPropertySourcesPlaceholderConfigurerConfigurationClassPostProcessor → ComponentScanAnnotationParserScannedGenericBeanDefinition,存入 BeanDefinitionRegistry。@Scope、@Primary、@Conditional 写入 BeanDefinition 属性。GenericBeanDefinition;registry.registerBeanDefinition() 自定义注册 BeanDefinition(Mybatis、Feign 大量使用)。BeanFactoryPostProcessor:所有 BeanDefinition 注册完成后、Bean 实例化之前,统一修改 BeanDefinition;典型:PropertySourcesPlaceholderConfigurer 处理 ${} 占位符。BeanDefinitionRegistryPostProcessor:比上面更早,可以新增、删除 BeanDefinition;核心实现:ConfigurationClassPostProcessor(扫描、解析配置类全靠它)。注意:BeanPostProcessor 操作的是实例化后的 Bean 对象,不操作 BeanDefinition,不要混淆。
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 把前面 prepareEnvironment() 构建好的完整环境绑定到容器
context.setEnvironment(environment);
// 容器的后置处理
postProcessApplicationContext(context);
// 执行所有 ApplicationContextInitializer:spring.factories 中配置的 SPI 扩展;SpringApplication.addInitializers() 手动添加的自定义初始化器。
applyInitializers(context);
// 发布容器准备好事件
listeners.contextPrepared(context);
// 发布引导上下文关闭事件
bootstrapContext.close(context);
// 把命令行参数注册为bean
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 注册banner
beanFactory.registerSingleton("springBootBanner", printedBanner);
// beanFactory后置处理器,把 defaultProperties 放在最低优先级
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// 注册启动主类
load(context, sources.toArray(new Object[0]));
// 发布上下文加载事件
listeners.contextLoaded(context);
load(context, sources.toArray(new Object[0]));createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources); 从sources 中加载bean定义,是一个门面,内部有 AnnotatedBeanDefinitionReader, XmlBeanDefinitionReader, ClassPathBeanDefinitionScanner.AnnotatedBeanDefinitionReader#register(Class<?>... componentClasses) 方法注册,内部调用AnnotatedBeanDefinitionReader#doRegisterBean// 生成bean名称:myApplication
this.beanNameGenerator.generateBeanName(abd, this.registry);
// 处理其他的注解信息,写入 AnnotatedGenericBeanDefinition,包括 @Lazy, @Primary, @DependsOn, @Role, @Description
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// bean定义持有者,有beanDefinition,bena名称,别名(默认为null)
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 设置代理,目前默认无代理
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 注册beanDefintion,调用 beanFactory 的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
// 存入 Map<String, BeanDefinition> beanDefinitionMap
// 同时把bean名称存入 List<String> beanDefinitionNames
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
shutdownHook.registerApplicationContext(context);context.addApplicationListener(this.contextCloseListener);AbstractApplicationContext#refresh() 执行synchronized (this.startupShutdownMonitor) 一旦触发异常,整个应用启动失败prepareRefresh() —— 容器刷新前置准备obtainFreshBeanFactory() —— 获取 / 刷新底层 Bean 工厂ConfigurableListableBeanFactory,这是存放所有 BeanDefinition、单例池的底层仓库;prepareBeanFactory(beanFactory) —— 配置 Bean 工厂基础能力Environment、系统属性、系统环境;ApplicationContextAwareProcessor,后续处理 *Aware 接口注入;ConversionService 类型转换服务;postProcessBeanFactory(beanFactory) —— 子类扩展 Bean 工厂request/session 等 Web 作用域;invokeBeanFactoryPostProcessors(beanFactory) —— 处理所有 Bean 定义后置处理器【注解扫描核心】BeanDefinitionRegistryPostProcessor(优先执行)
核心实现 ConfigurationClassPostProcessor:
扫描 @ComponentScan、解析 @Configuration/@Bean/@Import/@EnableAutoConfiguration,生成并注册全部业务 BeanDefinition;BeanFactoryPostProcessor 处理配置占位符 ${xxx}、修改已存在的 BeanDefinition;registerBeanPostProcessors(beanFactory) —— 注册 Bean 创建拦截器BeanPostProcessor 并按优先级排序注册到工厂:AutowiredAnnotationBeanPostProcessor:处理 @Autowired/@Value 注入;CommonAnnotationBeanPostProcessor:处理 @Resource/@PostConstruct;AnnotationAwareAspectJAutoProxyCreator:AOP 代理创建;initMessageSource() —— 初始化国际化资源MessageSource Bean,支持多语言配置读取,业务很少用到。initApplicationEventMulticaster() —— 初始化事件广播器ApplicationEventMulticaster,支撑 publishEvent()、@EventListener 事件体系;onRefresh() —— 子类专属刷新逻辑(SpringBoot 内嵌 Tomcat 关键)ServletWebServerApplicationContext 在这里创建内嵌 Tomcat/Jetty WebServer;registerListeners() —— 注册所有事件监听器ApplicationListener 实现类,注册到事件广播器;@EventListener 注解方法,封装成监听器;finishBeanFactoryInitialization(beanFactory) —— 实例化所有非懒加载单例 Bean【依赖注入核心】@PostConstruct/afterPropertiesSet) → 存入单例池;finishRefresh() —— 容器收尾,发布就绪事件Lifecycle 的 Bean;ContextRefreshedEvent;AbstractApplicationContext#prepareRefreshstartupDate:记录本次容器刷新的时间戳,后续打印启动耗时用;closed.set(false):把容器关闭标记置为 false,代表容器不再是关闭状态;active.set(true):标记容器为激活中,避免并发多次调用 refresh ()。initPropertySources() 初始化环境占位资源(目前没有执行什么操作)getEnvironment().validateRequiredProperties(); 校验必填配置项(目前是空的)earlyApplicationListenersearlyApplicationEvents,早期还无法发布事件,先缓存后面再发布setSerializationId 实际是 MyApplicationbeanFactory.setBeanClassLoader(getClassLoader()); 设置 bean 的类加载器,默认是线程上下文类加载器
注册 SpEL 解析器,支持 #{...} 对象表达式(@Value("#{bean.xxx}"));
注册资源编辑器,自动把字符串路径转为 Resource、File、URL 等类型。
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); Bean 创建后回调所有 XXXAware 接口,给 Bean 注入容器内置对象;
beanFactory.ignoreDependencyInterface(XXXAware.class); 告诉工厂不要通过自动注入填充这些 Aware 接口,统一由上面的后置处理器手动赋值,避免重复注入冲突。ApplicationContextAwareProcessor#postProcessBeforeInitialization 会注入 EnvironmentAware、ResourceLoaderAware、ApplicationEventPublisherAware、ApplicationContextAware 等
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); 注册可直接自动注入的内置依赖(registerResolvableDependency),效果是业务 Bean 可以直接 @Autowired 注入 ApplicationContext, ApplicationEventPublisher 等 bean。内部存入this.resolvableDependencies.put(dependencyType, autowiredValue)
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); 注册监听器探测器 ApplicationListenerDetector,凡是实现 ApplicationListener 的 Bean,实例化完成后自动注册到事件广播器,不用手动配置。
手动注册 4 个固定名称单例,全项目任意 Bean 可直接注入:
environment → ConfigurableEnvironment 读取配置、yml、命令行参数systemProperties → JVM 系统属性systemEnvironment → 操作系统环境变量applicationStartup → 启动耗时埋点工具注册单例 bean 在 DefaultSingletonBeanRegistry#registerSingleton(String beanName, Object singletonObject),内部存储在 Map<String, Object> singletonObjects,Set<String> registeredSingletons 存储注册的单例 bean 的名称
super.postProcessBeanFactory(beanFactory); 中调用 ServletWebServerApplicationContext#postProcessBeanFactory 添加 WebApplicationContextServletContextAwareProcessor 后置处理器,设置 servletContext 和 servletConfigregisterWebApplicationScopes(); 注入 ServletRequest,ServletResponse,HttpSession,WebRequestthis.scanner.scan(this.basePackages); 扫描预设基础包 basePackages,SpringBoot 正常场景不会走这里basePackages:通过代码手动指定的扫描包路径;context.scan("com.xxx") 时,basePackages 才会赋值this.reader.register(ClassUtils.toClassArray(this.annotatedClasses)); 注册手动添加的注解类 annotatedClasses,也不会走到这里context.register(Class.class) 时,annotatedClasses 才会赋值postProcessBeanDefinitionRegistry(registry)postProcessBeanFactory(beanFactory)先执行外部手动传入的 BeanDefinitionRegistryPostProcessor,来自 AbstractApplicationContext.beanFactoryPostProcessors,来源
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory 的 bean 定义,是个 rootBeanDefinitioncontext.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context))然后处理容器内 BeanDefinitionRegistryPostProcessor,按照实现 PriorityOrdered,实现 Ordered 和剩下无排序的分三批执行 invokeBeanDefinitionRegistryPostProcessors,内部执行 postProcessBeanDefinitionRegistry 完成Bean 定义注册;
然后执行 BeanDefinitionRegistryPostProcessor 的 postProcessBeanFactory 方法,然后是手动传入的普通 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法。processedBeans 记录已处理的 bean 名称
再执行容器内普通 BeanFactoryPostProcessor,过滤掉上一步已经处理过的处理器,也是按照三种优先级执行
configCandidates 只有 MyApplication
进入 ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter),configClass 是配置类对象(加了@Configuration的),sourceClass 是原始类
判断是否添加 @Component 注解
处理 @PropertySource 注解
处理 @ComponentScan 注解,执行扫描,进入 ComponentScanAnnotationParser#parse,创建 ClassPathBeanDefinitionScanner,根据 @ComponentScan 一系列属性,设置ClassPathBeanDefinitionScanner 的属性,进入其 doScan 方法,扫描启动类所在包下的类。
处理 @Import 注解,找到 sourceClass 上的注解的注解递归找 @Import 导入的类
处理 @ImportResource 注解
处理 @Bean,retrieveBeanMethodMetadata(sourceClass); 获取所有 @Bean 方法,构造 BeanMethod 加入 configClass 中
处理接口上的 @Bean 方法
返回其父类,接着处理 doProcessConfigurationClass
this.deferredImportSelectorHandler.process(); 处理自动配置的 selector
this.reader.loadBeanDefinitions(configClasses); 获取所有的配置类后,加载bean定义,进入 ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=[org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener]
org.springframework.boot.diagnostics.FailureAnalysisReporter=[org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter]
org.springframework.boot.ApplicationContextFactory=[org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext.Factory, org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext.Factory]
org.springframework.boot.SpringApplicationRunListener=[org.springframework.boot.context.event.EventPublishingRunListener]
org.springframework.beans.BeanInfoFactory=[org.springframework.beans.ExtendedBeanInfoFactory]
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=[org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider, org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider, org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider, org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider, org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider]
org.springframework.context.ApplicationListener=[org.springframework.boot.ClearCachesApplicationListener, org.springframework.boot.builder.ParentContextCloserApplicationListener, org.springframework.boot.context.FileEncodingApplicationListener, org.springframework.boot.context.config.AnsiOutputApplicationListener, org.springframework.boot.context.config.DelegatingApplicationListener, org.springframework.boot.context.logging.LoggingApplicationListener, org.springframework.boot.env.EnvironmentPostProcessorApplicationListener, org.springframework.boot.autoconfigure.BackgroundPreinitializer]
org.springframework.boot.logging.LoggingSystemFactory=[org.springframework.boot.logging.logback.LogbackLoggingSystem.Factory, org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.Factory, org.springframework.boot.logging.java.JavaLoggingSystem.Factory]
org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=[org.springframework.boot.flyway.FlywayDatabaseInitializerDetector, org.springframework.boot.jdbc.AbstractDataSourceInitializerDatabaseInitializerDetector, org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializerDetector, org.springframework.boot.liquibase.LiquibaseDatabaseInitializerDetector, org.springframework.boot.orm.jpa.JpaDatabaseInitializerDetector, org.springframework.boot.r2dbc.init.R2dbcScriptDatabaseInitializerDetector, org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializerDatabaseInitializerDetector]
org.springframework.boot.env.PropertySourceLoader=[org.springframework.boot.env.PropertiesPropertySourceLoader, org.springframework.boot.env.YamlPropertySourceLoader]
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=[org.springframework.boot.autoconfigure.condition.OnBeanCondition, org.springframework.boot.autoconfigure.condition.OnClassCondition, org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition]
org.springframework.boot.diagnostics.FailureAnalyzer=[org.springframework.boot.context.config.ConfigDataNotFoundFailureAnalyzer, org.springframework.boot.context.properties.IncompatibleConfigurationFailureAnalyzer, org.springframework.boot.context.properties.NotConstructorBoundInjectionFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.MutuallyExclusiveConfigurationPropertiesFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer, org.springframework.boot.diagnostics.analyzer.PatternParseFailureAnalyzer, org.springframework.boot.liquibase.LiquibaseChangelogMissingFailureAnalyzer, org.springframework.boot.web.context.MissingWebServerFactoryBeanFailureAnalyzer, org.springframework.boot.web.embedded.tomcat.ConnectorStartFailureAnalyzer, org.springframework.boot.autoconfigure.data.redis.RedisUrlSyntaxFailureAnalyzer, org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer, org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer, org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer, org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer, org.springframework.boot.autoconfigure.jooq.NoDslContextBeanFailureAnalyzer, org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer, org.springframework.boot.autoconfigure.r2dbc.MissingR2dbcPoolDependencyFailureAnalyzer, org.springframework.boot.autoconfigure.r2dbc.MultipleConnectionPoolConfigurationsFailureAnalyzer, org.springframework.boot.autoconfigure.r2dbc.NoConnectionFactoryBeanFailureAnalyzer, org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer]
org.springframework.boot.SpringBootExceptionReporter=[org.springframework.boot.diagnostics.FailureAnalyzers]
org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=[org.springframework.boot.sql.init.dependency.AnnotationDependsOnDatabaseInitializationDetector, org.springframework.boot.jdbc.SpringJdbcDependsOnDatabaseInitializationDetector, org.springframework.boot.jooq.JooqDependsOnDatabaseInitializationDetector, org.springframework.boot.orm.jpa.JpaDependsOnDatabaseInitializationDetector, org.springframework.boot.autoconfigure.batch.JobRepositoryDependsOnDatabaseInitializationDetector, org.springframework.boot.autoconfigure.quartz.SchedulerDependsOnDatabaseInitializationDetector, org.springframework.boot.autoconfigure.session.JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector]
org.springframework.boot.context.config.ConfigDataLocationResolver=[org.springframework.boot.context.config.ConfigTreeConfigDataLocationResolver, org.springframework.boot.context.config.StandardConfigDataLocationResolver]
org.springframework.context.ApplicationContextInitializer=[org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer, org.springframework.boot.context.ContextIdApplicationContextInitializer, org.springframework.boot.context.config.DelegatingApplicationContextInitializer, org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer, org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer, org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer, org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener]
org.springframework.boot.env.EnvironmentPostProcessor=[org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor, org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor, org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor, org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor, org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor, org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor, org.springframework.boot.autoconfigure.integration.IntegrationPropertiesEnvironmentPostProcessor]
org.springframework.boot.context.config.ConfigDataLoader=[org.springframework.boot.context.config.ConfigTreeConfigDataLoader, org.springframework.boot.context.config.StandardConfigDataLoader]