Frage

Gibt es eine Möglichkeit zu statisch global / eine Kopie des Application in einer Feder Anwendung anfordern?

Unter der Annahme, die Hauptklasse startet und initialisiert den Anwendungskontext, braucht es, dass auf alle Klassen durch den Call-Stack zu überliefern, die es brauchen, oder gibt es eine Möglichkeit für eine Klasse für den zuvor erstellten Kontext zu stellen? (Was ich davon ausgehen, hat ein Singleton sein?)

War es hilfreich?

Lösung

Wenn das Objekt, das den Zugriff auf den Behälter braucht, ist eine Bohne in den Behälter, implementieren nur die beanFactoryAware oder ApplicationContextAware Schnittstellen.

Wenn ein Objekt außerhalb des Behälters Zugang zum Behälter muss, habe ich eine Standard GoF Singletons verwendet Muster für den Federbehälter. Auf diese Weise nur in Ihrer Anwendung einen Singleton hat, der Rest ist alle Singletons Bohnen im Behälter.

Andere Tipps

Sie können ApplicationContextAware implementieren oder nur @Autowired verwenden:

public class SpringBean {
  @Autowired
  private ApplicationContext appContext;
}

SpringBean haben wird ApplicationContext injiziert, in dem dieser Bean instanziiert wird. Wenn Sie zum Beispiel Web-Anwendung haben mit einer ziemlich Standard Kontexten Hierarchie:

main application context <- (child) MVC context

und SpringBean innerhalb Haupt Zusammenhang erklärt, wird es Haupt Kontext injiziert haben; andernfalls, wenn sie innerhalb von MVC Kontext erklärt ist, wird es MVC Kontext injiziert haben.

Hier ist eine nette Art und Weise (nicht von mir, die ursprünglichen Bezugnahme hier: http://sujitpal.blogspot.com/2007 /03/accessing-spring-beans-from-legacy-code.html

Ich habe diesen Ansatz verwendet, und es funktioniert gut. Im Grunde ist es eine einfache Bean, die einen (statischen) Verweis auf den Anwendungskontext enthält. Durch Bezugnahme auf sie im Frühjahr Config wird es initialisiert.

Werfen Sie einen Blick auf dem Original-ref, es ist sehr klar.

Ich glaube, Sie SingletonBeanFactoryLocator . Die beanRefFactory.xml Datei würde die tatsächliche halte application, Es wäre so etwas wie dies geht:

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

Und der Code eine Bohne aus der Application von zu bekommen, wo immer etwas so sein würde:

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

Der Frühling Team die Verwendung dieser Klasse entmutigen und yadayada, aber es hat mir gut geeignet, wo ich es benutzt haben.

Bevor Sie eine der anderen Vorschläge umzusetzen, stellen Sie sich diese Fragen ...

  • Warum versuche ich, die Application zu bekommen?
  • Bin ich effektiv die Application als Service-Locator mit?
  • Kann ich das Applicationüberhaupt vermeiden zugreifen?

Die Antworten auf diese Fragen sind leichter in bestimmte Arten von Anwendungen (Web-Anwendungen, zum Beispiel), als sie in anderen sind, aber lohnt sich zu fragen sowieso.

Zugriff auf die Application nicht Art verletzen die ganze Dependency Injection Prinzip, aber manchmal hast du nicht bekommen viel Auswahl.

Wenn Sie einen Web-App verwenden, gibt es auch eine andere Möglichkeit, den Anwendungskontext zuzugreifen, ohne Singletons mit durch einen ServletFilter und einen Thread verwenden. Im Filter können Sie den Anwendungskontext zugreifen WebApplicationContextUtils und speichern entweder den Anwendungskontext oder die benötigten Bohnen im TheadLocal verwenden.

Achtung: Wenn Sie den Thread unset vergessen, werden Sie böse Probleme bekommen, wenn sie versuchen, die Anwendung zu deimplementieren! Daher sollten Sie es eingestellt und sofort einen Versuch starten, die den Thread im finally-Teil führt zum Löschen.

Natürlich wird in diesem nach wie vor einen Singleton: der Thread. Aber die eigentlichen Bohnen brauchen nicht mehr zu sein. Das kann auch sein Wunsch-scoped, und diese Lösung funktioniert auch, wenn Sie mehrere WARs in einer Anwendung mit den libaries in der EAR haben. Dennoch können Sie diese Verwendung von Thread so schlecht, wie die Verwendung von Normal Singletons betrachten. ; -)

Vielleicht Frühling bietet bereits eine ähnliche Lösung? Ich habe nicht finden, aber ich weiß nicht genau.

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);
  }
}

Quelle: http: // sujitpal. blogspot.de/2007/03/accessing-spring-beans-from-legacy-code.html

Werfen Sie einen Blick auf ContextSingletonBeanFactoryLocator . Es bietet statische Accessoren halten Spring Kontexte zu bekommen, sie in gewisser Weise registriert wurden unter der Annahme.

Es ist nicht schön, und komplexer als vielleicht möchten Sie, aber es funktioniert.

Beachten Sie, dass durch den Zustand aus dem aktuellen ApplicationContext speichern, oder den ApplicationContext selbst in einem statischen Variablen - zum Beispiel des Singletonmuster mit - Sie werden Ihre Tests instabil und unberechenbar machen, wenn Sie Frühlings-Test verwenden. Dies liegt daran, Frühlings-Test-Caches und wieder verwendet Anwendungskontexte in der gleichen JVM. Zum Beispiel:

  1. Ein Run Test und es ist mit @ContextConfiguration({"classpath:foo.xml"}) kommentiert.
  2. Test B laufen und es wird mit Anmerkungen versehen mit @ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
  3. Test C laufen und es wird mit Anmerkungen versehen mit @ContextConfiguration({"classpath:foo.xml"})

Wenn Test A ausgeführt wird, wird ein ApplicationContext erstellt und alle Bohnen implemeting ApplicationContextAware oder autowiring ApplicationContext auf die statische Variable schreiben könnte.

Wenn Test B läuft das gleiche passiert, und die statische Variable zeigt jetzt B ApplicationContext

Test

Wenn Test C läuft, keine Bohnen erstellt als die TestContext (und hier die ApplicationContext) von Test A resused werden. Jetzt haben Sie auf eine statische Variable zeigt auf eine andere ApplicationContext als die derzeit die Bohnen für den Test zu halten.

Es gibt viele Wege Anwendungskontext im Frühjahr Anwendung zu bekommen. Diese sind unten angegeben:

  1. Via 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;
    }
    }
    

Hier setApplicationContext(ApplicationContext applicationContext) Methode werden Sie die application bekommen

  

ApplicationContextAware :

     

Schnittstelle von jedem Objekt implementiert werden, die benachrichtigt werden möchte   der Application, dass es läuft in. Die Implementierung dieser Schnittstelle   macht Sinn, zum Beispiel, wenn ein Objekt Zugriff auf einen Satz erfordert von   zusammen Bohnen.

  1. Via Autowired :

    @Autowired
    private ApplicationContext applicationContext;
    

Hier @Autowired Schlüsselwort wird die application bieten. Autowired hat ein Problem. Es wird erstellen Problem während Komponententests.

Nicht sicher, wie nützlich diese sein wird, aber Sie können auch den Kontext erhalten, wenn Sie die App initialisieren. Dies ist die am ehesten Sie den Kontext bekommen, noch bevor ein @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);

Bitte beachten Sie, dass; der folgende Code wird neuen Anwendungskontext erstellen, anstatt die bereits geladen eine zu verwenden.

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

Beachten Sie auch, dass beans.xml sollte es Teil src/main/resources bedeutet im Krieg Teil WEB_INF/classes ist, wo, wie die reale Anwendung durch applicationContext.xml bei Web.xml erwähnt geladen werden.

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

Es ist schwierig applicationContext.xml Pfad in ClassPathXmlApplicationContext Konstruktor zu erwähnen. ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml") nicht in der Lage sein, um die Datei zu suchen.

So ist es besser, bestehende application verwenden, indem Sie Anmerkungen verwenden.

@Component
public class OperatorRequestHandlerFactory {

    public static ApplicationContext context;

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

Ich weiß, diese Frage beantwortet wird, aber ich möchte den Kotlin Code teilen ich den Frühling Kontext abzurufen tat.

Ich bin kein Spezialist, so dass ich bin offen für Kritik, Bewertungen und Hinweise:

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;
        }
    }
}

Nun ist eine Feder Kontext öffentlich zugänglich, die Möglichkeit, die gleiche Methode unabhängig vom Kontext zu nennen (JUnit-Tests, Bohnen, manuell instanziiert Klassen) wie auf dieser 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() {

    }
}

Sie autowire in Spring-Bean als unten:   @Autowired   Private Application appContext;

Sie werden das Application Objekt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top