一、问题:
在线程中使用注解注入失败(@Resource或者@Autowired注入全部为NULL),
原因就是spring和多线程安全的问题,不让注入。
原因就是spring和多线程安全的问题,不让注入。
二、主要解决方法有:
- 方法一:将需要的Bean作为线程的的构造函数的参数传入
- 方法二:使用ApplicationContext.getBean方法来静态的获取Bean
- 方法三:使用内部类的方法,在内部类中创建线程,然后就可以使用需要的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"); 即可
.getBean("systemConfigServiceBean"); 即可
四、分析方法三
使用内部类的方法,将线程中需要的Bean提前注入好,大致的结构如下:
class TestExample{
//这两个为线程所需要的Bean
TestDao testDao;
NeedDap needDao;
public void serviceExecute(){
//在这里开启线程,执行操作
ThreadExample te = new ThreadExample();
te.start();
}
//内部类
private class ThreadExample extends Thread{
public ThreadExample(){
//也可以在构造函数中传入参数
}
public void run(){
//这里为线程的操作
//就可以使用注入之后Bean了
}
}
}