線程中無法實例化spring注入的服務的解決辦法


  問題描述

  在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 }

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com