线程中实例化spring注入服务

来源:互联网 发布:网站编程常见单词 编辑:程序博客网 时间:2024/06/03 17:22

问题描述

  在Java Web应用中采用多线程处理数据,发现Spring注入的服务一直报NullPointerException。使用注解式的声明@Resource和XML配置的bean声明,都报空指针。然后寻找万能的网络寻找帮助,有的说spring因为考虑到线程安全问题,不支持注入,以及spring的bean声明周期,在工程启动时,没有检测到线程中的bean,进行注入。看来只能主动去获取spring声明的周期。

 

  解决办法:

  (1)主动实例化对象(不推荐)

 private TestService testService = new TestServiceImpl();

    每次加载这个类,就会重新创建一次,会过多耗费资源。

  (2)把线程设置为主程序的内部类,或者是利用线程的构造方法把bean传递过去

    主程序在web容器加载时,肯定是可以注入Spring bean的,那么将线程的实现类放在主程序的类中便可以“共享”Spring的bean,将生成线程的线程池定义在主程序的类中,每个线程的实现类作为内部类也定义在主程序中。

 

复制代码
 1 public class Test implements InitializingBean{ 2   3     @Resource 4     private TestService testService 5   6     public void close(){ 7     } 8  9     public void afterPropertiesSet() throws Exception {10         // 利用构造方法把bean传递过去11         new Thread(testService);12     }13 }
复制代码

 

 

 

  (3)用静态方法直接取的容器中的spring对象

    写一个SpringContextUtil类,实现ApplicationContextAware

复制代码
 1 package com.test.utils; 2  3 import java.util.Locale; 4 import java.util.Map; 5  6 import org.springframework.beans.BeansException; 7 import org.springframework.context.ApplicationContext; 8 import org.springframework.context.ApplicationContextAware; 9 10 public class SpringContextUtil implements ApplicationContextAware {11 12   private static ApplicationContext applicationContext = null;13 14 15   public void setApplicationContext(ApplicationContext context) throws BeansException {16     applicationContext = context;17   }18 19 20   /**21    * 获取applicationContext对象22    * @return23    */24   public static ApplicationContext getApplicationContext() {25     return applicationContext;26   }27 28 29   /**30    * 根据bean的id来查找对象31    * @param id32    * @return33    */34 35   public static <T> T getBeanById(String id) {36     return (T) applicationContext.getBean(id);37   }38 39 40   /**41    * 根据bean的class来查找对象42    * @param c43    * @return44    */45   public static <T> T getBeanByClass(Class c) {46     return (T) applicationContext.getBean(c);47   }48 49 50   /**51    * 根据bean的class来查找所有的对象(包括子类)52    * @param c53    * @return54    */55   public static Map getBeansByClass(Class c) {56     return applicationContext.getBeansOfType(c);57   }58 59   public static String getMessage(String key) {60     return applicationContext.getMessage(key, null, Locale.getDefault());61   }62 63 }
复制代码

      在applicationContext.xml中声明SpringContextUtil的bean

<bean id="springContextUtil" class="com.test.utils.SpringContextUtil"/>

      在线程中或线程调用的其他服务中可以主动加载bean,然后可以直接使用(testService必须是spring中配置的bean)

1 public void run() {2   TestService testService = (TestService ) SpringContextUtil.getBean("testService");3   testService.queryData(); 
4 }

       (4)看到网上说还可以通过BeanFactory来加载bean,没有去实现过,上个代码做个参考

复制代码
 1 public class SpringBeanFactoryUtils implements BeanFactoryAware {   2    3     private static BeanFactory beanFactory = null;   4     private static SpringBeanFactoryUtils factoryUtils = null;   5        6    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {   7         SpringBeanFactoryUtils.beanFactory = beanFactory;   8     }   9     public static BeanFactory getBeanFactory() {  10         return beanFactory;  11     }  12     public static SpringBeanFactoryUtils getInstance(){  13         if(factoryUtils==null){  14             //factoryUtils = (SpringBeanFactoryUtils)beanFactory.getBean("springBeanFactoryUtils");  15             factoryUtils = new SpringBeanFactoryUtils();  16         }  17         return factoryUtils;  18     }  19     public static Object getBean(String name){  20         return beanFactory.getBean(name);  21     }  22 }
原创粉丝点击