获取Spring应用程序上下文

Joe*_*ora 210 java configuration spring

有没有办法在Spring应用程序中静态/全局请求ApplicationContext的副本?

假设主类启动并初始化应用程序上下文,是否需要将它通过调用堆栈传递给任何需要它的类,或者有没有办法让类询问先前创建的上下文?(我认为必须是单身?)

Don*_*kby 168

如果需要访问容器的对象是容器中的bean,则只需实现BeanFactoryAwareApplicationContextAware接口.

如果容器外的对象需要访问容器,我已经为弹簧容器使用了标准的GoF单例模式.这样,您的应用程序中只有一个单例,其余的都是容器中的单例bean.

  • ApplicationContexts还有一个更好的接口--ApplicationContextAware.BeanFactoryAware应该可以工作,但如果您需要应用程序上下文功能,则必须将其强制转换为应用程序上下文. (14认同)
  • 谢谢你的提示,我已经更新了答案. (2认同)

omn*_*nom 115

您可以实现ApplicationContextAware或只使用@Autowired:

public class SpringBean {
  @Autowired
  private ApplicationContext appContext;
}
Run Code Online (Sandbox Code Playgroud)

SpringBeanApplicationContext注入,在其中实例化此bean.例如,如果您的Web应用程序具有非常标准的上下文层次结构:

main application context <- (child) MVC context
Run Code Online (Sandbox Code Playgroud)

并且SpringBean在主要上下文中声明,它将注入主要上下文; 否则,如果它在MVC上下文中声明,它将注入MVC​​上下文.

  • 这帮了很多.对于使用Spring 2.0的旧应用程序,我遇到了一些奇怪的问题,而你的回答是我能用一个单一的ApplicationContext,只需一个Spring IoC容器就可以得到理解的唯一方法. (2认同)

Ste*_* B. 38

这是一个不错的方式(不是我的,原始参考在这里:http: //sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html

我用过这种方法,它运行正常.基本上它是一个简单的bean,它包含对应用程序上下文的(静态)引用.通过在spring配置中引用它,它已初始化.

看看原始参考,非常清楚.

  • 如果从在单元测试期间运行的代码调用`getBean`,那么该方法可能会失败,因为在您请求之前不会设置Spring上下文.在成功使用这种方法2年之后,我刚刚抨击它的竞争条件. (4认同)

sti*_*ian 18

我相信你可以使用SingletonBeanFactoryLocator.beanRefFactory.xml文件将保存实际的applicationContext,它将是这样的:

<bean id="mainContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
     <constructor-arg>
        <list>
            <value>../applicationContext.xml</value>
        </list>
     </constructor-arg>
 </bean>
Run Code Online (Sandbox Code Playgroud)

从wheverver获取来自applicationcontext的bean的代码将是这样的:

BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
BeanFactoryReference bf = bfl.useBeanFactory("mainContext");
SomeService someService = (SomeService) bf.getFactory().getBean("someService");
Run Code Online (Sandbox Code Playgroud)

Spring团队不鼓励使用这个类和yadayada,但它在我使用它的地方很适合我.


bel*_*bob 11

在您实施任何其他建议之前,请问自己这些问题......

  • 为什么我要尝试获取ApplicationContext?
  • 我是否有效地使用ApplicationContext作为服务定位器?
  • 我可以完全避免访问ApplicationContext吗?

这些问题的答案在某些类型的应用程序(例如Web应用程序)中比在其他应用程序中更容易,但无论如何都值得提出.

访问ApplicationContext确实违反了整个依赖注入原则,但有时你没有太多选择.

  • 一个很好的例子是JSP标签; 他们的创造是由servlet容器决定的,因此他们别无选择,只能静态获取上下文.Spring提供了基类Tag类,它们使用BeanFactoryLocators来获取所需的上下文. (5认同)

Han*_*örr 6

如果您使用Web应用程序,还可以通过使用servletfilter和ThreadLocal来访问应用程序上下文而不使用单例.在过滤器中,您可以使用WebApplicationContextUtils访问应用程序上下文,并在TheadLocal中存储应用程序上下文或所需的bean.

警告:如果您忘记取消设置ThreadLocal,则在尝试取消部署应用程序时会遇到令人讨厌的问题!因此,您应该设置它并立即启动尝试以取消最终部分中的ThreadLocal.

当然,这仍然使用单例:ThreadLocal.但实际的bean不再需要了.甚至可以是请求范围的,如果在具有EAR中的库的应用程序中有多个WAR,则此解决方案也可以工作.不过,您可能会认为ThreadLocal的使用与使用普通单例一样糟糕.;-)

也许Spring已经提供了类似的解决方案?我找不到一个,但我不确定.


gog*_*tad 6

请注意,通过将当前的任何状态ApplicationContext或它ApplicationContext本身存储在静态变量中(例如使用单例模式),如果您使用 Spring-test,您将使您的测试不稳定且不可预测。这是因为 Spring-test 在同一个 JVM 中缓存并重用应用程序上下文。例如:

  1. 测试 A 运行并用 进行注释@ContextConfiguration({"classpath:foo.xml"})
  2. 测试 B 运行并注释为@ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
  3. 测试C运行并注释为@ContextConfiguration({"classpath:foo.xml"})

当测试 A 运行时,ApplicationContext会创建一个 Bean,并且任何实现ApplicationContextAware或自动装配的BeanApplicationContext的 bean 都可能写入静态变量。

当测试 B 运行时,会发生同样的事情,静态变量现在指向测试 B 的ApplicationContext

当测试 C 运行时,不会创建任何 Bean,因为测试 A 中的TestContext(此处为ApplicationContext)被重新使用。现在您有了一个静态变量,它指向另一个变量,ApplicationContext而不是当前保存用于测试的 bean 的变量。


Van*_*ato 6

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

资料来源:http://sujitpal.blogspot.de/2007/03/accessing-spring-beans-from-legacy-code.html


ska*_*man 5

看一下ContextSingletonBeanFactoryLocator。它提供了静态访问器来获取Spring的上下文,并假设它们已经以某些方式进行了注册。

它虽然不漂亮,但是比您想要的更复杂,但是可以。


Md.*_*rim 5

在 Spring 应用程序中有多种获取应用程序上下文的方法。这些是在下面给出的:

  1. 通过 ApplicationContextAware

    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    
    public class AppContextProvider implements ApplicationContextAware {
    
    private ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    }
    
    Run Code Online (Sandbox Code Playgroud)

这里setApplicationContext(ApplicationContext applicationContext)方法你会得到applicationContext

应用上下文感知

由任何希望被通知它运行的 ApplicationContext 的对象实现的接口。例如,当一个对象需要访问一组协作 bean 时,实现这个接口是有意义的。

  1. 通过自动连线

    @Autowired
    private ApplicationContext applicationContext;
    
    Run Code Online (Sandbox Code Playgroud)

这里@Autowired关键字将提供applicationContext。Autowired 有一些问题。它会在单元测试期间产生问题。