spring 在Thread中注入@Resource失败,总为null的解决方案

@Resource

private MyMapper myDao;

但是运行的时候,进入到这个线程,这个myDao总为null,也就是注入失败。

运行项目将会发现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。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Hongten

java web中的Exception in thread "ContainerBackgroundProcessor[StandardEngine[Catalina]]" java.lang.Out

E | hongtenzone@foxmail.com  B | http://www.cnblogs.com/hongten

1082
来自专栏web编程技术分享

web项目常见错误和解决方案

36712
来自专栏JMCui

Docker 系列七(Duubo 微服务部署实践).

    之前我们公司部署服务,就是大家都懂的那一套(安装JDK、Tomcat —> 编译好文件或者打war包上传 —> 启动Tomcat),这种部署方式一直持续...

2205
来自专栏Java学习网

Java中使用线程时,请不要忘记Spring TaskExecutor组件

当我们实现的web应用程序需要长时间运行一个任务时,Spring TaskExecutor管理组件是一个很好选择,会给我们代码的实现提供很大的方便,也会节省时间...

3665
来自专栏Kubernetes

SkyDNS2源码分析

SkyDNS2是SkyDNS Version 2.x的统称,其官方文档只有README.md,网上能找到的资料也不多,因此需要我们自行对代码进行一定的分析,才能...

3856
来自专栏SpringSpace.cn

在 ubuntu 12.10 中安装 opensips 1.8.2

解压软件包: tar -zxvf opensips-1.8.2_src.tar.gz

1912
来自专栏JAVA同学会

Spring Security实现RBAC权限管理

在企业应用中,认证和授权是非常重要的一部分内容,业界最出名的两个框架就是大名鼎鼎的 Shiro和Spring Security。由于Spring Boot非常的...

3802
来自专栏冷冷

oAuth2 升级Spring Cloud Finchley.RELEASE踩坑分享 .md

6.19号,spring团队发布了期待已久的 Spring Cloud Finchley.RELEASE 版本。

2593
来自专栏battcn

一起来学Spring Cloud(F版) | 第二篇:Ribbon软负载

Ribbon 是 Netflix 开源的基于 HTTP 和 TCP 的客户端负载均衡器框架,目前也已被 SpringCloud 团队集成在 spring-clo...

1103
来自专栏菩提树下的杨过

jboss eap 6.3 集群(cluster)-Session 复制(Replication)

本文算是前一篇的后续,java web application中,难免会用到session,集群环境中apache会将http请求智能转发到其中某台jboss ...

3367

扫码关注云+社区