springboot2启动时执行,初始化(或定时任务)servletContext问题

目录
  • springboot2启动时执行,初始化(或定时任务)servletContext
    • 可以实现 ApplicationListener
    • 使用注解注入
  • springboot启动时初始化数据的几种方式
    • 一、ApplicationRunner与CommandLineRunner
    • 二、Spring Bean初始化的InitializingBean,init-method和PostConstruct
    • 三、Spring的事件机制
  • 总结

springboot2启动时执行,初始化(或定时任务)servletContext

需求:springboot 启动后自动执行,初始化数据,并将数据放到 servletContext 中。

首先,不可使用 ServletContextListener 即不能用 @WebListener ,因为 servlet 容器初始化后,spring 并未初始化完毕,不能使用 @Autowired 注入 spring 的对象。

代码如下:

可以实现 ApplicationListener

@Component
public class SettingDataInitListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        WebApplicationContext webApplicationContext = 
            (WebApplicationContext)contextRefreshedEvent.getApplicationContext();
        ServletContext servletContext = webApplicationContext.getServletContext();
        servletContext.setAttribute("key", "value");
    }
}

使用注解注入

service类里注入 servletContext

@Autowired private ServletContext servletContext;

service类里要启动执行的方法加上注解

@PostConstruct

在定时任务里,也可以注入 servletContext,进行定时操作

@Component
public class MyTask {
    @Autowired
    private ServletContext servletContext;

    // 秒 分 时 日 月 周
    @Scheduled(cron = "0 * * * * *")
    public void resetDays() {
        // servletContext
    }
}

springboot启动时初始化数据的几种方式

在我们用springboot搭建项目的时候,经常碰到在项目启动时初始化一些字典数据、地市数据、等各类需求,针对这种需求Spring与Spring boot为我们提供了以下几种方案供我们选择:

  • springboot提供的ApplicationRunner与CommandLineRunner接口
  • Spring Bean初始化的init-method、PostConstruct注解、

InitializingBean、BeanPostProcessor接口

Spring的事件机制: 实现 ApplicationListener 接口

一、ApplicationRunner与CommandLineRunner

如果需要在SpringApplication启动时执行一些特殊的代码,可以通过实现ApplicationRunner或CommandLineRunner接口,这两个接口都提供单一的run方法,且run方法仅在SpringApplication.run(…)完成之前调用。

区别:参数不一样,CommandLineRunner的参数是最原始的参数,没有进行任何处理,ApplicationRunner的参数是ApplicationArguments

ApplicationRunner接口只需要自己创建类实现ApplicationRunner接口

/**
 * @author 重庆阿汤哥
 * @Description: 测试
 * @date 2021/11/26  
 */
@Component
@Slf4j
public class ApplicationRunnerTest implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("ApplicationRunner init data.....");
    }
}

CommandLineRunner

对于这个接口而言,我们可以通过Order注解或者使用Ordered接口来指定调用顺序,@Order()中的值越小,优先级越高

/**
 * @author 重庆阿汤哥
 * @Description: 测试
 * @date 2021/11/26  
 */
@Component
@Slf4j
@Order(1)
public class CommandLineRunnerTest implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        log.info("CommandLineRunner init data.....");
    }
}

二、Spring Bean初始化的InitializingBean,init-method和PostConstruct

InitializingBean接口、BeanPostProcessor接口

InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet()方法。

在spring初始化bean的时候,如果bean实现了InitializingBean接口,在对象的所有属性被初始化后之后才会调用afterPropertiesSet()方法

/**
 * @author 重庆阿汤哥
 * @Description: 测试
 * @date 2021/11/26  
 */
@Component
@Slf4j

@Component
public class InitialingzingBeanTest implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
       log.info("InitializingBean init....");
    }
}

@PostConstruct

/**
 * @author 重庆阿汤哥
 * @Description: 测试
 * @date 2021/11/26  
 */
@Component
@Slf4j
public class DynamicRouteMonitor {
   
    @PostConstruct
    public void init() {
        log.info("gateway route init...");
        }
}

BeanPostProcessor接口

可以用于判断某些特定类加载完成后才能初始化数据的场景,只需要自己实现该接口中的方法进行前置条件判断

public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

三、Spring的事件机制

在Spring中,默认对ApplicationEvent事件提供了如下支持:

  • ContextStartedEvent:ApplicationContext启动后触发的事件
  • ContextStoppedEvent:ApplicationContext停止后触发的事件
  • ContextRefreshedEvent:ApplicationContext初始化或刷新完成后触发的事件;也就是容器初始化完成后调用。
  • ContextClosedEvent:ApplicationContext关闭后触发的事件;如web容器关闭时自动会触发spring容器的关闭。甚至大家听说过的钩子程序都是调用ctx.registerShutdownHook()进行注册虚拟机关闭。

利用ContextRefreshedEvent事件进行初始化操作

/**
 * @author 重庆阿汤哥
 * @Description:容器初始化完整后初始字典数据
 * @date 2021/11/26  10:51
 */
@Component
public class ApplicationStartup implements ApplicationListener<ContextRefreshedEvent> {
    public void onApplicationEvent(ContextRefreshedEvent event) {
        //在容器加载完毕后获取dao层来操作数据库
        ISysDictTypeService sysDictTypeService = (ISysDictTypeService) event.getApplicationContext().getBean(ISysDictTypeService.class);

        sysDictTypeService.initDict();

        IProvCityService provCityService = (IProvCityService) event.getApplicationContext().getBean(IProvCityService.class);
        provCityService.initProvCity();

    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

这几种方式都可以满足我们日常开发的需求,针对具体场景使用对应的方案,在微服务应用中使用也较广泛。

总结

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

(0)

相关推荐

  • SpringBoot数据库初始化datasource配置方式

    目录 I. 项目搭建 1. 依赖 2. 配置 3. 初始化sql II. 示例 1. 验证demo 2. 问题记录 2.1 只有初始化数据data.sql,没有schema.sql时,不生效 2.2 版本问题导致配置不生效 2.3 mode配置不对导致不生效 2.4 重复启动之后,报错 小结 I. 项目搭建 在我们的日常业务开发过程中,如果有db的相关操作,通常我们是直接建立好对应的库表结构,并初始化对应的数据,即更常见的情况下是我们在已有表结构基础之下,进行开发: 但是当我们是以项目形式工作时

  • SpringBoot启动并初始化执行sql脚本问题

    目录 SpringBoot启动并初始化执行sql脚本 我们先看一下源码 下面我们验证一下这两种方式 SpringBoot项目在启动时执行指定sql文件 1. 启动时执行 2. 执行多个sql文件 3. 不同运行环境执行不同脚本 4. 支持不同数据库 5. 避坑 总结 SpringBoot启动并初始化执行sql脚本 如果我们想在项目启动的时候去执行一些sql脚本该怎么办呢,SpringBoot给我们提供了这个功能,可以在启动SpringBoot的项目时,执行脚本,下面我们来看一下. 我们先看一下源

  • SpringBoot使用CommandLineRunner接口完成资源初始化方式

    目录 1 简介 1.1 应用场景 1.2 CommandLineRunner接口 1.3 ApplicationRunner接口 1.4 @Order注解 1.5 CommandLineRunner和ApplicationRunner区别 2 CommandLineRunner完成资源初始化 2.1 背景介绍 2.2 数据类型关系 2.3 实现过程 2.4 源码实现 3 总结 1 简介 1.1 应用场景 在应用服务启动时,需要在所有Bean生成之后,加载一些数据和执行一些应用的初始化. 例如:删

  • SpringBoot项目速度提升之延迟初始化(Lazy Initialization)详解

    目录 前言 是什么? 有啥用? 如何实现? 全局懒加载 注意的点 总结 前言 在一个名为种花家的小镇上,生活着一群热爱编程的人.他们致力于构建出高效.可维护的软件系统,而 Spring Boot 框架成为了他们的不二之选.这个小镇上的人们每天都在用 Spring Boot 框架创造着令人瞩目的应用程序. 然而,随着时间的推移,他们的应用程序变得越来越庞大,包含了许多不同的模块和组件.在应用程序启动的时候,所有的 bean 都会被一次性初始化,这导致了一个令人头疼的问题:启动时间变得越来越长了.

  • docker mysql启动时执行初始化sql

    1.拉取Mysql镜像 docker pull mysql:5.7 2.检查mysql镜像 docker inspect mysql:5.7 "Entrypoint": [ "docker-entrypoint.sh" ], 3.本地创建mysql外挂的目录 ##挂载到容器内/docker-entrypoint-initdb.d:MySQL启动时将执行 01_create_database.sql /root/mysql-5.7/init-data 01_creat

  • 详解SpringBoot程序启动时执行初始化代码

    因项目集成了Redis缓存部分数据,需要在程序启动时将数据加载到Redis中,即初始化数据到Redis. 在SpringBoot项目下,即在容器初始化完毕后执行我们自己的初始化代码. 第一步:创建实现ApplicationListener接口的类 package com.stone; import com.stone.service.IPermissionService; import org.springframework.context.ApplicationListener; import

  • Spring启动时实现初始化有哪些方式?

    一.Spring启动时实现初始化的几种方式 准确的说是spring容器实例化完成后,几种初始化的方式.为什么这么说呢?下看面示例: @Slf4j @Component public class InitBeanDemo { @Autowired private Environment env; public InitBeanDemo() { log.info("DefaultProfiles: {}", Arrays.asList(env.getDefaultProfiles()));

  • java如何实现项目启动时执行指定方法

    本文实例为大家分享了java项目启动时执行指定方法,供大家参考,具体内容如下 想到的就是监听步骤如下: 1.配置web.xml <listener> <listener-class>com.listener.InitListener</listener-class> </listener> 2.编写InitListener类 package com.listener; import java.io.File; import javax.servlet.Ser

  • tomcat启动完成执行 某个方法 定时任务(Spring)操作

    第一步引入接口: ServletContextListener @RestController @RequestMapping("/schedule") public class ScheduleController implements ServletContextListener { @Autowired private ScheduleService scheduleService; @Override public void contextDestroyed(ServletCo

  • springboot中项目启动时实现初始化方法加载参数

    目录 springboot项目启动,初始化方法加载参数 1.@PostConstruct说明 2.@PreDestroy说明 第一种:注解@PostConstruct 第二种:实现CommandLineRunner接口 第三种:springboot的启动类 springboot初始化参数顺序 spring初始化参数顺序为 springboot项目启动,初始化方法加载参数 今天我看到项目中用到了 @PostConstruct 这个注解,之前没看到过,特地查了一下, 1.@PostConstruct

  • 详解Spring Boot 项目启动时执行特定方法

    Springboot给我们提供了两种"开机启动"某些方法的方式:ApplicationRunner和CommandLineRunner. 这两种方法提供的目的是为了满足,在项目启动的时候立刻执行某些方法.我们可以通过实现ApplicationRunner和CommandLineRunner,来实现,他们都是在SpringApplication 执行之后开始执行的. CommandLineRunner接口可以用来接收字符串数组的命令行参数,ApplicationRunner 是使用App

  • 详解如何在 Linux 启动时自动执行命令或脚本

    我一直很好奇,在启动 Linux 系统并登录的过程中到底发生了什么事情.按下开机键或启动一个虚拟机,你就启动了一系列事件,之后会进入到一个功能完备的系统中,有时,这个过程不到一分钟.当你注销或者关机时,也是这样. 更有意思的是,在系统启动以及用户登录或注销时,还可以让系统执行特定的操作. 本文,我们将探讨一下在 Linux 操作系统中实现这些目标的传统方法. 注意:我们假定使用的是 Bash 作为登录及注销的主 Shell.如果你使用的是其他 Shell,那么有些方法可能会无效.如果有其他的疑问

  • 如何在Spring Boot启动时运行定制的代码

    Spring Boot会自动为我们做很多配置,但迟早你需要做一些自定义工作.在本文中,您将学习如何挂钩应用程序引导程序生命周期并在Spring Boot启动时执行代码. 1.执行bean初始化的方法 Spring启动应用程序后运行某些逻辑的最简单方法是将代码作为所选bean引导过程的一部分来执行. 只需创建一个类,将其标记为Spring组件,并将应用程序初始化代码放在带有@PostConstruct注释的方法中.理论上,您可以使用构造函数而不是单独的方法,但将对象的构造与其实际责任分开是一种很好

  • 使用Spring启动时运行自定义业务

    在Spring应用启动时运行自定义业务的场景很常见,但应用不当也可能会导致一些问题. 基于Spring控制反转(Inverse of Control)功能用户几乎不用干预bean实例化过程,对于自定义业务则需要控制部分流程及容器,因此值得须特别关注. 1. Spring启动时运行自定义业务 我们不能简单包括自定义业务在bean的构造函数或在实例化任何对象之后调用方法,这些过程不由我们控制.请看示例: @Component public class InvalidInitExampleBean {

随机推荐