• 线程中无法实例化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 }
  • 相关阅读:
    java读取properties 属性文件
    oracle中插入一条数据,id自动增长,插入之后怎么得到这个id(sequence的使用)
    Android布局实现圆角边框
    TabHost中使用startActivityForResult无法接收返回值的解决方案[转]
    ORA00937: not a singlegroup group function
    MVC与WebForm最大的区别
    使用SQL Server存储ASP.NET Session变量
    JS中的event 对象详解
    一列多行值合并成一个值(MS SQL SERVER 2008)
    c#如何共享程序集
  • 原文地址:https://www.cnblogs.com/playcode/p/5259781.html
Copyright © 2020-2023  润新知