Spring 在多线程中,bean的注入问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tangshuai33333/article/details/79669025

一、问题:
在线程中使用注解注入失败(@Resource或者@Autowired注入全部为NULL),
原因就是spring和多线程安全的问题,不让注入。

二、主要解决方法有:
  1. 方法一:将需要的Bean作为线程的的构造函数的参数传入
  2. 方法二:使用ApplicationContext.getBean方法来静态的获取Bean
  3. 方法三:使用内部类的方法,在内部类中创建线程,然后就可以使用需要的Bean
线程中所需要的Bean的数量较多,并且以后还有可能增加或者减少,所以方法1并不适合


三、方法三分析

根据spring上下文环境获取bean
创建类SpringContextUtil, 实现类ContextLoaderListener
web.config中

原应该为

SpringContextUtil 代码如下
package util;

import java.sql.Connection;
import java.sql.SQLException;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.WebApplicationContextUtils;

import ddd.simple.dao.base.DAO;
import ddd.simple.dao.systemConfig.SystemConfigDao;

public class SpringContextUtil extends ContextLoaderListener implements
		ServletContextListener {

	private static ApplicationContext applicationContext; // Spring应用上下文环境

	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	/**
	 * 获取对象
	 * 
	 * @param name
	 * @return Object 一个以所给名字注册的bean的实例
	 * @throws BeansException
	 */
	public static Object getBean(String name) throws BeansException {
		if (applicationContext == null) {
			return null;
		}
		return applicationContext.getBean(name);
	}

	/**
	 * 获取类型为requiredType的对象
	 * 如果bean不能被类型转换,相应的异常将会被抛出(BeanNotOfRequiredTypeException)
	 * 
	 * @param name
	 *            bean注册名
	 * @param requiredType
	 *            返回对象类型
	 * @return Object 返回requiredType类型对象
	 * @throws BeansException
	 */
	public static Object getBean(String name, Class<?> requiredType)
			throws BeansException {
		return applicationContext.getBean(name, requiredType);
	}

	/**
	 * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
	 * 
	 * @param name
	 * @return boolean
	 */
	public static boolean containsBean(String name) {
		return applicationContext.containsBean(name);
	}

	/**
	 * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。
	 * 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
	 * 
	 * @param name
	 * @return boolean
	 * @throws NoSuchBeanDefinitionException
	 */
	public static boolean isSingleton(String name)
			throws NoSuchBeanDefinitionException {
		return applicationContext.isSingleton(name);
	}

	/**
	 * @param name
	 * @return Class 注册对象的类型
	 * @throws NoSuchBeanDefinitionException
	 */
	public static Class<?> getType(String name)
			throws NoSuchBeanDefinitionException {
		return applicationContext.getType(name);
	}

	/**
	 * 如果给定的bean名字在bean定义中有别名,则返回这些别名
	 * 
	 * @param name
	 * @return
	 * @throws NoSuchBeanDefinitionException
	 */
	public static String[] getAliases(String name)
			throws NoSuchBeanDefinitionException {
		return applicationContext.getAliases(name);
	}

	public static Connection GetConnection() throws SQLException {
		DAO dao = applicationContext.getBean(SystemConfigDao.class);
		Connection conn = SessionFactoryUtils.getDataSource(
				dao.getSessionFactory()).getConnection();
		return conn;
	}

	public void contextDestroyed(ServletContextEvent event) {

	}

	public void contextInitialized(ServletContextEvent event) {
		super.contextInitialized(event);// 实际加载spring
		applicationContext = WebApplicationContextUtils
				.getWebApplicationContext(event.getServletContext());
	}
}

使用时:SystemConfigService systemConfigService = SpringContextUtil
      .getBean("systemConfigServiceBean");  即可

四、分析方法三

使用内部类的方法,将线程中需要的Bean提前注入好,大致的结构如下:
@Service
class TestExample{

   
//这两个为线程所需要的Bean
   
@Resource
   
TestDao testDao;

   
@Resource
   
NeedDap needDao;

    public void serviceExecute(){
       
//在这里开启线程,执行操作
       
ThreadExample te = new ThreadExample();
        te.start();
    }
   
   
//内部类
   
private class ThreadExample extends Thread{

        public
ThreadExample(){
           
//也可以在构造函数中传入参数
        }
        public void run(){
           
//这里为线程的操作
           
//就可以使用注入之后Bean了

        }
    }
}

猜你喜欢

转载自blog.csdn.net/Tangshuai33333/article/details/79669025