有没有办法在Spring应用程序中静态/全局请求ApplicationContext的副本?
假设主类启动并初始化应用程序上下文,是否需要将它通过调用堆栈传递给任何需要它的类,或者有没有办法让类询问先前创建的上下文?(我认为必须是单身?)
如果需要访问容器的对象是容器中的bean,则只需实现BeanFactoryAware或ApplicationContextAware接口.
如果容器外的对象需要访问容器,我已经为弹簧容器使用了标准的GoF单例模式.这样,您的应用程序中只有一个单例,其余的都是容器中的单例bean.
您可以实现ApplicationContextAware
或只使用@Autowired
:
public class SpringBean { @Autowired private ApplicationContext appContext; }
SpringBean
将ApplicationContext
注入,在其中实例化此bean.例如,如果您的Web应用程序具有非常标准的上下文层次结构:
main application context <- (child) MVC context
并且SpringBean
在主要上下文中声明,它将注入主要上下文; 否则,如果它在MVC上下文中声明,它将注入MVC上下文.
这是一个不错的方式(不是我的,原始参考在这里:http: //sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html
我用过这种方法,它运行正常.基本上它是一个简单的bean,它包含对应用程序上下文的(静态)引用.通过在spring配置中引用它,它已初始化.
看看原始参考,非常清楚.
我相信你可以使用SingletonBeanFactoryLocator.beanRefFactory.xml文件将保存实际的applicationContext,它将是这样的:
../applicationContext.xml
从wheverver获取来自applicationcontext的bean的代码将是这样的:
BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance(); BeanFactoryReference bf = bfl.useBeanFactory("mainContext"); SomeService someService = (SomeService) bf.getFactory().getBean("someService");
Spring团队不鼓励使用这个类和yadayada,但它在我使用它的地方很适合我.
在您实施任何其他建议之前,请问自己这些问题......
为什么我要尝试获取ApplicationContext?
我是否有效地使用ApplicationContext作为服务定位器?
我可以完全避免访问ApplicationContext吗?
这些问题的答案在某些类型的应用程序(例如Web应用程序)中比在其他应用程序中更容易,但无论如何都值得提出.
访问ApplicationContext确实违反了整个依赖注入原则,但有时你没有太多选择.
如果您使用Web应用程序,还可以通过使用servletfilter和ThreadLocal来访问应用程序上下文而不使用单例.在过滤器中,您可以使用WebApplicationContextUtils访问应用程序上下文,并在TheadLocal中存储应用程序上下文或所需的bean.
警告:如果您忘记取消设置ThreadLocal,则在尝试取消部署应用程序时会遇到令人讨厌的问题!因此,您应该设置它并立即启动尝试以取消最终部分中的ThreadLocal.
当然,这仍然使用单例:ThreadLocal.但实际的bean不再需要了.甚至可以是请求范围的,如果在具有EAR中的库的应用程序中有多个WAR,则此解决方案也可以工作.不过,您可能会认为ThreadLocal的使用与使用普通单例一样糟糕.;-)
也许Spring已经提供了类似的解决方案?我找不到一个,但我不确定.
SpringApplicationContext.java import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * Wrapper to always return a reference to the Spring Application Context from * within non-Spring enabled beans. Unlike Spring MVC's WebApplicationContextUtils * we do not need a reference to the Servlet context for this. All we need is * for this bean to be initialized during application startup. */ public class SpringApplicationContext implements ApplicationContextAware { private static ApplicationContext CONTEXT; /** * This method is called from within the ApplicationContext once it is * done starting up, it will stick a reference to itself into this bean. * @param context a reference to the ApplicationContext. */ public void setApplicationContext(ApplicationContext context) throws BeansException { CONTEXT = context; } /** * This is about the same as context.getBean("beanName"), except it has its * own static handle to the Spring context, so calling this method statically * will give access to the beans by name in the Spring application context. * As in the context.getBean("beanName") call, the caller must cast to the * appropriate target class. If the bean does not exist, then a Runtime error * will be thrown. * @param beanName the name of the bean to get. * @return an Object reference to the named bean. */ public static Object getBean(String beanName) { return CONTEXT.getBean(beanName); } }
资料来源:http://sujitpal.blogspot.de/2007/03/accessing-spring-beans-from-legacy-code.html
看一下ContextSingletonBeanFactoryLocator。它提供了静态访问器来获取Spring的上下文,并假设它们已经以某些方式进行了注册。
它虽然不漂亮,但是比您想要的更复杂,但是可以。