問題說明
今天在web應用中用到了Java多線程的技術來並發處理一些業務,但在執行時一直會報NullPointerException的錯誤,問題定位了一下發現是線程中的Spring bean沒有被注入,bean對象的值為null。
原因分析
web容器在啟動應用時,並沒有提前將線程中的bean注入(在線程啟動前,web容易也是無法感知的)
解決方案
方法有多種,網上也看到了不少。
1. 使用static聲明變量
可參見
引用
http://blog.csdn.net/bjamosgavin/article/details/6125497
但這個方法自己試了一下但是沒有成功。。。
2. 把線程設置為主程序的內部類
這也是一種簡單的方法,主程序在web容器加載時肯定是可以注入Spring bean的,那么將線程的實現類放在主程序的類中便可以“共享”Spring的bean,(當然,這需要提前把線程中的需要用到的bean定義在外層的類中)。
具體操作方法,就是將生成線程的線程池定義在主程序的類中,每個線程的實現類作為內部類也定義在主程序中。這個方法自己試過,是可以的。
3. 使用靜態方法直接取的容器中的spring對象
這個方法稍微專業點,可以線程的分發與線程的實現分離出來。在每個線程中使用靜態方法直接取的容器中的spring對象。
使用靜態方法獲取容器中的spring對象可以參見
引用
http://littie1987.iteye.com/blog/937877,
或者http://my.oschina.net/skyline520/blog/181158?p={{page}}
但一定要記住,你定義這個工具類也要配置成spring中的bean!
下面貼一下我在使用時的代碼
(1)定義工具類
public class SpringApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext context) throws BeansException { SpringApplicationContextHolder.context = context; } public static Object getSpringBean(String beanName) { notEmpty(beanName, "bean name is required"); return context==null?null:context.getBean(beanName); } public static String[] getBeanDefinitionNames() { return context.getBeanDefinitionNames(); }
在Spring中注冊工具類的bean
<bean class="com.xxx.spring.SpringApplicationContextHolder" />
線程中獲取bean
UserRepo user = (UserRepo) SpringApplicationContextHolder.getSpringBean("userRepo");