문제

는 방법이 있을 정적으로/전 세계적으로 요청의 사본 ApplicationContext 에서 봄 응용 프로그램?

고 가정하고 기본 클래스를 시작하고 응용 프로그램을 초기화 컨텍스트,그것을 통과해야는 아래를 통해 호출 스택을 모는 클래스를,그것을 필요로하는 방법이 있는 클래스를 요청 이전에 만든다.(나는 가정을 수 있 싱글?)

도움이 되었습니까?

해결책

컨테이너에 접근 해야하는 물체가 컨테이너의 콩이라면 beanfactoryaware 또는 ApplicationContextAware 인터페이스.

컨테이너 외부의 물체가 컨테이너에 액세스 해야하는 경우 표준 GOF 싱글 톤 패턴 스프링 컨테이너 용. 이렇게하면 응용 프로그램에 싱글 톤이 하나뿐입니다. 나머지는 모두 컨테이너의 싱글 톤 콩입니다.

다른 팁

당신은 구현할 수 있습니다 ApplicationContextAware 또는 그냥 사용하십시오 @Autowired:

public class SpringBean {
  @Autowired
  private ApplicationContext appContext;
}

SpringBean 가질 것이다 ApplicationContext 이 콩이 인스턴스화되는 주입. 예를 들어, 표준 컨텍스트 계층이있는 웹 응용 프로그램이있는 경우 :

main application context <- (child) MVC context

그리고 SpringBean 주요 맥락에서 선언되면 주요 상황이 주입됩니다. 그렇지 않으면 MVC 컨텍스트 내에서 선언 된 경우 MVC 컨텍스트가 주입됩니다.

다음은 좋은 방법입니다 (내 것이 아니라 원래 참조는 여기에 있습니다.http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html

나는이 접근법을 사용했고 잘 작동합니다. 기본적으로 응용 프로그램 컨텍스트에 대한 (정적) 참조를 보유하는 간단한 콩입니다. 스프링 구성에서 참조하여 초기화되었습니다.

원래 심판을 살펴보십시오. 매우 분명합니다.

나는 당신이 사용할 수 있다고 생각합니다 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");

봄 팀은이 클래스와 Yadayada의 사용을 방해하지만, 내가 그것을 사용한 곳에 나에게 적합했습니다.

다른 제안을 구현하기 전에이 질문을 스스로에게 물어보십시오 ...

  • ApplicationContext를 얻으려고하는 이유는 무엇입니까?
  • ApplicationContext를 서비스 로케이터로 효과적으로 사용하고 있습니까?
  • ApplicationContext에 전혀 액세스를 피할 수 있습니까?

이러한 질문에 대한 답변은 특정 유형의 응용 프로그램 (예 : 웹 앱)에서 다른 질문보다 쉽지만 어쨌든 물어볼 가치가 있습니다.

ApplicationContext에 액세스하면 전체 종속성 주입 원칙을 위반하지만 때로는 선택이 많지 않습니다.

를 사용하는 경우 웹사-응용 프로그램이하는 또 다른 방법에 액세스 응용 프로그램 컨텍스트를 사용하지 않고 싱글이 사용하여 servletfilter 및 ThreadLocal.필터에 액세스할 수 있는 응용 프로그램 컨텍스트를 사용하여 WebApplicationContextUtils 및 저장소 중 하나 응용 프로그램 또는 컨텍스트에 필요한 콩 TheadLocal.

주의:하는 것을 잊어버리면 설정 해제 ThreadLocal 당신을 얻을 것이다 불쾌한려고 할 때 문제가 배포를 취소하려면 응용 프로그램!따라서,설정해야 합니다 그것은 즉시 시작하려고 하는 unsets 의 ThreadLocal 에서 마지막으로 부분입니다.

물론,이것은 여전히 사용하는 단일:이 ThreadLocal.하지만 실제 콩 필요하지 않습니다.수도 요청의 범위,그리고 이 솔루션은 또한 작품이 여러 개 있는 경우의 전쟁에서 사용하여 응용 프로그램 libaries 에서 귀.여전히,당신은 고려할 수 있습니다 이의 사용 ThreadLocal 로 나쁜 사용의 일반 singleton.;-)

아마도 봄 이미 제공한 유사 솔루션?내가 찾지 못한 하나,하지만 나는지 확실히 알 수 있습니다.

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

보세요 ContextingletonBeanFactoryLocator. 그것은 특정 방식으로 등록되었다고 가정 할 때 Spring의 맥락을 유지하기 위해 정적 액세서를 제공합니다.

그것은 당신이 원하는 것보다 예쁘지 않고 더 복잡하지는 않지만 작동합니다.

현재로부터 모든 상태를 저장함으로써 ApplicationContext, 아니면 그 ApplicationContext 스프링 테스트를 사용하는 경우 테스트를 불안정하고 예측할 수없는 정적 변수 자체입니다. 이는 스프링 테스트가 동일한 JVM에서 응용 프로그램 컨텍스트를 캐시하고 재사용하기 때문입니다. 예를 들어:

  1. 달리기를 테스트하면 주석이 달라집니다 @ContextConfiguration({"classpath:foo.xml"}).
  2. Test B가 실행되면 주석이 달라집니다 @ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
  3. 테스트 C 실행과 함께 주석이 달라집니다 @ContextConfiguration({"classpath:foo.xml"})

실행을 테스트 할 때 ApplicationContext 생성되고 콩이 구현됩니다 ApplicationContextAware 또는 Autowiring ApplicationContext 정적 변수에 쓸 수 있습니다.

테스트 B가 동일한 일이 발생하면 정적 변수가 이제 B의 테스트를 가리 킵니다. ApplicationContext

테스트 C가 실행되면 콩이 만들어지지 않습니다 로서 TestContext (여기서 ApplicationContext) 테스트에서 A가 보였다. 이제 당신은 다른 사람을 가리키는 정적 변수를 얻었습니다 ApplicationContext 현재 테스트를 위해 콩을 들고있는 것보다.

스프링 응용 프로그램에서 응용 프로그램 컨텍스트를 얻는 방법에는 여러 가지가 있습니다. 그것들은 벨로우어가 주어집니다 :

  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에는 문제가 있습니다. 단위 테스트 중에 문제가 발생합니다.

이것이 얼마나 유용한 지 확실하지 않지만 앱을 초기화 할 때 컨텍스트를 얻을 수도 있습니다. 이것은 이전에도 컨텍스트를 얻을 수있는 가장 빨리 @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, 실제 응용 프로그램이로드되는 곳 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;
    }
}

이 질문에 대한 답변이 있다는 것을 알고 있지만 스프링 컨텍스트를 검색하기 위해 한 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;
        }
    }
}

이제 스프링 컨텍스트가 공개적으로 이용 가능하며,이 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() {

    }
}

다음과 같이 스프링 빈에서 Autowire를 수행하십시오.

ApplicationContext 객체가됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top