问题描述

  在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    * @return
23    */
24   public static ApplicationContext getApplicationContext() {
25     return applicationContext;
26   }
27 
28 
29   /**
30    * 根据bean的id来查找对象
31    * @param id
32    * @return
33    */
34 
35   public static <T> T getBeanById(String id) {
36     return (T) applicationContext.getBean(id);
37   }
38 
39 
40   /**
41    * 根据bean的class来查找对象
42    * @param c
43    * @return
44    */
45   public static <T> T getBeanByClass(Class c) {
46     return (T) applicationContext.getBean(c);
47   }
48 
49 
50   /**
51    * 根据bean的class来查找所有的对象(包括子类)
52    * @param c
53    * @return
54    */
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 }

 

posted on 2016-03-09 21:37  Rory.Zhang  阅读(9365)  评论(0编辑  收藏  举报