获得Spring应用上下文(Getting Spring Application Context)

2019-06-18 13:15发布

有没有一种方法,以静态/全球要求的ApplicationContext的副本在Spring应用程序?

假设主类启动并初始化应用程序上下文,它需要通过调用堆栈传递到任何需要它的类,或者是有一类,要求以前创建的上下文的方法吗? (我假设必须是单身?)

Answer 1:

如果所需要的容器访问的对象是在容器中的bean,只需实现了BeanFactoryAware或了ApplicationContextAware接口。

如果容器外部的对象需要访问容器,我使用一个标准的GoF Singleton模式用于弹簧容器。 这样一来,你只需要在你的应用程序一个单,其余都在容器中的所有单身豆类。



Answer 2:

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

public class SpringBean {
  @Autowired
  private ApplicationContext appContext;
}

SpringBean将有ApplicationContext注入,其内这个bean实例化。 例如,如果你有一个非常标准的背景层次的Web应用程序:

main application context <- (child) MVC context

SpringBean的主要范围内声明的,这将有主要方面注入; 否则,如果它的MVC框架内宣布,它将有MVC方面注入。



Answer 3:

这里是一个很好的方式(不是我的,原来的基准是在这里: http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html

我用这个方法,它工作正常。 基本上,它是拥有(静态)参考应用程序上下文一个简单的bean。 通过在Spring配置引用它它的初始化。

看看原来的裁判,这是非常清楚的。



Answer 4:

我相信你可以使用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的,但它适合我很好,我一直用它。



Answer 5:

你执行任何其他建议之前,先问问自己这些问题...

  • 为什么我试图让ApplicationContext的?
  • 我是否有效利用的ApplicationContext作为服务定位?
  • 我能避免访问ApplicationContext的呢?

这些问题的答案是在某些类型的应用程序(Web应用程序,例如)比他们在其他国家更容易,但值得一问反正。

访问ApplicationContext的呢那种违背整个依赖注入的原则,但有时你没有得到太多的选择。



Answer 6:

如果您使用web应用程序也有另一种方式来访问应用程序上下文不使用单身人士使用ServletFilter中和一个ThreadLocal。 在过滤器中,你可以使用WebApplicationContextUtils访问应用程序上下文和存储无论是应用方面还是在TheadLocal所需的豆类。

注意:如果你忘记取消设置ThreadLocal的尝试取消部署应用程序时,你会得到讨厌的问题! 因此,你应该设置它,并立即开始尝试取消设置ThreadLocal的在最后部分。

当然,这依然采用的是单:ThreadLocal的。 但实际的bean不需要再被。 该甚至可以请求范围的,而这个解决方案也适用,如果你在在耳边libaries应用程序有多个战争。 不过,你可能会考虑这种使用ThreadLocal中的那么糟糕,因为使用普通单身。 ;-)

也许春天已经提供了类似的解决方案? 我没有找到一个,但我不知道。



Answer 7:

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



Answer 8:

看看ContextSingletonBeanFactoryLocator的 。 它提供静态存取获得Spring的背景下举行,假定他们已经在某些方面被注册。

这不是漂亮,更复杂的或许比你想的,但它的工作原理。



Answer 9:

请注意,通过存储从当前的任何状态ApplicationContextApplicationContext本身在一个静态变量-使用Singleton模式的例子-你会做你的测试不稳定和不可预测的,如果你使用Spring测试。 这是因为春季测试缓存和在同一个JVM重用应用程序上下文。 例如:

  1. 测试运行,并标注有@ContextConfiguration({"classpath:foo.xml"})
  2. 试验B运行并且注释有@ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
  3. 测试C运行并且注释有@ContextConfiguration({"classpath:foo.xml"})

当测试A运行,一个ApplicationContext创建,任何豆implemeting ApplicationContextAware或自动装配ApplicationContext可能写入静态变量。

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

当试验C运行时, 没有豆作为创建 TestContext (以及本文所述ApplicationContext从试验A)被resused。 现在,你有一个静态变量指向另一个ApplicationContext比目前持有豆测试中的一个。



Answer 10:

有很多办法让应用程序上下文中的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; } } 

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

了ApplicationContextAware:

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

  1. 通过自动装配Autowired:

     @Autowired private ApplicationContext applicationContext; 

这里@Autowired关键字将提供一个ApplicationContext。 自动装配Autowired有一些问题。 这将单元测试过程中创建的问题。

谢谢 :)



Answer 11:

不知道这是多么有用会有,但你也可以得到背景下,当你初始化应用程序。 这是一个连之前尽快你可以得到的背景下, @Autowire

@SpringBootApplication
public class Application extends SpringBootServletInitializer {
    private static ApplicationContext context;

    // I believe this only runs during an embedded Tomcat with `mvn spring-boot:run`. 
    // I don't believe it runs when deploying to Tomcat on AWS.
    public static void main(String[] args) {
        context = SpringApplication.run(Application.class, args);
        DataSource dataSource = context.getBean(javax.sql.DataSource.class);
        Logger.getLogger("Application").info("DATASOURCE = " + dataSource);


Answer 12:

请注意; 下面的代码将创建的,而不是使用已经加载一个新的应用程序上下文。

private static final ApplicationContext context = 
               new ClassPathXmlApplicationContext("beans.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>

这是很难说applicationContext.xml路径ClassPathXmlApplicationContext构造。 ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml")将无法找到该文件。

因此,最好是通过使用注释使用现有的applicationContext。

@Component
public class OperatorRequestHandlerFactory {

    public static ApplicationContext context;

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        context = applicationContext;
    }
}


Answer 13:

我知道这个问题的答案,但我想和大家分享的科特林代码我做检索Spring上下文。

我不是专家,所以我愿意接受批评,评论和建议:

https://gist.github.com/edpichler/9e22309a86b97dbd4cb1ffe011aa69dd

package com.company.web.spring

import com.company.jpa.spring.MyBusinessAppConfig
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import
import org.springframework.stereotype.Component
import org.springframework.web.context.ContextLoader
import org.springframework.web.context.WebApplicationContext
import org.springframework.web.context.support.WebApplicationContextUtils
import javax.servlet.http.HttpServlet

@Configuration
@Import(value = [MyBusinessAppConfig::class])
@ComponentScan(basePackageClasses  = [SpringUtils::class])
open class WebAppConfig {
}

/**
 *
 * Singleton object to create (only if necessary), return and reuse a Spring Application Context.
 *
 * When you instantiates a class by yourself, spring context does not autowire its properties, but you can wire by yourself.
 * This class helps to find a context or create a new one, so you can wire properties inside objects that are not
 * created by Spring (e.g.: Servlets, usually created by the web server).
 *
 * Sometimes a SpringContext is created inside jUnit tests, or in the application server, or just manually. Independent
 * where it was created, I recommend you to configure your spring configuration to scan this SpringUtils package, so the 'springAppContext'
 * property will be used and autowired at the SpringUtils object the start of your spring context, and you will have just one instance of spring context public available.
 *
 *Ps: Even if your spring configuration doesn't include the SpringUtils @Component, it will works tto, but it will create a second Spring Context o your application.
 */
@Component
object SpringUtils {

        var springAppContext: ApplicationContext? = null
    @Autowired
    set(value) {
        field = value
    }



    /**
     * Tries to find and reuse the Application Spring Context. If none found, creates one and save for reuse.
     * @return returns a Spring Context.
     */
    fun ctx(): ApplicationContext {
        if (springAppContext!= null) {
            println("achou")
            return springAppContext as ApplicationContext;
        }

        //springcontext not autowired. Trying to find on the thread...
        val webContext = ContextLoader.getCurrentWebApplicationContext()
        if (webContext != null) {
            springAppContext = webContext;
            println("achou no servidor")
            return springAppContext as WebApplicationContext;
        }

        println("nao achou, vai criar")
        //None spring context found. Start creating a new one...
        val applicationContext = AnnotationConfigApplicationContext ( WebAppConfig::class.java )

        //saving the context for reusing next time
        springAppContext = applicationContext
        return applicationContext
    }

    /**
     * @return a Spring context of the WebApplication.
     * @param createNewWhenNotFound when true, creates a new Spring Context to return, when no one found in the ServletContext.
     * @param httpServlet the @WebServlet.
     */
    fun ctx(httpServlet: HttpServlet, createNewWhenNotFound: Boolean): ApplicationContext {
        try {
            val webContext = WebApplicationContextUtils.findWebApplicationContext(httpServlet.servletContext)
            if (webContext != null) {
                return webContext
            }
            if (createNewWhenNotFound) {
                //creates a new one
                return ctx()
            } else {
                throw NullPointerException("Cannot found a Spring Application Context.");
            }
        }catch (er: IllegalStateException){
            if (createNewWhenNotFound) {
                //creates a new one
                return ctx()
            }
            throw er;
        }
    }
}

现在,Spring上下文是公开的,能够调用方法独立于同一背景下的(JUnit测试,豆类,手动实例化类)喜欢上了这Java Servlet的:

@WebServlet(name = "MyWebHook", value = "/WebHook")
public class MyWebServlet extends HttpServlet {


    private MyBean byBean
            = SpringUtils.INSTANCE.ctx(this, true).getBean(MyBean.class);


    public MyWebServlet() {

    }
}


Answer 14:

在Spring bean的做自动装配如下:@Autowired私人的ApplicationContext appContext;

你会在ApplicationContext对象。



文章来源: Getting Spring Application Context