Spring

// yml文件:config.jwt.expire: 1000 * 60 * 60 * 24 * 7
public static long expire; // 过期时间,单位毫秒
public static String secret; // 密钥长度≥4

// #用于注入Spel表达式,$是占位符,字符串替换
@Value("#{${config.jwt.expire}}")
public void setExpire(long expire){
    JwtUtils.expire = expire;
}

@Value("${config.jwt.secret}")
public void setSecret(String secret){
    JwtUtils.secret = secret;
}
ℹ️note

类上需有 @Component 注解,将类交由 Spring 容器管理

GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
❗️important

当你创建一个Bean定义时,你创建了一个“配方”,用于创建该Bean定义(definition)是所定义的类的实际实例

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 的上下文中有效。
public class MyBean implements ApplicationContextAware {
    private ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
    // 使用context来获取其他Bean或配置信息
@Configuration
public class AppConfig {
    @Bean
    public ConversionService conversionService() {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
        conversionService.addConverter(new MyCustomConverter());
        return conversionService;
    }
}

事件

ℹ️note
  • 启动期间运行的任务应由 CommandLineRunnerApplicationRunner 组件执行,而不是使用 Spring 组件生命周期回调,如 @PostConstruct
  • 事件侦听器不应运行可能很长的任务,因为默认情况下它们在同一线程中执行。考虑改用 CommandLineRunnerApplicationRunner
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MyApplication.class);
        application.setApplicationStartup(new BufferingApplicationStartup(2048));
        application.run(args);
    }

}

属性值配置

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]}"
// 直接创建对象,耦合度高
class A{
  B b = new B();
}

// 依赖注入,通过构造函数,此时A不需要关注如何创建对象,只需要会使用就可以
class A{
  private B b;
  
  @AutoWired // 使用 spring 直接注入
  A(B b){
    this.b = b;
  }
}
ℹ️note
  • 注入的方式有两种:基于注解和基于xml的
  • bean 就是已经初始化的对象,交给容器管理
  • bean 在被注入前肯定是一个完备的状态
  • 由于可以混合使用基于构造函数和基于设置器的DI,因此将构造函数用于强制依赖关系,将 setter 方法或配置方法用于可选依赖关系是一个很好的经验法则。

bean 声明周期

ℹ️note
  • bean 实例只有在从 @PostConstruct 方法返回后才被视为完全初始化并准备好发布给其他人。
  • XXXAware 接口通常是让 bean 意识到 XXX 存在,例如 ApplicationContextAware 接口定义了一个 setApplicationContext(ApplicationContext applicationContext)bean 可以获得 applicationContext 的引用。BeanNameAware 获得 beanName 的引用
  • 实例化(instantiating)是为对象分配内存
  • 初始化(initializing)是设置对象的其他属性,使其成为可使用的状态。

事件

STOMP

请求方式

注解用途绑定来源典型 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
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> upload(
    @RequestPart("file") MultipartFile file,
    @RequestPart("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>)
@PostMapping("/users/batch")
public ResponseEntity<?> createUsers(@RequestBody 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)
@GetMapping("/users")
public List<User> getUsersByIds(@RequestParam 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)
@PostMapping(value = "/delete", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public void deleteUsers(@RequestParam 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
});

spring 启动过程核心类

spring 扩展点

ApplicationContextInitializer

使用场景

public class EnvironmentInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        environment.setActiveProfiles("development");
        System.out.println("配置文件设置为development");
    }
}
public class CustomBeanFactoryPostProcessorInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
            // 添加自定义的 BeanFactoryPostProcessor
            System.out.println("添加了自定义BeanFactory后处理器...");
        });
    }
}
public class PropertySourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
        propertySources.addFirst(new MapPropertySource("customPropertySource", Collections.singletonMap("customKey", "customValue")));
        System.out.println("已添加自定义属性源");
    }
}

Spring环境下添加扩展点

// 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>

SpringBoot环境下添加扩展点

public class TestApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    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())语句加入 
@SpringBootApplication
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

BeanFactoryPostProcessor

使用场景

public class PropertyModifierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    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 {

    @Override
    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 {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myBean");
        beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    }
}
public class CustomPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
            throws BeansException {
        super.processProperties(beanFactory, props);
        // 自定义属性处理逻辑
    }
}

BeanDefinitionRegistryPostProcessor

使用场景

public class BeanDefinitionModifier implements BeanDefinitionRegistryPostProcessor {

    @Override
    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");
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 此方法可以留空或用于进一步处理
    }
}
public class ConditionalBeanRegistrar implements BeanDefinitionRegistryPostProcessor {

    @Override
    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);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 此方法可以留空或用于进一步处理
    }

    private boolean someCondition() {
        // 自定义条件逻辑
        return true;
    }
}
public class CustomAnnotationBeanRegistrar implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("在 postProcessBeanDefinitionRegistry 中扫描并注册自定义注解的 Bean");

        // 自定义扫描逻辑,假设找到一个类 MyAnnotatedBean
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
                .genericBeanDefinition(MyAnnotatedBean.class)
                .getBeanDefinition();
        registry.registerBeanDefinition("myAnnotatedBean", beanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 此方法可以留空或用于进一步处理
    }
}
@Configuration
public class AppConfig {

    @Bean
    public static BeanDefinitionRegistryPostProcessor customBeanDefinitionRegistryPostProcessor() {
        return new BeanDefinitionRegistryPostProcessor() {

            @Override
            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);
                }
            }

            @Override
            public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
                // 此方法可以留空或用于进一步处理
            }
        };
    }
}
// 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;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    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);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 此方法可以留空或用于进一步处理
    }
}
ℹ️note
  • BeanDefinitionRegistryPostProcessor 阶段
    • 此时所有 @Component、@Bean 等注解的Bean定义已扫描完成,但尚可修改bean配置。
    • 可通过 BeanDefinitionRegistry 动态添加、删除或修改Bean定义。
  • BeanFactoryPostProcessor 阶段
    • 此时所有Bean定义(包括动态注册的)已就绪,但尚未实例化。
    • 只能通过 ConfigurableListableBeanFactory 修改Bean定义的属性(如修改构造器参数、属性值)
  • BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor的父类,因此实现BeanDefinitionRegistryPostProcessor这个接口,也可以重写其父类。但实现了BeanDefinitionRegistryPostProcessorpostProcessBeanFactory方法会先执行,再执行实现了BeanFactoryPostProcessorpostProcessBeanFactory

BeanPostProcessor

使用场景

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {

    @Override
    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;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MyBean) {
            System.out.println("bean初始化后: " + beanName);
        }
        return bean;
    }
}
@Component
public class ProxyBeanPostProcessor implements BeanPostProcessor {

    @Override
    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() {
                @Override
                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;
    }
}
@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("开始初始化bean: " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化bean结束: " + beanName);
        return bean;
    }
}
@Component
public class AutowireBeanPostProcessor implements BeanPostProcessor {

    @Override
    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;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

@Retention(RetentionPolicy.RUNTIME)
public @interface AutowireCustom {
}

public class MyBean {
    @AutowireCustom
    private String customField;

    public MyBean() {
    }

    @Override
    public String toString() {
        return "MyBean{customField='" + customField + "'}";
    }
}

InstantiationAwareBeanPostProcessor

ℹ️note

InstantiationAwareBeanPostProcessor和 BeanPostProcessor 是可以同时被实现的,并且也会同时生效,但是InstantiationAwareBeanPostProcessor的执行时机要稍早于BeanPostProcessor

使用场景

@Component
public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    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() {
                @Override
                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;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之后的 Bean: " + beanName);
        return bean;
    }
}
@Component
public class DependencyInjectionControlPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (bean instanceof MyBean) {
            System.out.println("实例化之后控制依赖注入: " + beanName);
            return false; // 不进行默认的依赖注入
        }
        return true;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之后的 Bean: " + beanName);
        return bean;
    }
}
@Component
public class PropertyModificationPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (bean instanceof MyBean) {
            System.out.println("设置属性值之前: " + beanName);
            // 修改属性值的逻辑
        }
        return pvs;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之后的 Bean: " + beanName);
        return bean;
    }
}

SmartInstantiationAwareBeanPostProcessor

ℹ️note

InstantiationAwareBeanPostProcessor,由于SmartInstantiationAwareBeanPostProcessorInstantiationAwareBeanPostProcessor的子类,因此SmartInstantiationAwareBeanPostProcessor 也同样能扩展 InstantiationAwareBeanPostProcessor的所有方法。但是如果有两个类分别重写了 SmartInstantiationAwareBeanPostProcessorInstantiationAwareBeanPostProcessor 的方法,那么重写 InstantiationAwareBeanPostProcessor 的类的方法会先于重写了 SmartInstantiationAwareBeanPostProcessor的类的方法(注意,这里说的是两者都有的方法)。

使用场景

@Component
public class CustomConstructorSelectionPostProcessor implements SmartInstantiationAwareBeanPostProcessor {

    @Override
    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;
    }

    @Override
    public String toString() {
        return "MyBean{name='" + name + "'}";
    }
}

-解决循环依赖问题:通过提供早期 Bean 引用,解决循环依赖问题。

@Component
public class EarlyBeanReferencePostProcessor implements SmartInstantiationAwareBeanPostProcessor {

    @Override
    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() {
                @Override
                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;
    }
}
@Component
public class BeanTypePredictionPostProcessor implements SmartInstantiationAwareBeanPostProcessor {

    @Override
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
        if (beanClass == MyBean.class) {
            System.out.println("预测 Bean 类型: " + beanName);
            return MyBean.class;
        }
        return null;
    }
}

BeanNameAware

使用场景

@Component
public class LoggingBean implements BeanNameAware {

    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("设置 Bean 名称: " + name);
    }

    public void doSomething() {
        System.out.println("正在执行某些操作, 当前 Bean 名称: " + beanName);
    }
}

@Configuration
@ComponentScan(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();
    }
}
@Component
public class ConditionalLogicBean implements BeanNameAware {

    private String beanName;

    @Override
    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("执行普通逻辑");
        }
    }
}

@Configuration
@ComponentScan(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();
    }
}
@Component("beanA")
public class DynamicBeanA implements BeanNameAware {

    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("设置 Bean 名称: " + name);
    }

    public void execute() {
        System.out.println("执行 Bean: " + beanName);
    }
}

@Component("beanB")
public class DynamicBeanB implements BeanNameAware {

    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("设置 Bean 名称: " + name);
    }

    public void execute() {
        System.out.println("执行 Bean: " + beanName);
    }
}

@Configuration
@ComponentScan(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();
    }
}

BeanClassLoaderAware

使用场景

@Component
public class DynamicClassLoader implements BeanClassLoaderAware {

    private ClassLoader classLoader;

    @Override
    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);
        }
    }
}

@SpringBootApplication
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("不存在的类");
    }
}
@Component
public class ClassAvailabilityChecker implements BeanClassLoaderAware {

    private ClassLoader classLoader;

    @Override
    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;
        }
    }
}

@SpringBootApplication
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("不存在的类");
    }
}
@Component
public class ResourceLoader implements BeanClassLoaderAware {

    private ClassLoader classLoader;

    @Override
    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);
        }
    }
}

@SpringBootApplication
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("不存在的资源");
    }
}

BeanFactoryAware

使用场景

@Component
public class DynamicBeanFetcher implements BeanFactoryAware {

    private BeanFactory beanFactory;

    @Override
    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);
    }
}

@Component
public class MyBean {
    @Override
    public String toString() {
        return "这是 MyBean 实例";
    }
}

@Configuration
@ComponentScan(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();
    }
}
@Component
public class BeanStateChecker implements BeanFactoryAware {

    private BeanFactory beanFactory;

    @Override
    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);
    }
}

@Component("myBean")
public class MyBean {
    @Override
    public String toString() {
        return "这是 MyBean 实例";
    }
}

@Configuration
@ComponentScan(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();
    }
}
@Component
public class ComplexBeanInitializer implements BeanFactoryAware {

    private BeanFactory beanFactory;

    @Override
    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);
        // 在这里可以执行复杂的初始化逻辑
    }
}

@Component
public class MyBean {
    @Override
    public String toString() {
        return "这是 MyBean 实例";
    }
}

@Configuration
@ComponentScan(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();
    }
}

各种Aware接口

@PostConstruct

ℹ️note

使用@PostConstruct注解标记的方法不能有参数,除非是拦截器,可以采用拦截器规范定义的InvocationContext对象。

使用@PostConstruct注解标记的方法不能有返回值,实际上如果有返回值,也不会报错,但是会忽略掉;

使用@PostConstruct注解标记的方法不能被static修饰,但是final是可以的;

InitializingBean

ℹ️note

InitializingBean#afterPropertiesSet()类似效果的是init-method,但是需要注意的是InitializingBean#afterPropertiesSet()执行时机要略早于init-method;

InitializingBean#afterPropertiesSet()的调用方式是在bean初始化过程中直接调用bean的afterPropertiesSet()

bean自定义属性init-method是通过java反射的方式进行调用 ;

使用场景

public class NormalBeanA implements InitializingBean{
    @Overrideimport org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class ResourceInitializer implements InitializingBean {

    @Override
    public void afterPropertiesSet() {
        // 模拟资源初始化
        System.out.println("资源初始化:建立数据库连接");
    }

    public void performAction() {
        System.out.println("资源使用:执行数据库操作");
    }
}
    
@Configuration
@ComponentScan(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();
    }
}
@Component
public class InitialValueSetter implements InitializingBean {

    private String initialValue;

    @Override
    public void afterPropertiesSet() {
        initialValue = "默认值";
        System.out.println("设置初始值:" + initialValue);
    }

    public void printValue() {
        System.out.println("当前值:" + initialValue);
    }
}

@Configuration
@ComponentScan(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();
    }
}
@Component
public class ConfigLoader implements InitializingBean {

    private String configValue;

    @Override
    public void afterPropertiesSet() {
        // 模拟配置加载
        configValue = "配置值";
        System.out.println("加载配置:" + configValue);
    }

    public void printConfig() {
        System.out.println("当前配置:" + configValue);
    }
}

@Configuration
@ComponentScan(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();
    }
}

SmartInitializingSingleton

ℹ️note

实现SmartInitializingSingleton接口的bean的作用域必须是单例,afterSingletonsInstantiated()才会触发;

afterSingletonsInstantiated()触发执行时,非懒加载的单例bean已经完成实现化、属性注入以及相关的初始化操作;

afterSingletonsInstantiated()的执行时机是在DefaultListableBeanFactory#preInstantiateSingletons();

使用场景

@Component
public class GlobalInitializer implements SmartInitializingSingleton {

    @Override
    public void afterSingletonsInstantiated() {
        // 模拟全局初始化操作
        System.out.println("全局初始化操作:启动全局调度任务");
    }
}

FactoryBean

使用场景

class ComplexObject {
    private String name;
    private int value;

    public ComplexObject(String name, int value) {
        this.name = name;
        this.value = value;
    }

    @Override
    public String toString() {
        return "ComplexObject{name='" + name + "', value=" + value + "}";
    }
}

@Component
public class ComplexObjectFactoryBean implements FactoryBean<ComplexObject> {

    @Override
    public ComplexObject getObject() {
        // 创建复杂对象
        ComplexObject complexObject = new ComplexObject("复杂对象", 42);
        System.out.println("创建复杂对象:" + complexObject);
        return complexObject;
    }

    @Override
    public Class<?> getObjectType() {
        return ComplexObject.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

@Configuration
@ComponentScan(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 {
    @Override
    public void execute() {
        System.out.println("执行服务实现A");
    }
}

class ServiceImplB implements Service {
    @Override
    public void execute() {
        System.out.println("执行服务实现B");
    }
}

@Component
public class DynamicServiceFactoryBean implements FactoryBean<Service> {

    private boolean useServiceA = true; // 可以通过配置或条件动态设置

    @Override
    public Service getObject() {
        if (useServiceA) {
            System.out.println("创建服务实现A");
            return new ServiceImplA();
        } else {
            System.out.println("创建服务实现B");
            return new ServiceImplB();
        }
    }

    @Override
    public Class<?> getObjectType() {
        return Service.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

@Configuration
@ComponentScan(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("懒对象执行操作");
    }
}

@Lazy
@Component
public class LazyObjectFactoryBean implements FactoryBean<LazyObject> {

    @Override
    public LazyObject getObject() {
        System.out.println("创建懒对象实例");
        return new LazyObject();
    }

    @Override
    public Class<?> getObjectType() {
        return LazyObject.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

@Configuration
@ComponentScan(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();
    }
}

CommandLineRunner和ApplicationRunner

ℹ️note

CommandLineRunner和ApplicationRunner都有一个扩展方法run(),但是run()形参数类型不同;

CommandLineRunner.run()方法的形参数类型是String... args,ApplicationRunner.run()的形参数类型是ApplicationArguments args;

CommandLineRunner.run()的执行时机要晚于ApplicationRunner.run()一点;

CommandLineRunner和ApplicationRunner触发执行时机是在Spring容器、Tomcat容器正式启动完成后,可以正式处理业务请求前,即项目启动的最后一步;

CommandLineRunner和ApplicationRunner可以应用的场景:项目启动前,热点数据的预加载、清除临时文件、读取自定义配置信息等;

使用场景

@Component
public class DataInitializer implements CommandLineRunner {

    @Override
    public void run(String... args) {
        System.out.println("初始化数据:插入初始数据");
        // 模拟插入初始数据
        insertInitialData();
    }

    private void insertInitialData() {
        System.out.println("插入数据:用户表初始数据");
    }
}
@Component
public class TaskExecutor implements CommandLineRunner {

    @Override
    public void run(String... args) {
        System.out.println("启动后执行任务:发送启动通知");
        // 模拟发送启动通知
        sendStartupNotification();
    }

    private void sendStartupNotification() {
        System.out.println("通知:应用已启动");
    }
}
@Component
public class CommandLineArgsProcessor implements CommandLineRunner {

    @Override
    public void run(String... args) {
        System.out.println("处理命令行参数:");
        for (String arg : args) {
            System.out.println("参数:" + arg);
        }
    }
}

@SpringBootApplication
public class AppConfig {
    public static void main(String[] args) {
        SpringApplication.run(AppConfig.class, new String[]{"参数1", "参数2", "参数3"});
    }
}

ApplicationListener 和 ApplicationContextInitializer

使用场景

// 定义自定义事件
class CustomEvent extends ApplicationEvent {
    private final String message;

    public CustomEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

// 监听自定义事件
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {

    @Override
    public void onApplicationEvent(CustomEvent event) {
        System.out.println("监听到自定义事件:处理事件");
        handleCustomEvent(event);
    }

    private void handleCustomEvent(CustomEvent event) {
        System.out.println("处理自定义事件:" + event.getMessage());
    }
}

@Component
public class EventPublisher implements ApplicationEventPublisherAware {
    
    private ApplicationEventPublisher eventPublisher;

    @Override
    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);
    }
}

@SpringBootApplication
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

DisposableBean

ℹ️note

DisposableBean是一个接口,为Spring bean提供了一种释放资源的方式 ,只有一个扩展方法destroy();

实现DisposableBean接口,并重写destroy(),可以在Spring容器销毁bean的时候获得一次回调;

destroy()的回调执行时机是Spring容器关闭,需要销毁所有的bean时;

与InitializingBean比较类似的是,InitializingBean#afterPropertiesSet()是在bean初始化的时候触发执行,DisposableBean#destroy()是在bean被销毁的时候触发执行

使用场景

@Component
public class DatabaseConnectionManager implements DisposableBean {

    @Override
    public void destroy() {
        System.out.println("释放数据库连接:关闭连接");
        // 模拟关闭数据库连接
        closeConnection();
    }

    private void closeConnection() {
        System.out.println("数据库连接已关闭");
    }
}

SpringFramework

Core

bean

// 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;
    }
}

Dependencies

@Configuration
public class AppConfig {
    @Bean
    @DependsOn({"beanB", "beanC"}) // 先初始化 beanB 和 beanC
    public BeanA beanA() {
        return new BeanA();
    }
    @Bean
    public BeanB beanB() {
        return new BeanB();
    }
    @Bean
    public BeanC beanC() {
        return new BeanC();
    }
}

SpringSecurity

SpringMvc流程梳理

核心流程

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);
    } 
}

getHandler() 方法分析

getHandlerAdapter() 方法分析

handle(processedRequest, response, mappedHandler.getHandler()) 方法分析

AbstractHandlerMethodAdapter 类型

// 请求过来的字段和实体类里面的字段一一绑定,就是这个绑定器要干的事情
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 对象

processDispatchResult() 方法

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);
}

handlerMappings 初始化

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
@Configuration
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
@Component
public class HelloSimpleController extends AbstractController {

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.getWriter().write("ControllerController execute..");
        return null;
    }
}
@Configuration
@EnableWebMvc
public class MyWebMvcConfigure implements WebMvcConfigurer {

    @Override
    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/");
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/gotoJsp").setViewName("abc2");
    }
}
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {

    @Bean
    @Nullable
    public HandlerMapping resourceHandlerMapping(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

        ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
                this.servletContext, contentNegotiationManager, pathConfig.getUrlPathHelper());
        addResourceHandlers(registry);

        AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
        return handlerMapping;
    }    
    
    @Nullable
    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 {

    @Bean
    @Nullable
    public HandlerMapping viewControllerHandlerMapping(
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

        ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext);
        addViewControllers(registry);

        AbstractHandlerMapping handlerMapping = registry.buildHandlerMapping();
        return handlerMapping;
    }
    
    @Nullable
    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;
    }
}

HandlerAdapter 初始化

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

ViewResolver 初始化

handlerMap 和 register 映射关系

handlerMap 映射关系

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);
            });
        }
}

参数解析器、返回值解析器初始化

@Override
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;
}

MessageConverter 消息转换器初始化

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()));
    }
}
ℹ️note
  • WebMvcConfigurer 是接口,用于扩展 springmvc 配置,推荐使用该接口
  • WebMvcConfigurationSupport 是 springmvc 的全局配置类,在需要完全自定义springmvc配置时继承该类
  • @EnableWebMvc 注解会自动注入 DelegatingWebMvcConfiguration 类,该类是 WebMvcConfigurationSupport 的子类,
  • WebMvcAutoConfiguration 是springboot 中的 springmvc 的自动配置类。SpringBoot 的 WebMvcAutoConfiguration 通过 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 条件生效。
  • 只要容器中存在 WebMvcConfigurationSupport 的子类 Bean(包括 @EnableWebMvc 引入的 DelegatingWebMvcConfiguration),自动配置即失效。
  • springboot 项目只需实现 WebMvcConfigurer,无需 @EnableWebMvc。
  • 对于 springmvc 项目,通常创建一个配置类,用 @Configuration 和 @EnableWebMvc 注解。同时让该配置类实现 WebMvcConfigurer,并在其中重写需要自定义的方法,来进行配置扩展。

SpringBoot启动流程

创建SpringApplication对象

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();
}
// 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<>();

执行run方法

准备环境

💡s SpringBoot 环境体系
  • Environment:对环境的总抽象,包括激活的配置文件profile和属性property,property来源有properties文件, JVM系统属性, 系统环境变量, JNDI, servlet 上下文参数, ad-hoc Properties对象, Maps对象
  • ConfigurableEnvironment(环境总容器)内部持有 MutablePropertySources (多个PropertySource有序集合,优先级从上到下递减)和 MutablePropertyResolver (占位符解析器,处理${xxx}
  • PropertySource 存在优先级,上层同名 key 覆盖下层。PropertySource<T> 表示单个配置源抽象,代表一组 k-v 配置数据。常用实现有:
    • SystemEnvironmentPropertySource:操作系统环境变量
    • SystemPropertiesPropertySource:JVM 系统属性(-Dxxx)
    • CommandLinePropertySource:命令行参数(--xxx=yyy)名称:commandLineArgs
    • MapPropertySource:自定义 Map 配置
    • ResourcePropertySource:application.yml / application.properties
  • PropertySources 持有多个 PropertySource,MutablePropertySources 是其默认实现
  • CommandLinePropertySource 定位:放入 Environment 的配置源,底层实现子类:SimpleCommandLinePropertySource,构造时依赖 ApplicationArguments,提取里面所有 --key=value;包装成 PropertySource,插入到 MutablePropertySources 最顶部(最高优先级);只承载「配置型参数」,丢弃纯普通参数(普通参数不进环境变量)。
  • ApplicationArguments 定位:原始命令行参数结构化解析工具,只有选项型参数(--开头)才视为属性源的一种,非选项参数视为普通参数
  • CommandLineArgs 简单表示命令行参数,ApplicationArguments 内部使用它

ApplicationContext 继承关系图

BeanDefinition

各类注解如何转换成 BeanDefinition
  1. @Component / @Service / @Controller / @Repository
  1. @Configuration + @Bean
  1. @Import / ImportBeanDefinitionRegistrar
  1. @Conditional 系列注解
💡tip
  1. BeanFactoryPostProcessor所有 BeanDefinition 注册完成后、Bean 实例化之前,统一修改 BeanDefinition;典型:PropertySourcesPlaceholderConfigurer 处理 ${} 占位符。
  2. BeanDefinitionRegistryPostProcessor:比上面更早,可以新增、删除 BeanDefinition;核心实现:ConfigurationClassPostProcessor(扫描、解析配置类全靠它)。

    注意:BeanPostProcessor 操作的是实例化后的 Bean 对象,不操作 BeanDefinition,不要混淆。

回到run方法

// 把前面 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);
// 生成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);

刷新上下文

整体流程

  1. prepareRefresh() —— 容器刷新前置准备
  1. obtainFreshBeanFactory() —— 获取 / 刷新底层 Bean 工厂
  1. prepareBeanFactory(beanFactory) —— 配置 Bean 工厂基础能力
  1. postProcessBeanFactory(beanFactory) —— 子类扩展 Bean 工厂
  1. invokeBeanFactoryPostProcessors(beanFactory) —— 处理所有 Bean 定义后置处理器【注解扫描核心】
  1. registerBeanPostProcessors(beanFactory) —— 注册 Bean 创建拦截器
  1. initMessageSource() —— 初始化国际化资源
  1. initApplicationEventMulticaster() —— 初始化事件广播器
  1. onRefresh() —— 子类专属刷新逻辑(SpringBoot 内嵌 Tomcat 关键)
  1. registerListeners() —— 注册所有事件监听器
  1. finishBeanFactoryInitialization(beanFactory) —— 实例化所有非懒加载单例 Bean【依赖注入核心】
  1. finishRefresh() —— 容器收尾,发布就绪事件
  1. 异常 catch 块
  1. finally 块

逐步解析

prepareRefresh

obtainFreshBeanFactory

prepareBeanFactory

postProcessBeanFactory

invokeBeanFactoryPostProcessors

  1. BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
    • 独有方法:postProcessBeanDefinitionRegistry(registry)
    • 能力:新增、删除、修改 BeanDefinition(最核心,包扫描、自动配置全靠它)
  2. BeanFactoryPostProcessor
    • 方法:postProcessBeanFactory(beanFactory)
    • 能力:只能修改已经存在的 BeanDefinition,不能新增 Bean
ConfigurationClassPostProcessor#processConfigBeanDefinitions
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]