获取Spring应用程序上下文
有没有一种方法可以在Spring应用程序中静态/全局地请求ApplicationContext的副本?
假设主类启动并初始化了应用程序上下文,它是否需要通过调用堆栈将其向下传递给需要它的任何类,还是有一种方法可以让一个类请求先前创建的上下文? (我认为必须是一个单身人士?)
解决方案
这是一个不错的方法(不是我的,原始参考在这里:
http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html
我已经使用了这种方法,并且效果很好。基本上,它是一个简单的bean,其中包含对应用程序上下文的(静态)引用。通过在spring config中引用它,可以对其进行初始化。
看一下原始的参考,这很清楚。
看一下ContextSingletonBeanFactoryLocator。它提供了静态访问器来获取Spring的上下文,并假设它们已经以某些方式进行了注册。
它并不漂亮,而且可能比我们想要的还要复杂,但是它可以工作。
如果需要访问容器的对象是容器中的Bean,则只需实现BeanFactoryAware或者ApplicationContextAware接口。
如果容器外部的对象需要访问该容器,那么我已经对弹簧容器使用了标准的GoF单例模式。这样,应用程序中只有一个单例,其余都是容器中的所有单例bean。
在实施任何其他建议之前,请先问自己以下问题...
- 为什么我要获取ApplicationContext?
- 我可以有效地将ApplicationContext用作服务定位器吗?
- 我可以完全避免访问ApplicationContext吗?
这些问题的答案在某些类型的应用程序(例如Web应用程序)中比在其他类型的应用程序中容易,但是无论如何都值得提出。
访问ApplicationContext确实违反了整个依赖注入原理,但是有时我们没有太多选择。
我相信我们可以使用SingletonBeanFactoryLocator。 beanRefFactory.xml文件将保存实际的applicationContext,它将类似于以下内容:
<bean id="mainContext" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <list> <value>../applicationContext.xml</value> </list> </constructor-arg> </bean>
从任何地方从applicationcontext获取bean的代码都是这样的:
BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance(); BeanFactoryReference bf = bfl.useBeanFactory("mainContext"); SomeService someService = (SomeService) bf.getFactory().getBean("someService");
Spring团队不鼓励使用此类和yadayada,但在使用该类的地方它非常适合我。
如果我们使用Web应用程序,则还有另一种方法可以通过使用servletfilter和ThreadLocal来访问应用程序上下文而不使用单例。在过滤器中,我们可以使用WebApplicationContextUtils访问应用程序上下文,并将应用程序上下文或者所需的bean存储在TheadLocal中。
警告:如果我们忘记取消设置ThreadLocal,则在尝试取消部署应用程序时会遇到讨厌的问题!因此,我们应该对其进行设置,然后立即开始尝试以在final-part中取消设置ThreadLocal。
当然,这仍然使用单例:ThreadLocal。但是实际的bean不再需要了。甚至可以在请求范围内使用,如果应用程序中有多个WAR,并且EAR中有库,则此解决方案也可以使用。不过,我们可能会认为ThreadLocal的使用与纯单例的使用一样糟糕。 ;-)
也许Spring已经提供了类似的解决方案?我没有找到一个,但我不确定。