狩猎幻想
4.41MB · 2025-11-23
SpringBoot 提供了丰富的扩展点,允许开发者在应用启动的不同阶段进行自定义操作。本文将详细介绍 SpringBoot 的核心扩展点、执行顺序、实现原理及具体应用案例。
SpringBoot 应用启动时的核心扩展点按执行顺序排列如下:
作用:在 Spring 应用上下文(ApplicationContext)被刷新(refresh)之前执行自定义初始化逻辑。
接口定义:
@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
使用场景:
注册方式:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.addInitializers(new MyApplicationContextInitializer());
application.run(args);
}
}
application.properties 或 application.yml 中配置:context.initializer.classes=com.example.MyApplicationContextInitializer
META-INF/spring.factories 中配置:org.springframework.context.ApplicationContextInitializer=com.example.MyApplicationContextInitializer
示例实现:
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 添加自定义属性
Map<String, Object> map = new HashMap<>();
map.put("custom.key", "custom.value");
environment.getPropertySources().addLast(new MapPropertySource("customPropertySource", map));
System.out.println("ApplicationContextInitializer 执行完毕");
}
}
作用:在 BeanDefinition 注册后,实例化前执行,允许动态注册新的 BeanDefinition。
接口定义:
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
使用场景:
示例实现:
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 动态注册一个新的 Bean
BeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(UserService.class)
.addPropertyValue("userName", "admin")
.setScope(BeanDefinition.SCOPE_SINGLETON)
.getBeanDefinition();
registry.registerBeanDefinition("dynamicUserService", beanDefinition);
System.out.println("BeanDefinitionRegistryPostProcessor 执行完毕");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// BeanFactoryPostProcessor 的方法,可在此处对 BeanFactory 进行操作
}
}
作用:在 BeanDefinition 加载完成后,Bean 实例化之前修改 BeanFactory 的配置信息。
接口定义:
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
使用场景:
示例实现:
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 获取指定 Bean 的 BeanDefinition 并修改其属性
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
beanDefinition.getPropertyValues().add("userName", "modifiedName");
// 修改 Bean 的作用域
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
System.out.println("BeanFactoryPostProcessor 执行完毕");
}
}
作用:在 Bean 实例化后,初始化前后执行的处理器。
接口定义:
public interface BeanPostProcessor {
// Bean 初始化前调用
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
// Bean 初始化后调用
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
使用场景:
示例实现:
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof UserService) {
System.out.println("BeanPostProcessor Before: " + beanName);
// 可以对 UserService 进行一些预处理
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof UserService) {
System.out.println("BeanPostProcessor After: " + beanName);
// 可以在这里创建代理对象等
}
return bean;
}
}
作用:应用启动完成后执行的回调接口,用于执行一些初始化操作。
接口定义:
@FunctionalInterface
public interface CommandLineRunner {
void run(String... args) throws Exception;
}
@FunctionalInterface
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}
区别:
使用场景:
示例实现:
@Component
@Order(1) // 指定执行顺序
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner 执行,参数:" + Arrays.toString(args));
// 执行初始化操作,如加载缓存、初始化配置等
}
}
@Component
@Order(2)
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner 执行,非选项参数:" + args.getNonOptionArgs());
System.out.println("ApplicationRunner 执行,选项参数:" + args.getOptionNames());
// 执行其他初始化操作
}
}
利用 SpringBoot 的扩展机制开发自定义 Starter:
步骤:
示例:MinIO 文件上传 Starter
// 1. 配置属性类
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {
private String endpoint;
private String accessKey;
private String secretKey;
// getters and setters
}
// 2. 自动配置类
@Configuration
@EnableConfigurationProperties(MinioProperties.class)
@ConditionalOnClass(MinioClient.class)
public class MinioAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MinioClient minioClient(MinioProperties properties) {
return MinioClient.builder()
.endpoint(properties.getEndpoint())
.credentials(properties.getAccessKey(), properties.getSecretKey())
.build();
}
}
// 3. 在 META-INF/spring.factories 中注册
// org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.MinioAutoConfiguration
利用 Spring 的扩展点实现动态数据源切换:
// 1. 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
String value() default "master";
}
// 2. AOP 切面实现数据源切换
@Aspect
@Component
public class DataSourceAspect {
@Before("@annotation(dataSource)")
public void before(JoinPoint point, DataSource dataSource) {
DataSourceContextHolder.setDataSource(dataSource.value());
}
@After("@annotation(dataSource)")
public void after(DataSource dataSource) {
DataSourceContextHolder.clearDataSource();
}
}
// 3. 使用示例
@Service
public class UserServiceImpl implements UserService {
@DataSource("slave")
@Override
public User getUserById(Long id) {
// 从从库查询数据
}
}
利用扩展点进行应用启动性能优化:
// 使用 ApplicationContextInitializer 预加载配置
public class PreloadConfigInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// 提前加载配置,避免在 Bean 初始化时耗时
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 预加载配置到缓存
}
}
// 使用 CommandLineRunner 异步加载非关键资源
@Component
public class AsyncResourceLoader implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 异步加载缓存、索引等非关键资源
CompletableFuture.runAsync(() -> {
// 加载缓存
});
}
}
SpringBoot 提供了多种控制扩展点执行顺序的方式:
示例:
@Component
@Order(1)
public class FirstBeanPostProcessor implements BeanPostProcessor {
// 高优先级,先执行
}
@Component
@Order(2)
public class SecondBeanPostProcessor implements BeanPostProcessor {
// 低优先级,后执行
}
在复杂业务场景下,可以组合使用多个扩展点:
// 1. 使用 ApplicationContextInitializer 准备环境
// 2. 使用 BeanDefinitionRegistryPostProcessor 注册动态 Bean
// 3. 使用 BeanPostProcessor 处理 Bean 初始化
// 4. 使用 CommandLineRunner 执行启动后逻辑
@Component
public class MyBeanProcessor implements BeanFactoryPostProcessor, ApplicationRunner {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 修改 BeanFactory 配置
}
@Override
public void run(ApplicationArguments args) {
// 应用启动后执行
}
}
结合 Spring 的事件机制实现更灵活的扩展:
@Component
public class MyEventListener {
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady(ApplicationReadyEvent event) {
// 应用就绪后执行,类似于 CommandLineRunner
}
@EventListener(ContextRefreshedEvent.class)
public void onContextRefreshed(ContextRefreshedEvent event) {
// 上下文刷新后执行
}
}
SpringBoot 的扩展点机制为开发者提供了强大的自定义能力,通过合理使用这些扩展点,可以实现:
深入理解并灵活运用这些扩展点,能够帮助我们更好地构建和优化 SpringBoot 应用。