zoukankan      html  css  js  c++  java
  • 在Listener(监听器)定时启动的TimerTask(定时任务)中使用Spring@Service注解的bean

    1.有时候在项目中需要定时启动某个任务,对于这个需求,基于JavaEE规范,我们可以使用Listener与TimerTask来实现,代码如下:

    public class TestTaskListener implements ServletContextListener {
          //Context()初始化方法
          @Override
          public void contextInitialized(ServletContextEvent sce) {
              //新建一个定时管理器
              new TestTimerManager();
          }
          public TestTaskListener() {
              super();
          }
          @Override
          public void contextDestroyed(ServletContextEvent sce) {         
          }
      }

    2.contextInitialized方法中新建了一个定时管理器,代码如下:

    public class TestTimerManager {
          //新建一个定时器
          Timer timer = new Timer();
          public TestTimerManager() {
              super();
              //新建一个定时任务
              TestTimerTask task = new TestTimerTask();
              //设置定时任务
              timer.schedule(task, firstTimeToStartTheTask, period);
          }   
      }

    3.在定时任务的Constructor中新建了一个定时任务,其代码如下:

    @Configuration
      public class TestTimerTask extends TimerTask {
          //采用Spring框架的依赖注入
          @Autowired
          private SelectDataService selectDataService;
    
          public TestTimerTask() {
              super();
          }
          @Override
          public void run(){
              try {
                  //访问数据库
                  MyData myData = selectDataService.selectMyDataById(id);
              }catch(Exception ex) {
                  System.out.println("定时任务出错");
                  ex.printStackTrace();
              }
          }
      }

    spring是个性能非常优秀的抽象工厂,可以生产出工程所需要的实例,这里采用Spring容器的自动注入selectDataService实例。上面代码中,selectDataService这个类是采用Spring的@Service注解的,在项目中主要通过Spring容器注入到Controller中,其作用主要用来访问数据库

    运行项目将会发现NullPointerException,也就是说SelectDataService的实例没有被注入到变量selectDataService中。那么,这是什么原因呢?首先来看看配置文件。 
    下面是web.xml:

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>com.test.TestTaskListener</listener-class>
    </listener>

    在启动web项目时,Servlet容器(比如Tomcat)会读web.xml配置文件中的两个节点和,节点用来加载appliactionContext.xml(即Spring的配置文件),节点用来创建监听器(比如TestTaskListener)实例。Listener的生命周期是由servlet容器管理的,例中的TestTaskListener是由servlet容器实例化并调用其contextInitialized方法的,但是,SelectDataService是通过@Service注解的,也就是说SelectDataService是由Spring容器管理的,在Spring容器外无法直接通过依赖注入得到Spring容器管理的bean实例的引用。为了在Spring容器外得到Spring容器管理的bean,可以使用Spring提供的工具类WebApplicationContextUtils。也就是说,可以在servlet容器管理的Listener中使用该工具类获Spring管理的bean。

    看如下代码:

    public class TestTaskListener implements ServletContextListener {
          //Context()初始化方法
          @Override
          public void contextInitialized(ServletContextEvent sce) {
              //获得Spring容器
              WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
              //从Spring容器中获得SelectDataServlet的实例
              SelectDataService selectDataService = ctx.getBean(SelectDataService.class);
              //新建一个定时管理器
              new TestTimerManager();
          }
          public TestTaskListener() {
              super();
          }
          @Override
          public void contextDestroyed(ServletContextEvent sce) {         
          }
      }

    那么在Listener中获得的SelectDataService实例如何在TestTimerTask中使用呢?可以通过作为参数传递过去,看如下代码:

    public class TestTaskListener implements ServletContextListener {
          //Context()初始化方法
          @Override
          public void contextInitialized(ServletContextEvent sce) {
              //获得Spring容器
              WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
              //从Spring容器中获得SelectDataServlet的实例
              SelectDataService selectDataService = ctx.getBean(SelectDataService.class);
              //新建一个定时管理器
              new TestTimerManager(selectDataService);
          }
          public TestTaskListener() {
              super();
          }
          @Override
          public void contextDestroyed(ServletContextEvent sce) {         
          }
      }
    
    public class TestTimerManager {
          //新建一个定时器
          Timer timer = new Timer();
    
          public TestTimerManager(SelectDataService selectDataService) {
              super();
              //新建一个定时任务
              TestTimerTask task = new TestTimerTask(selectDataService);
              //设置定时任务
              timer.schedule(task, firstTimeToStartTheTask, period);
          }   
      }
    
    @Configuration
      public class TestTimerTask extends TimerTask {
          private SelectDataService selectDataService;
    
          public TestTimerTask(SelectDataService selectDataService) {
              super();
              this.selectDataService = selectDataService;
          }
          @Override
          public void run(){
              try {
                  //访问数据库
                  MyData myData = selectDataService.selectMyDataById(id);
              }catch(Exception ex) {
                  System.out.println("定时任务出错");
                  ex.printStackTrace();
              }
          }
      }

    再回到web.xml 
    由于Servlet容器在初始化TestTaskListener时,获取了Spring容器,所以必须保证,在此之前,Spring容器已经初始化完成。因为Spring容器的初始化也是由Listener(ContextLoaderListener)完成,该监听器用Spring框架提供,可以在web应用启动时启动Spring容器。所以,在web.xml中,要先配置ContextLoaderListener,再配置TestTaskListener。

    1.有时候在项目中需要定时启动某个任务,对于这个需求,基于JavaEE规范,我们可以使用Listener与TimerTask来实现,代码如下:

    public class TestTaskListener implements ServletContextListener {
          //Context()初始化方法
          @Override
          public void contextInitialized(ServletContextEvent sce) {
              //新建一个定时管理器
              new TestTimerManager();
          }
          public TestTaskListener() {
              super();
          }
          @Override
          public void contextDestroyed(ServletContextEvent sce) {         
          }
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.contextInitialized方法中新建了一个定时管理器,代码如下:

    public class TestTimerManager {
          //新建一个定时器
          Timer timer = new Timer();
          public TestTimerManager() {
              super();
              //新建一个定时任务
              TestTimerTask task = new TestTimerTask();
              //设置定时任务
              timer.schedule(task, firstTimeToStartTheTask, period);
          }   
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.在定时任务的Constructor中新建了一个定时任务,其代码如下:

    @Configuration
      public class TestTimerTask extends TimerTask {
          //采用Spring框架的依赖注入
          @Autowired
          private SelectDataService selectDataService;
    
          public TestTimerTask() {
              super();
          }
          @Override
          public void run(){
              try {
                  //访问数据库
                  MyData myData = selectDataService.selectMyDataById(id);
              }catch(Exception ex) {
                  System.out.println("定时任务出错");
                  ex.printStackTrace();
              }
          }
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    spring是个性能非常优秀的抽象工厂,可以生产出工程所需要的实例,这里采用Spring容器的自动注入selectDataService实例。上面代码中,selectDataService这个类是采用Spring的@Service注解的,在项目中主要通过Spring容器注入到Controller中,其作用主要用来访问数据库

    运行项目将会发现NullPointerException,也就是说SelectDataService的实例没有被注入到变量selectDataService中。那么,这是什么原因呢?首先来看看配置文件。 
    下面是web.xml:

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>com.test.TestTaskListener</listener-class>
    </listener>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在启动web项目时,Servlet容器(比如Tomcat)会读web.xml配置文件中的两个节点和,节点用来加载appliactionContext.xml(即Spring的配置文件),节点用来创建监听器(比如TestTaskListener)实例。Listener的生命周期是由servlet容器管理的,例中的TestTaskListener是由servlet容器实例化并调用其contextInitialized方法的,但是,SelectDataService是通过@Service注解的,也就是说SelectDataService是由Spring容器管理的,在Spring容器外无法直接通过依赖注入得到Spring容器管理的bean实例的引用。为了在Spring容器外得到Spring容器管理的bean,可以使用Spring提供的工具类WebApplicationContextUtils。也就是说,可以在servlet容器管理的Listener中使用该工具类获Spring管理的bean。

    看如下代码:

    public class TestTaskListener implements ServletContextListener {
          //Context()初始化方法
          @Override
          public void contextInitialized(ServletContextEvent sce) {
              //获得Spring容器
              WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
              //从Spring容器中获得SelectDataServlet的实例
              SelectDataService selectDataService = ctx.getBean(SelectDataService.class);
              //新建一个定时管理器
              new TestTimerManager();
          }
          public TestTaskListener() {
              super();
          }
          @Override
          public void contextDestroyed(ServletContextEvent sce) {         
          }
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    那么在Listener中获得的SelectDataService实例如何在TestTimerTask中使用呢?可以通过作为参数传递过去,看如下代码:

    public class TestTaskListener implements ServletContextListener {
          //Context()初始化方法
          @Override
          public void contextInitialized(ServletContextEvent sce) {
              //获得Spring容器
              WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
              //从Spring容器中获得SelectDataServlet的实例
              SelectDataService selectDataService = ctx.getBean(SelectDataService.class);
              //新建一个定时管理器
              new TestTimerManager(selectDataService);
          }
          public TestTaskListener() {
              super();
          }
          @Override
          public void contextDestroyed(ServletContextEvent sce) {         
          }
      }
    
    public class TestTimerManager {
          //新建一个定时器
          Timer timer = new Timer();
    
          public TestTimerManager(SelectDataService selectDataService) {
              super();
              //新建一个定时任务
              TestTimerTask task = new TestTimerTask(selectDataService);
              //设置定时任务
              timer.schedule(task, firstTimeToStartTheTask, period);
          }   
      }
    
    @Configuration
      public class TestTimerTask extends TimerTask {
          private SelectDataService selectDataService;
    
          public TestTimerTask(SelectDataService selectDataService) {
              super();
              this.selectDataService = selectDataService;
          }
          @Override
          public void run(){
              try {
                  //访问数据库
                  MyData myData = selectDataService.selectMyDataById(id);
              }catch(Exception ex) {
                  System.out.println("定时任务出错");
                  ex.printStackTrace();
              }
          }
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    再回到web.xml 
    由于Servlet容器在初始化TestTaskListener时,获取了Spring容器,所以必须保证,在此之前,Spring容器已经初始化完成。因为Spring容器的初始化也是由Listener(ContextLoaderListener)完成,该监听器用Spring框架提供,可以在web应用启动时启动Spring容器。所以,在web.xml中,要先配置ContextLoaderListener,再配置TestTaskListener。

  • 相关阅读:
    构造TreeView
    vs2017和Xamarin
    最可能的原因使用的托管的处理程序,但是未安装或未完整安装asp.net
    网站搭建(二)
    网站搭建(一)
    .asp 和 .aspx
    第一天
    IMU的预计分算法
    VINS-MONO初始化
    VINS-MONO ProjectionFactor代码分析及公式推导
  • 原文地址:https://www.cnblogs.com/shizhijie/p/8031197.html
Copyright © 2011-2022 走看看