Java 获取 Spring 应用程序上下文
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/129207/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting Spring Application Context
提问by Joe Skora
Is there a way to statically/globally request a copy of the ApplicationContext in a Spring application?
有没有办法在 Spring 应用程序中静态/全局请求 ApplicationContext 的副本?
Assuming the main class starts up and initializes the application context, does it need to pass that down through the call stack to any classes that need it, or is there a way for a class to ask for the previously created context? (Which I assume has to be a singleton?)
假设主类启动并初始化应用程序上下文,它是否需要通过调用堆栈将其传递给任何需要它的类,或者有没有办法让类请求先前创建的上下文?(我认为必须是单身人士?)
采纳答案by Don Kirkby
If the object that needs access to the container is a bean in the container, just implement the BeanFactoryAwareor ApplicationContextAwareinterfaces.
如果需要访问容器的对象是容器中的 bean,则只需实现BeanFactoryAware或ApplicationContextAware接口。
If an object outside the container needs access to the container, I've used a standard GoF singleton patternfor the spring container. That way, you only have one singleton in your application, the rest are all singleton beans in the container.
如果容器外的对象需要访问容器,我对 spring 容器使用了标准的 GoF 单例模式。这样,您的应用程序中只有一个单例,其余的都是容器中的单例 bean。
回答by Steve B.
Here's a nice way (not mine, the original reference is here: http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html
这是一个不错的方法(不是我的,原始参考在这里:http: //sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html
I've used this approach and it works fine. Basically it's a simple bean that holds a (static) reference to the application context. By referencing it in the spring config it's initialized.
我已经使用过这种方法并且效果很好。基本上它是一个简单的 bean,它包含对应用程序上下文的(静态)引用。通过在 spring 配置中引用它,它被初始化。
Take a look at the original ref, it's very clear.
看一下原始参考,它很清楚。
回答by skaffman
Take a look at ContextSingletonBeanFactoryLocator. It provides static accessors to get hold of Spring's contexts, assuming they have been registered in certain ways.
看看ContextSingletonBeanFactoryLocator。它提供静态访问器来获取 Spring 的上下文,假设它们已以某种方式注册。
It's not pretty, and more complex than perhaps you'd like, but it works.
它并不漂亮,而且可能比您想要的更复杂,但它确实有效。
回答by belugabob
Before you implement any of the other suggestions, ask yourself these questions...
在你实施任何其他建议之前,问问自己这些问题......
- Why am I trying to get the ApplicationContext?
- Am I effectively using the ApplicationContext as a service locator?
- Can I avoid accessing the ApplicationContext at all?
- 为什么我要尝试获取 ApplicationContext?
- 我是否有效地使用 ApplicationContext 作为服务定位器?
- 我可以完全避免访问 ApplicationContext 吗?
The answers to these questions are easier in certain types of applications (Web apps, for example) than they are in others, but are worth asking anyway.
这些问题的答案在某些类型的应用程序(例如 Web 应用程序)中比在其他应用程序中更容易,但无论如何都值得一问。
Accessing the ApplicationContext does kind of violate the whole dependency injection principle, but sometimes you've not got much choice.
访问 ApplicationContext 确实违反了整个依赖注入原则,但有时您没有太多选择。
回答by stian
I believe you could use SingletonBeanFactoryLocator. The beanRefFactory.xml file would hold the actual applicationContext, It would go something like this:
我相信你可以使用SingletonBeanFactoryLocator。beanRefFactory.xml 文件将保存实际的 applicationContext,它会是这样的:
<bean id="mainContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>../applicationContext.xml</value>
</list>
</constructor-arg>
</bean>
And the code to get a bean from the applicationcontext from whereever would be something like this:
以及从任何地方从应用程序上下文中获取 bean 的代码是这样的:
BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
BeanFactoryReference bf = bfl.useBeanFactory("mainContext");
SomeService someService = (SomeService) bf.getFactory().getBean("someService");
The Spring team discourage the use of this class and yadayada, but it has suited me well where I have used it.
Spring 团队不鼓励使用这个类和 yadayada,但它非常适合我使用它的地方。
回答by Hans-Peter St?rr
If you use a web-app there is also another way to access the application context without using singletons by using a servletfilter and a ThreadLocal. In the filter you can access the application context using WebApplicationContextUtils and store either the application context or the needed beans in the TheadLocal.
如果您使用 Web 应用程序,还有另一种方法可以通过使用 servletfilter 和 ThreadLocal 来访问应用程序上下文,而无需使用单例。在过滤器中,您可以使用 WebApplicationContextUtils 访问应用程序上下文并将应用程序上下文或所需的 bean 存储在 TheadLocal 中。
Caution: if you forget to unset the ThreadLocal you will get nasty problems when trying to undeploy the application! Thus, you should set it and immediately start a try that unsets the ThreadLocal in the finally-part.
注意:如果您忘记取消设置 ThreadLocal,您将在尝试取消部署应用程序时遇到令人讨厌的问题!因此,您应该设置它并立即开始尝试在 finally 部分取消设置 ThreadLocal 。
Of course, this still uses a singleton: the ThreadLocal. But the actual beans do not need to be anymore. The can even be request-scoped, and this solution also works if you have multiple WARs in an Application with the libaries in the EAR. Still, you might consider this use of ThreadLocal as bad as the use of plain singletons. ;-)
当然,这仍然使用单例:ThreadLocal。但实际的 bean 不再需要了。甚至可以是请求范围的,如果应用程序中有多个 WAR,并且 EAR 中有库,则此解决方案也适用。不过,您可能认为 ThreadLocal 的这种使用与普通单例的使用一样糟糕。;-)
Perhaps Spring already provides a similar solution? I did not find one, but I don't know for sure.
也许 Spring 已经提供了类似的解决方案?我没有找到,但我不确定。
回答by omnomnom
You can implement ApplicationContextAware
or just use @Autowired
:
您可以实施ApplicationContextAware
或仅使用@Autowired
:
public class SpringBean {
@Autowired
private ApplicationContext appContext;
}
SpringBean
will have ApplicationContext
injected, within which this bean is instantiated. For example if you have web application with a pretty standard contexts hierarchy:
SpringBean
将ApplicationContext
注入,在其中实例化此 bean。例如,如果您的 Web 应用程序具有非常标准的上下文层次结构:
main application context <- (child) MVC context
and SpringBean
is declared within main context, it will have main context injected;
otherwise, if it's declared within MVC context, it will have MVC context injected.
并且SpringBean
在主上下文中声明,它将注入主上下文;否则,如果它是在 MVC 上下文中声明的,它将注入 MVC 上下文。
回答by gogstad
Note that by storing any state from the current ApplicationContext
, or the ApplicationContext
itself in a static variable - for example using the singleton pattern - you will make your tests unstable and unpredictable if you're using Spring-test. This is because Spring-test caches and reuses application contexts in the same JVM. For example:
请注意,通过将来自 current 的任何状态ApplicationContext
或其ApplicationContext
本身存储在静态变量中 - 例如使用单例模式 - 如果您使用 Spring-test,您将使您的测试不稳定和不可预测。这是因为 Spring-test 在同一个 JVM 中缓存和重用应用程序上下文。例如:
- Test A run and it is annotated with
@ContextConfiguration({"classpath:foo.xml"})
. - Test B run and it is annotated with
@ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
- Test C run and it is annotated with
@ContextConfiguration({"classpath:foo.xml"})
- 测试 A 运行,它用
@ContextConfiguration({"classpath:foo.xml"})
. - 测试 B 运行,并带有注释
@ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
- 测试 C 运行,它被注释为
@ContextConfiguration({"classpath:foo.xml"})
When Test A runs, an ApplicationContext
is created, and any beans implemeting ApplicationContextAware
or autowiring ApplicationContext
might write to the static variable.
当测试 A 运行时,ApplicationContext
会创建一个,并且任何实现ApplicationContextAware
或自动装配的bean 都ApplicationContext
可能写入静态变量。
When Test B runs the same thing happens, and the static variable now points to Test B's ApplicationContext
当测试 B 运行时,同样的事情发生,静态变量现在指向测试 B 的 ApplicationContext
When Test C runs, no beans are createdas the TestContext
(and herein the ApplicationContext
) from Test A is resused. Now you got a static variable pointing to another ApplicationContext
than the one currently holding the beans for your test.
当测试 C 运行时,不会创建任何 bean,因为来自测试 A的TestContext
(以及此处的ApplicationContext
)被重用。现在您有一个静态变量指向另一个,而ApplicationContext
不是当前为您的测试持有 bean 的变量。
回答by Kanagavelu Sugumar
Please note that; the below code will create new application context instead of using the already loaded one.
请注意;下面的代码将创建新的应用程序上下文,而不是使用已经加载的上下文。
private static final ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
Also note that beans.xml
should be part of src/main/resources
means in war it is part of WEB_INF/classes
, where as the real application will be loaded through applicationContext.xml
mentioned at Web.xml
.
还要注意,beans.xml
应该是src/main/resources
战争中的手段的一部分,它是其中的一部分WEB_INF/classes
,真正的应用程序将通过applicationContext.xml
在 中提到的加载Web.xml
。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>META-INF/spring/applicationContext.xml</param-value>
</context-param>
It is difficultto mention applicationContext.xml
path in ClassPathXmlApplicationContext
constructor. ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml")
wont be able to locate the file.
这是很难说applicationContext.xml
的路径ClassPathXmlApplicationContext
构造。ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml")
将无法找到该文件。
So it is better to use existing applicationContext by using annotations.
所以最好通过使用注解来使用现有的 applicationContext。
@Component
public class OperatorRequestHandlerFactory {
public static ApplicationContext context;
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
context = applicationContext;
}
}
回答by Vanessa Schissato
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);
}
}
Source: http://sujitpal.blogspot.de/2007/03/accessing-spring-beans-from-legacy-code.html
来源:http: //sujitpal.blogspot.de/2007/03/accessing-spring-beans-from-legacy-code.html