Spring启动时实现初始化的几种方案

 更新时间:2024年06月15日 17:07:24   作者:pbxs  
这篇文章主要介绍了Spring启动时实现初始化的几种方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

准确的说是spring容器实例化完成后,几种初始化的方式。为什么这么说呢?

下看面示例:

@Slf4j
@Component
public class InitBeanDemo {
    @Autowired
    private Environment env;

    public InitBeanDemo() {
        log.info("DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles()));
        log.info("ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles()));
    }

示例是在bean的构造方法里做一些初始化的工作,示例比较简单只做了日志打印。是理想很丰满,现实很骨感,报错了:

Constructor threw exception; nested exception is java.lang.NullPointerException

原因是,Environment尚未初始化完成。

接下来我们来探索一下 有哪些初始化方式能满足上面示例的需求。

构造方法里初始化

可以正常运行,在所有初始化方式里执行时机最早。

原理是在InitBeanDemo实例化前就实例化了Environment。

@Component
public class InitBeanDemo {

    private final Environment env;

    @Autowired
    public InitBeanDemo (Environment environment) {
        this.env = environment;
        log.info("Constructor DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles()));
        log.info("Constructor ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles()));
    }
}

常规三件套

常规三件套:@PostConstruct、InitializingBean、initMethod。

如果你愿意的话,三种方式可以在同一个Bean下同时使用,执行的优先级@PostConstruct > InitializingBean > initMethod。

@PostConstruct注解

在一个可以被扫描到Bean里,添加一个public void xxx()方法并加上@PostConstruct注解,方法里编写需要初始化的逻辑。

同一个应用程序里可以有多个@PostConstruct注解,同一个Bean里也可以有多个@PostConstruct注解。

@Slf4j
@Component
public class InitBeanDemo {
    @Autowired
    private Environment env;

    @PostConstruct
    public void init() {
        log.info("@PostConstruct DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles()));
        log.info("@PostConstruct ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles()));
    }

实现InitializingBean接口

实现InitializingBean接口,在afterPropertiesSet() 方法里编写需要初始化的逻辑。

同一个应用程序里可以有多个实现InitializingBean接口的类,执行时机会按类名的自然顺序排序。

@Slf4j
@Component
public class InitBeanDemo implements InitializingBean {
    @Autowired
    private Environment env;

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("InitializingBean DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles()));
        log.info("InitializingBean ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles()));
    }
}

指定Bean的initMethod方法

使用@Bean注解的initMethod属性可用于Bean的初始化后执行的方法。

initMethod必须是public void 的无参构造方法。

@Slf4j
public class InitBeanDemo implements InitializingBean {
    @Autowired
    private Environment env;
    
	public void initMethod() {
        log.info("initMethod DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles()));
        log.info("initMethod ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles()));
    }
@Configuration
public class InitBeanConfig {

    @Bean(initMethod="initMethod")
    public InitBeanDemo initBeanDemo () {
        return new InitBeanDemo();
    }

}

等同于 在XML 配置中的init-method属性:

<bean id="initBeanDemo" class="com.xxx.InitBeanDemo" init-method="initMethod"></bean>

自定义ApplicationListener监听

两种方式,一种实现接口,另一种使用注解。

实现ApplicationListener接口

监听ContextRefreshedEvent事件。

@Slf4j
@Component
public class InitBeanDemo implements ApplicationListener<ContextRefreshedEvent>{
    @Autowired
    private Environment env;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        log.info("ApplicationListener DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles()));
        log.info("ApplicationListener ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles()));
    }
}

@EventListener注释

方法参数里指定ContextRefreshedEvent事件。

@Slf4j
@Component
public class InitBeanDemo {
    @Autowired
    private Environment env;

    @EventListener
    public void onApplicationEvent2(ContextRefreshedEvent event) {
        log.info("@EventListener DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles()));
        log.info("@EventListener ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles()));
    }
}

Spring Boot提供的初始化接口

ApplicationRunner接口

@Slf4j
@Component
public class InitBeanDemo implements ApplicationRunner {
    @Autowired
    private Environment env;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("ApplicationRunner: {}", args);
        log.info("ApplicationRunner: {}", args.getOptionNames());
        log.info("ApplicationRunner DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles()));
        log.info("ApplicationRunner ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles()));
    }
}

CommandLineRunner接口

可以在同一个应用程序上下文中定义多个CommandLineRunner bean,并且可以使用@Ordered接口或@Order注释进行排序。

@Slf4j
@Component
public class InitBeanDemo implements CommandLineRunner {
    @Autowired
    private Environment env;

    @Override
    public void run(String... args) throws Exception {
        log.info("CommandLineRunner: {}", args);
        log.info("CommandLineRunner DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles()));
        log.info("CommandLineRunner ActiveProfiles: {}", Arrays.asList(env.getActiveProfiles()));
    }
}

在同一个Bean里使用以上初始化方式的执行先后顺序

在同一个Bean里使用以上初始化方式,运行的日志片段:

2021-06-07 11:24:41|INFO |main|c.c.s.s.t.ConstructorInitDemo|Constructor DefaultProfiles: [default]
2021-06-07 11:24:41|INFO |main|c.c.s.s.t.ConstructorInitDemo|Constructor ActiveProfiles: [sit]

2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|@PostConstruct DefaultProfiles: [default]
2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|@PostConstruct ActiveProfiles: [sit]
2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|InitializingBean DefaultProfiles: [default]
2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|InitializingBean ActiveProfiles: [sit]
2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|initMethod DefaultProfiles: [default]
2021-06-07 11:24:42|INFO |main|c.c.s.s.test.InitBeanDemo|initMethod ActiveProfiles: [sit]

2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|@EventListener DefaultProfiles: [default]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|@EventListener ActiveProfiles: [sit]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationListener DefaultProfiles: [default]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationListener ActiveProfiles: [sit]


2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationRunner: org.springframework.boot.DefaultApplicationArguments@68bef3df
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationRunner: []
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationRunner DefaultProfiles: [default]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|ApplicationRunner ActiveProfiles: [sit]

2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|CommandLineRunner: {}
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|CommandLineRunner DefaultProfiles: [default]
2021-06-07 11:24:44|INFO |main|c.c.s.s.test.InitBeanDemo|CommandLineRunner ActiveProfiles: [sit]

也即 整篇文章整理的先后顺序。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • ssh框架实现文件上传下载实例代码

    ssh框架实现文件上传下载实例代码

    本篇文章主要介绍了ssh框架文件上传下载实例代码,实例分析了Spring+struts+Hibernate的使用技巧,非常具有实用价值,需要的朋友可以参考下。
    2017-03-03
  • 基于Java文件输入输出流实现文件上传下载功能

    基于Java文件输入输出流实现文件上传下载功能

    这篇文章主要为大家详细介绍了基于Java文件输入输出流实现文件上传下载功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-04-04
  • SpringBoot 指标监控actuator的专题

    SpringBoot 指标监控actuator的专题

    未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能,通读本篇对大家的学习或工作具有一定的价值,需要的朋友可以参考下
    2021-11-11
  • struts2入门(搭建环境、配置、示例)详解

    struts2入门(搭建环境、配置、示例)详解

    这篇文章主要介绍了struts2入门(搭建环境、配置、示例)详解,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • Java网络通信中ServerSocket的设计优化方案

    Java网络通信中ServerSocket的设计优化方案

    今天小编就为大家分享一篇关于Java网络通信中ServerSocket的设计优化方案,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • 微信小程序+后端(java)实现开发

    微信小程序+后端(java)实现开发

    这篇文章主要介绍了微信小程序+后端(java)实现开发,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • Spring @Cacheable注解类内部调用失效的解决方案

    Spring @Cacheable注解类内部调用失效的解决方案

    这篇文章主要介绍了Spring @Cacheable注解类内部调用失效的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Java中的ScheduledThreadPoolExecutor定时任务详解

    Java中的ScheduledThreadPoolExecutor定时任务详解

    这篇文章主要介绍了Java中的ScheduledThreadPoolExecutor详解,  ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor,它主要用来在给定的延迟之后运行任务,或者定期执行任务,ScheduledThreadPoolExecutor 的功能与 Timer 类似<BR>,需要的朋友可以参考下
    2023-12-12
  • 深入了解Java File分隔符和Path分隔符的使用

    深入了解Java File分隔符和Path分隔符的使用

    不同的操作系统使用不同的字符作为文件和路径分隔符。当我们的应用程序需要在多个平台上运行时,我们需要正确处理这些问题。Java帮助我们选择一个合适的分隔符,本文就来聊聊Java中File分隔符和 Path分隔符的使用
    2022-07-07
  • 关于报错IDEA Terminated with exit code 1的解决方法

    关于报错IDEA Terminated with exit code 

    如果在IDEA构建项目时遇到下面这样的报错IDEA Terminated with exit code 1,那必然是Maven的设置参数重置了,导致下载错误引起的,本文给大家分享两种解决方法,需要的朋友可以参考下
    2022-08-08

最新评论