有问题的写法
有些时候想用ApplicationContext又怕麻烦,于是使用一个工具类持有当前的ApplicationContext,保存为静态变量,代码示例如下:
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextHolder.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
}
使用时代码如下:
ApplicationContextHolder.getApplicationContext().getBean("略")
static的本意是方便工具类使用,不需要实例。
问题出在哪
static意味着独一个,如果这个bean被声明在同一个jvm的多个ApplicationContext中,问题就出现了。
setter被调用多次,参数为不同的ApplicationContext,static变量保存的引用和期待的就不一样。
通常我们不会写出多个ApplicationContext,但是,spring-webmvc就这么干了,在一个jvm中启动了多个ApplicationContext,而且他们之间还有父子关系,详见笔者另一篇博文《spring-webmvc应用中有几个ApplicationContext》。
从另一个角度讲,笔者一直理解ApplicationContext在jvm中圈出了一个隔离起来的空间,应避免static属性这样的全局用法。
应该怎么办
如果是为了得到ApplicationContext,可以
- 让用的类实现
ApplicationContextAware,通过实现setter方法得到 -
@Autowired一个ApplicationContext,可用于属性、构造器或setter方法上
实际观察后,发现用这个工具类多是为了getBean(...),其实完全可以通过其他途径做到,比如@Autowired,可用于属性,构造器或setter方法上。
比较棘手的是需要小scope的bean时,应该使用其他方式,比如:
-
xml中使用<aop:scope-proxy> -
xml中使用<beans:lookup-method>或@Configuration类中@Lookup