Skip to content

ApplicationContext扩展 ​

深入理解SpringBoot对ApplicationContext的扩展和增强,掌握ApplicationContext类型、上下文初始化器、上下文监听器的工作原理,学会自定义和扩展ApplicationContext。

📋 ApplicationContext扩展概览 ​

SpringBoot在Spring的ApplicationContext基础上进行了扩展,提供了更多功能和便利性。

🎯 一、ApplicationContext类型 ​

1.1 应用类型推断 ​

SpringBoot根据类路径自动推断应用类型:

  • SERVLET:传统Web应用
  • REACTIVE:响应式Web应用
  • NONE:非Web应用
java
static WebApplicationType deduceFromClasspath() {
    if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", 
            null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", 
            null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}

1.2 ServletWebApplicationContext ​

类定义:

java
public class AnnotationConfigServletWebServerApplicationContext 
        extends ServletWebServerApplicationContext 
        implements AnnotationConfigRegistry {
    
    private final AnnotatedBeanDefinitionReader reader;
    private final ClassPathBeanDefinitionScanner scanner;
    private final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();
    private String[] basePackages;
}

特点:

  • 支持注解配置
  • 嵌入式Web服务器
  • Servlet容器集成

1.3 ReactiveWebApplicationContext ​

类定义:

java
public class AnnotationConfigReactiveWebServerApplicationContext 
        extends ReactiveWebServerApplicationContext 
        implements AnnotationConfigRegistry {
    
    private final AnnotatedBeanDefinitionReader reader;
    private final ClassPathBeanDefinitionScanner scanner;
    private final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();
    private String[] basePackages;
}

特点:

  • 响应式编程支持
  • 非阻塞I/O
  • WebFlux集成

🎯 二、ApplicationContextInitializer ​

2.1 接口定义 ​

java
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
    void initialize(C applicationContext);
}

2.2 使用场景 ​

  • 注册自定义的Bean定义
  • 设置环境变量
  • 配置属性源
  • 自定义BeanFactoryPostProcessor

2.3 实现示例 ​

自定义初始化器:

java
public class MyApplicationContextInitializer 
        implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        
        // 添加自定义属性源
        MapPropertySource customPropertySource = new MapPropertySource(
                "customProperties", 
                Collections.singletonMap("custom.property", "custom-value"));
        environment.getPropertySources().addLast(customPropertySource);
        
        // 注册自定义Bean定义
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(MyCustomBean.class);
        ((BeanDefinitionRegistry) applicationContext.getBeanFactory())
                .registerBeanDefinition("myCustomBean", beanDefinition);
    }
}

注册初始化器:

方式1:通过spring.factories

properties
# META-INF/spring.factories
org.springframework.context.ApplicationContextInitializer=\
com.example.MyApplicationContextInitializer

方式2:通过SpringApplication

java
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(MyApplication.class);
        app.addInitializers(new MyApplicationContextInitializer());
        app.run(args);
    }
}

🎯 三、ApplicationListener ​

3.1 接口定义 ​

java
public interface ApplicationListener<E extends ApplicationEvent> 
        extends EventListener {
    void onApplicationEvent(E event);
}

3.2 启动事件 ​

SpringBoot在启动过程中发布的事件:

  1. ApplicationStartingEvent:应用启动开始
  2. ApplicationEnvironmentPreparedEvent:环境准备完成
  3. ApplicationContextInitializedEvent:上下文初始化完成
  4. ApplicationPreparedEvent:上下文准备完成
  5. ContextRefreshedEvent:上下文刷新完成
  6. ApplicationStartedEvent:应用启动完成
  7. ApplicationReadyEvent:应用就绪

3.3 监听器实现 ​

方式1:实现接口

java
@Component
public class MyApplicationListener 
        implements ApplicationListener<ApplicationReadyEvent> {
    
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        System.out.println("应用已就绪!");
        // 执行启动后的逻辑
    }
}

方式2:使用注解

java
@Component
public class MyApplicationListener {
    
    @EventListener
    public void onApplicationReady(ApplicationReadyEvent event) {
        System.out.println("应用已就绪!");
    }
    
    @EventListener
    @Async
    public void onApplicationStarted(ApplicationStartedEvent event) {
        System.out.println("应用已启动!");
    }
}

3.4 监听器注册 ​

自动注册:

  • 使用@Component注解
  • 通过spring.factories注册

spring.factories注册:

properties
# META-INF/spring.factories
org.springframework.context.ApplicationListener=\
com.example.MyApplicationListener

🎯 四、ApplicationRunner和CommandLineRunner ​

4.1 ApplicationRunner ​

接口定义:

java
public interface ApplicationRunner {
    void run(ApplicationArguments args) throws Exception;
}

使用示例:

java
@Component
@Order(1)
public class MyApplicationRunner implements ApplicationRunner {
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner执行");
        // 获取命令行参数
        String[] sourceArgs = args.getSourceArgs();
        Set<String> optionNames = args.getOptionNames();
        
        // 执行启动后的逻辑
    }
}

4.2 CommandLineRunner ​

接口定义:

java
public interface CommandLineRunner {
    void run(String... args) throws Exception;
}

使用示例:

java
@Component
@Order(2)
public class MyCommandLineRunner implements CommandLineRunner {
    
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner执行");
        // 直接获取命令行参数
        for (String arg : args) {
            System.out.println("参数: " + arg);
        }
    }
}

4.3 执行时机 ​

ApplicationRunner和CommandLineRunner在ApplicationContext刷新完成后执行:

java
private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}

🎯 五、自定义ApplicationContext ​

5.1 扩展ApplicationContext ​

创建自定义上下文:

java
public class MyCustomApplicationContext 
        extends AnnotationConfigApplicationContext {
    
    @Override
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        super.postProcessBeanFactory(beanFactory);
        // 自定义后处理
    }
    
    @Override
    protected void onRefresh() {
        super.onRefresh();
        // 自定义刷新逻辑
    }
}

5.2 使用自定义上下文 ​

java
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(MyApplication.class);
        app.setApplicationContextClass(MyCustomApplicationContext.class);
        app.run(args);
    }
}

📖 学习资源 ​

视频教程 ​

网站资源 ​

✅ 学习检查清单 ​

  • [ ] 已理解ApplicationContext类型
  • [ ] 已掌握ApplicationContextInitializer的使用
  • [ ] 已掌握ApplicationListener的使用
  • [ ] 已理解启动事件体系
  • [ ] 已掌握ApplicationRunner和CommandLineRunner
  • [ ] 已能够自定义ApplicationContext

上一章节:配置属性绑定
返回目录:SpringBoot源码深度解析
下一主题:Spring源码深度解析