有没有一种方法来静态/全球请求的副本送在弹簧的应用程序?

假设的主流的启动和初始化的应用程序方面,它需要通过下来通过呼叫叠的任何类需要,或是否有办法一类问以前创建的背景下?(我假设已经是一个单独的?)

有帮助吗?

解决方案

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

如果容器外的对象需要访问容器,我使用了标准GoF单例弹簧容器的图案。这样,你的应用程序中只有一个单例,其余的都是容器中的单例bean。

其他提示

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

public class SpringBean {
  @Autowired
  private ApplicationContext appContext;
}

SpringBean 会有 ApplicationContext 注,在这种豆是实例化。例如,如果你有网络应用程序非常标准的情况下分层结构:

main application context <- (child) MVC context

SpringBean 宣告内的主要方面,它将具有主要方面注射;否则,如果它声明的内视上下文中,它将视下文注射。

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

我使用过这种方法,但效果很好。基本上它是一个简单的bean,它包含对应用程序上下文的(静态)引用。通过在spring配置中引用它,它已初始化。

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

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

<bean id="mainContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
     <constructor-arg>
        <list>
            <value>../applicationContext.xml</value>
        </list>
     </constructor-arg>
 </bean>

从应用程序文本中获取bean的代码将是这样的:

BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
BeanFactoryReference bf = bfl.useBeanFactory("mainContext");
SomeService someService = (SomeService) bf.getFactory().getBean("someService");

Spring团队不鼓励使用这个课程和yadayada,但它在我使用它的地方非常适合我。

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

  • 我为什么想要得到的文?
  • 我有效地使用文作为一个服务定位器?
  • 我可以避免访问的文在吗?

这些问题的答案更容易在某些类型的应用程序(网络应用程序,例如)于他们在其他人,但值得一问。

访问的文不样的违反全依赖注射的原理,但有时候你已经没有太多的选择。

如果您使用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的上下文,假设它们已经以某种方式注册。

它不漂亮,比你想要的更复杂,但它确实有用。

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

  1. 测试运行并使用 @ContextConfiguration({&quot; classpath:foo.xml&quot;})进行注释。
  2. 测试B运行并使用 @ContextConfiguration({&quot; classpath:foo.xml&quot;,&quot; classpath:bar.xml})进行注释
  3. 测试C运行并使用 @ContextConfiguration({&quot; classpath:foo.xml&quot;})注释
  4. 当运行测试A时,会创建 ApplicationContext ,并且任何实现 ApplicationContextAware 或自动装配 ApplicationContext 的bean都可能会写入静态变量。 / p>

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

    当测试C运行时,没有创建bean ,因为测试A中的 TestContext (以及 ApplicationContext )被重用。现在你有一个静态变量指向另一个 ApplicationContext 而不是当前持有测试bean的那个。

有很多方法可以在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;
    }
    }
    
  2. 这里 setApplicationContext(ApplicationContext applicationContext)方法你将得到applicationContext

      

    <强>了ApplicationContextAware

         

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

    1. 通过自动装配

      @Autowired
      private ApplicationContext applicationContext;
      
    2. 此处 @Autowired 关键字将提供applicationContext。自动装配有一些问题。它会在单元测试期间产生问题。

不确定这会有多大用处,但您也可以在初始化应用时获取上下文。这是最快的,你甚至可以在 @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);

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

private static final ApplicationContext context = 
               new ClassPathXmlApplicationContext("beans.xml");

另请注意 beans.xml 应该是 src / main / resources 的一部分意味着在战争中它是 WEB_INF / classes 的一部分,实际应用程序将通过 Web.xml 中提到的 applicationContext.xml 加载。

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>META-INF/spring/applicationContext.xml</param-value>
</context-param>

很难提及 applicationContext.xml ClassPathXmlApplicationContext 构造函数中的路径。 ClassPathXmlApplicationContext(&quot; META-INF / spring / applicationContext.xml&quot;)将无法找到该文件。

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

@Component
public class OperatorRequestHandlerFactory {

    public static ApplicationContext context;

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

我知道这个问题已经得到解答,但我想分享我用来检索Spring Context的Kotlin代码。

我不是专家,因此我对评论家,评论和建议持开放态度:

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测试,bean,手动实例化类)调用相同的方法,就像在这个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() {

    }
}

在Spring bean中自动装配如下:   @Autowired   private ApplicationContext appContext;

你将是applicationcontext对象。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top