首先需要知道的是,容器中的组件,也就是你添加了诸如 @Component
,@Service
, @Controller
以及 @Repository
等等注解,在容器启动的时候是会扫描标注这些注解的类创建 Bean 并放入容器中。
如果该类中的成员变量上使用了诸如 @Autowired
和 @Resource
注解时,容器将会找对应的 Bean 并注入,又叫依赖注入。
而在多线程实例中使用 @Autowired
注解得不到对象,又叫 Null,为什么呢?
这是因为多线程是防注入的,所以只是在多线程实现类中简单的使用 @Autowired
方法注入自己的 service,会在程序运行到此类调用 service 方法的时候提示注入的 service 为 null。
所以这里给出两种解决方案:
service
当做多线程实现类的一个属性参数(也就是构造的时候当做参数或者没有构造的话使用set方法),然后在调用多线程,使用new的时候将该service赋值给实现类springbean
的帮助类,实现 ApplicationContextAware
接口:/**
* 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext.
*
* @author Zaric
* @date 2013-5-29 下午1:25:40
*/
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
assertContextInjected();
return applicationContext;
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
assertContextInjected();
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
if (logger.isDebugEnabled()){
logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
}
applicationContext = null;
}
/**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
/**
* 实现DisposableBean接口, 在Context关闭时清理静态变量.
*/
@Override
public void destroy() throws Exception {
SpringContextHolder.clearHolder();
}
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected() {
Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
}
}
调用
private static LogDao logDao = SpringContextHolder.getBean(LogDao.class);
private static SynchroDataService synchroDataService = SpringContextHolder.getBean(SynchroDataService.class);
用帮助类的时候应注意以下几点:
a.如果是用注解形式注入spring容器(即不用spring的配置文件)的话,一定要使用@Component将此帮助类注入到spring容器中。此时可以通过clazz参数形式:clazz为在多线程中使用的service的类名.class(点class)。
b.帮助类中定义ApplicationContext类型的静态变量applicationContext,然后在获取bean的方法中使用该静态变量从spring容器中获取通过getBean方法获取容器中的bean。
c.当使用spring配置文件的时候,一定要使用<bean id="springBeanUtil" class="类的路径" />
将帮助类注入到容器中。然后在多线程中使用serveri时获取bean的时候可以通过上面name参数形式:name一定是想要在多线程中使用的service在spring配置文件中注入的bean标签的id值,也可以通过上面clazz参数形式:clazz为在多线程中使用的service的类名.class(点class)。
d.帮助类获取bean的方法一定是static修饰静态方法
e.重要的事情说3遍:不管使用注解形式还是spring配置文件形式,帮助类一定要注入到spring容器中!!!