我的博客原文链接

前言

通常的我们的项目开发中,经常会遇到那种在服务一启动就需要自动执行一些业务代码的情况。比如将数据库中的配置信息或者数据字典之类的缓存到redis,或者在服务启动的时候将一些配置化的定时任务开起来。关于spring mvc或者springboot如何在项目启动的时候就执行一些代码,方法其实有很多,我这边介绍一下我使用过的三种。

1、@PostConstruct 注解

从Java EE5规范开始,Servlet中增加了两个影响Servlet生命周期的注解,@PostConstruct@PreDestroy,这两个注解被用来修饰一个非静态的void()方法。@PostConstruct会在所在类的构造函数执行之后执行,在init()方法执行之前执行。(@PreDestroy注解的方法会在这个类的destory()方法执行之后执行。)

  • 使用示例:在Spring容器加载之后,我需要启动定时任务去做任务的处理(我的定时任务采用的是读取数据库配置的方式)。在这里我使用@PostConstruct 指定了需要启动的方法。
@Component // 注意 这里必须有
public class StartAllJobInit {protected Logger logger = LoggerFactory.getLogger(getClass().getName());@AutowiredJobInfoService jobInfoService;@AutowiredJobTaskUtil jobTaskUtil;@PostConstruct // 构造函数之后执行public void init(){System.out.println("容器启动后执行");startJob();}public void startJob() {List<JobInfoBO> list = jobInfoService.findList();for (JobInfoBO jobinfo :list) {try {if("0".equals(jobinfo.getStartWithrun())){logger.info("任务{}未设置自动启动。", jobinfo.getJobName());jobInfoService.updateJobStatus(jobinfo.getId(), BasicsConstantManual.BASICS_SYS_JOB_STATUS_STOP);}else{logger.info("任务{}设置了自动启动。", jobinfo.getJobName());jobTaskUtil.addOrUpdateJob(jobinfo);jobInfoService.updateJobStatus(jobinfo.getId(), BasicsConstantManual.BASICS_SYS_JOB_STATUS_STARTING);}} catch (SchedulerException e) {logger.error("执行定时任务出错,任务名称 {} ", jobinfo.getJobName());}}}
}

2、实现CommandLineRunner接口并重写run()方法

CommandLineRunner接口文档描述如下:

/*** Interface used to indicate that a bean should <em>run</em> when it is contained within* a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined* within the same application context and can be ordered using the {@link Ordered}* interface or {@link Order @Order} annotation.* <p>* If you need access to {@link ApplicationArguments} instead of the raw String array* consider using {@link ApplicationRunner}.** @author Dave Syer* @see ApplicationRunner*/
public interface CommandLineRunner {/*** Callback used to run the bean.* @param args incoming main method arguments* @throws Exception on error*/void run(String... args) throws Exception;}

如上所说:接口被用作加入Spring容器中时执行run(String… args)方法,通过命令行传递参数。SpringBoot在项目启动后会遍历所有实现CommandLineRunner的实体类并执行run方法,多个实现类可以并存并且根据order注解排序顺序执行。这边还有个ApplicationRunner接口,但是接收参数是使用的ApplicationArguments。这边不再赘述。

同样是启动时执行定时任务,使用这种方式我的写法如下:

@Component // 注意 这里必须有
//@Order(2) 如果有多个类需要启动后执行 order注解中的值为启动的顺序
public class StartAllJobInit implements CommandLineRunner {protected Logger logger = LoggerFactory.getLogger(getClass().getName());@AutowiredJobInfoService jobInfoService;@AutowiredJobTaskUtil jobTaskUtil;@Overridepublic void run(String... args) {List<JobInfoBO> list = jobInfoService.findList();for (JobInfoBO jobinfo :list) {try {if("0".equals(jobinfo.getStartWithrun())){logger.info("任务{}未设置自动启动。", jobinfo.getJobName());jobInfoService.updateJobStatus(jobinfo.getId(), BasicsConstantManual.BASICS_SYS_JOB_STATUS_STOP);}else{logger.info("任务{}设置了自动启动。", jobinfo.getJobName());jobTaskUtil.addOrUpdateJob(jobinfo);jobInfoService.updateJobStatus(jobinfo.getId(), BasicsConstantManual.BASICS_SYS_JOB_STATUS_STARTING);}} catch (SchedulerException e) {logger.error("执行定时任务出错,任务名称 {} ", jobinfo.getJobName());}}}
}

3、使用ContextRefreshedEvent事件(上下文件刷新事件)

ContextRefreshedEvent 官方在接口上的doc说明

Event raised when an {@code ApplicationContext} gets initialized or refreshed.

ContextRefreshedEvent是Spring的ApplicationContextEvent一个实现,ContextRefreshedEvent 事件会在Spring容器初始化完成后以及刷新时触发。

在这里我需要在springboot程序启动之后加载配置信息和字典信息到Redis缓存中去,我可以这样写:

@Component // 注意 这个也是必须有的注解 三种都需要 使spring扫描到这个类并交给它管理
public class InitRedisCache implements ApplicationListener<ContextRefreshedEvent> {static final Logger logger = LoggerFactory.getLogger(InitRedisCache.class);@Autowiredprivate SysConfigService sysConfigService;@Autowiredprivate SysDictService sysDictService;@Overridepublic void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {logger.info("-------加载配置信息 start-------");sysConfigService.loadConfigIntoRedis();logger.info("-------加载配置信息 end-------");logger.info("-------加载字典信息 start-------");sysDictService.loadDictIntoRedis();logger.info("-------加载字典信息 end-------");}
}

注意:这种方式在springmvc-spring的项目中使用的时候会出现执行两次的情况。这种是因为在加载spring和springmvc的时候会创建两个容器,都会触发这个事件的执行。这时候只需要在onApplicationEvent方法中判断是否有父容器即可。

@Override  public void onApplicationEvent(ContextRefreshedEvent event) {  if(event.getApplicationContext().getParent() == null){//root application context 没有parent,他就是老大.  //需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。  }  }

总结

以上,就是我在实际开发中常用的三种,在项目启动时执行代码的方式,开发者可以根据不同的使用情况选择合适的方法去执行自己的业务逻辑。

如何在SpringWEB项目或者Springboot启动时直接执行业务代码(三种方式)相关推荐

  1. JVM 在遇到OOM(OutOfMemoryError)时生成Dump文件的三种方式

    JVM 在遇到OOM(OutOfMemoryError)时生成Dump文件的三种方式,以及如何使用Eclips Memory Analyzer(MAT)插件进行堆内存分析. 方法一: jmap -du ...

  2. java oom dump_JVM 在遇到OOM(OutOfMemoryError)时生成Dump文件的三种方式

    JVM 在遇到OOM(OutOfMemoryError)时生成Dump文件的三种方式,以及如何使用Eclips Memory Analyzer(MAT)插件进行堆内存分析. 方法一: jmap -du ...

  3. Springboot单元测试mysql_Springboot Mybatis-Plus数据库单元测试实战(三种方式)

    单元测试长久以来是热门话题,本文不会讨论需不需要写单测,可以看看参考资料1,我个人认为写好单测应该是每个优秀开发者必备的技能,关于写单测的好处在这里我就不展开讨论了,快速进入本文着重讨论的话题,如何写 ...

  4. springboot 注册dao层 service 层的三种方式,高级内容详解

    可以使用三种注解来引入DAO层的接口到spring容器中. 1.@Mapper,写在每一个DAO层接口上,如下: 2.@MapperScan和@ComponentScan两者之一.前者的意义是将指定包 ...

  5. storyboard搭建项目_简单谈谈ios程序界面实现的三种方式(代码创建,xib和storyboard)...

    一丶前言 实现ios界面总的来说,有三种方式,传统的是纯代码创建与xib创建,近年来,苹果官网一直推荐用storyboard管理项目界面,最新的xcode 创建的project也是默认为storybo ...

  6. 详解Ubuntu Server下启动/停止/重启MySQL数据库的三种方式(ubuntu 16.04)

    启动mysql: 方式一:sudo /etc/init.d/mysql start 方式二:sudo service mysql start 停止mysql: 方式一:sudo /etc/init.d ...

  7. 如何在项目启动时就执行某些操作

    参考资料:如何在项目启动时就执行某些操作 在实际的项目开发中经常会遇到一些需要在项目启动的时候进行初始化操作的需求,比如初始化线程池,配置某些对象的序列化和反序列化方式,加载黑名单白名单,加载权限应用 ...

  8. 启动rrt什么意思_面试官:你来说一下springboot启动时的一个自动装配过程吧!...

    前言 继续总结吧,没有面试就继续夯实自己的基础,前阵子的在面试过程中遇到的各种问题陆陆续续都会总结出来分享给大家,这次要说的也是面试中被问到的一个高频的问题,我当时其实没答好,因为很早之前是看过spr ...

  9. springboot启动时控制台打印图案

    springboot启动时控制台打印图案如下: 1.假如我们不想看到这个图案 public static void main(String[] args) {SpringApplication app ...

最新文章

  1. 怎么把写好的python代码打包成exe-【Python之点到为止】如何优雅的将你的代码打包成EXE...
  2. Linux显示某文件中有关某字符串的信息
  3. U-BOOT的目录结构
  4. QT的QXmlDefaultHandler类的使用
  5. c语言编程宝典pdf,C语言编程宝典之一.pdf
  6. 转:集群和分布式的区别
  7. hadoop hdfs (java api)
  8. P4414 [COCI2006-2007#2] ABC(python3实现)
  9. 起止时间控制,显示格式控制
  10. 关于面试题的一些想法
  11. 特斯拉2020全年交付49.955万辆车,未能完成50万辆目标
  12. go-import下划线的作用
  13. 解决Win10 PowerShell无法激活Anaconda环境的问题
  14. 8255A置位复位控制字
  15. 华硕笔记本 X550JD4710HQ
  16. 文献阅读 An incremental density-based clustering framework using fuzzy local clustering
  17. 转载 JavaScript的24条实用建议
  18. mitmproxy工具使用小红书数据抓取
  19. matlab 画折线图并美化
  20. python批量图像处理_基于python代码批量处理图片resize

热门文章

  1. 白嫖钉钉机器人-员工服务台
  2. Android考勤毕业论文,基于android的考勤系统的设计与实现.doc
  3. 转载 NLS_LANG设置
  4. 深度学习在文档矫正中的应用
  5. 共阳极数码管三极管驱动
  6. 国外小项目,简单小项目赚美金,1个任务10秒,让你轻松赚美金,2022副业轻松赚钱
  7. OSChina 周一乱弹 —— 终于可以尝尝冷水泡面了
  8. 奇安信渗透测试工程师试题(2020)
  9. Pinia全新一代状态管理工具Pinia-Vue3全家桶
  10. BufferedWriter的write(int c)方法