問題說明
今天在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();
}
(2)在Spring中註冊工具類的bean
(3)線程中獲取bean
UserRepo user = (UserRepo) SpringApplicationContextHolder.getSpringBean("userRepo");