Getting Spring Application Context
Czy istnieje sposób statycznie / globalnie zażądać kopii ApplicationContext w aplikacji Spring?
Zakładając, że główna klasa uruchamia się i inicjalizuje kontekst aplikacji, czy musi przekazać go przez stos wywołań do klas, które go potrzebują, czy jest jakiś sposób, aby Klasa zapytała o wcześniej utworzony kontekst? (Który, jak zakładam, musi być singletonem?)
11 answers
Jeśli obiekt, który potrzebuje dostępu do kontenera jest bean w kontenerze, po prostu zaimplementuj interfejsy BeanFactoryAware lub ApplicationContextAware.
Jeśli obiekt poza kontenerem potrzebuje dostępu do kontenera, użyłem standardowego wzorca Singletona GoF dla kontenera spring. W ten sposób Masz tylko jeden singleton w aplikacji, reszta to fasola singleton w pojemniku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-30 21:22:58
Możesz zaimplementować ApplicationContextAware
lub po prostu użyć @Autowired
:
public class SpringBean {
@Autowired
private ApplicationContext appContext;
}
SpringBean
będzie miał ApplicationContext
wstrzyknięty, w którym ta fasola jest instancjowana. Na przykład, jeśli masz aplikację internetową z dość standardową hierarchią kontekstów:
main application context <- (child) MVC context
I SpringBean
jest zadeklarowane w głównym kontekście, będzie miał główny kontekst wstrzykiwany;
w przeciwnym razie, jeśli zostanie zadeklarowany w kontekście MVC, zostanie mu zaimplementowany kontekst MVC.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-14 11:31:02
Oto fajny sposób (nie mój, oryginał jest tutaj: http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html
Użyłem tego podejścia i działa dobrze. Zasadniczo jest to prosta fasola, która zawiera (statyczne) odniesienie do kontekstu aplikacji. Odwołując się do niego w Spring config jest inicjowany.
Spójrz na oryginalny ref, to bardzo jasne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-24 19:33:07
Wierzę, że możesz użyć SingletonBeanFactoryLocator . Fabryka fasoli.plik xml będzie zawierał rzeczywisty applicationContext, będzie wyglądał tak:
<bean id="mainContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>../applicationContext.xml</value>
</list>
</constructor-arg>
</bean>
I kod do pobrania fasolki z applicationkontekstu skąd by było coś takiego:
BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
BeanFactoryReference bf = bfl.useBeanFactory("mainContext");
SomeService someService = (SomeService) bf.getFactory().getBean("someService");
[2]} drużyna Wiosenna nie chce korzystać z tej klasy i yadayada, ale dobrze mi się tam, gdzie jej używałem.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-27 12:56:34
Zanim wdrożysz jakiekolwiek inne sugestie, zadaj sobie te pytania...
- Dlaczego próbuję pobrać ApplicationContext?
- czy skutecznie używam ApplicationContext jako lokalizatora usług?
- Czy Mogę w ogóle uniknąć dostępu do ApplicationContext?
Odpowiedzi na te pytania są łatwiejsze w niektórych rodzajach aplikacji (na przykład aplikacje internetowe) niż w innych, ale i tak warto je zadać.
Dostęp do ApplicationContext w pewnym sensie narusza całą zasadę iniekcji zależności, ale czasami nie masz dużego wyboru.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-27 08:28:19
Jeśli używasz aplikacji webowej, istnieje również inny sposób dostępu do kontekstu aplikacji bez użycia singletonów za pomocą filtra servletfilter i ThreadLocal. W filtrze można uzyskać dostęp do kontekstu aplikacji za pomocą Webaplicationcontextutils i zapisać albo kontekst aplikacji lub potrzebne fasolki w TheadLocal.
Uwaga: jeśli zapomnisz odłączyć ThreadLocal, pojawią się nieprzyjemne problemy podczas próby cofnięcia aplikacji! Dlatego należy go ustawić i natychmiast rozpocząć próba, która unsets ThreadLocal w końcu-część.
Oczywiście nadal używa singletonu: ThreadLocal. Ale rzeczywista fasola nie musi już być. Może być nawet request-scoped, a to rozwiązanie działa również, jeśli masz wiele wojen w aplikacji z libariami w uchu. Mimo to możesz uznać to użycie ThreadLocal za złe, jak użycie zwykłych singletonów. ;-)
Może już wiosna daje podobne rozwiązanie? Nie znalazłem, ale nie wiem na pewno.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-31 14:32:49
Spójrz na ContextSingletonBeanFactoryLocator . Zapewnia statyczne Accesory, aby uchwycić konteksty Springa, zakładając, że zostały zarejestrowane w określony sposób.
To nie jest ładne, i bardziej skomplikowane niż może chcesz, ale to działa.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-22 23:01:24
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);
}
}
Źródło: http://sujitpal.blogspot.de/2007/03/accessing-spring-beans-from-legacy-code.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-21 08:16:24
Zauważ, że przechowując dowolny stan z bieżącego ApplicationContext
lub samego ApplicationContext
W Zmiennej statycznej - na przykład używając wzoru Singletona - sprawisz, że twoje testy będą niestabilne i nieprzewidywalne, jeśli używasz Spring-test. Dzieje się tak, ponieważ Spring-test buforuje i ponownie wykorzystuje konteksty aplikacji w tym samym JVM. Na przykład:
- Przetestuj bieg i jest on opatrzony adnotacją
@ContextConfiguration({"classpath:foo.xml"})
. - Test B Uruchom i jest opatrzony adnotacją
@ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
- Test C Uruchom i jest on opatrzony adnotacją
@ContextConfiguration({"classpath:foo.xml"})
Po uruchomieniu Test a, tworzony jest ApplicationContext
, a Dowolna implementacja beans ApplicationContextAware
lub autowiringowanie ApplicationContext
może zapisać do zmiennej statycznej.
Gdy Test B uruchamia się to samo, a zmienna statyczna wskazuje teraz na Test b ApplicationContext
Po uruchomieniu testu C, nie są tworzone , ponieważ TestContext
(i tutaj ApplicationContext
) z testu A jest ponownie używany. Teraz masz zmienną statyczną wskazującą na inną ApplicationContext
niż ta, która aktualnie trzyma fasolę dla Twojego test.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-20 11:52:18
Proszę zauważyć, że poniższy kod utworzy nowy kontekst aplikacji zamiast użycia już załadowanego.
private static final ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
Należy również zauważyć, że beans.xml
powinna być częścią src/main/resources
oznacza to, że w wojnie jest częścią WEB_INF/classes
, gdzie jako prawdziwa aplikacja zostanie załadowana przez applicationContext.xml
wymienione w Web.xml
.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>META-INF/spring/applicationContext.xml</param-value>
</context-param>
Jest trudno wspomnieć applicationContext.xml
ścieżkę w konstruktorze ClassPathXmlApplicationContext
. ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml")
nie będzie w stanie zlokalizować pliku.
Więc lepiej jest użyć istniejącego applicationContext przez używanie adnotacji.
@Component
public class OperatorRequestHandlerFactory {
public static ApplicationContext context;
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
context = applicationContext;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:16
Wiem, że to pytanie jest odpowiedzią, ale chciałbym podzielić się kodem Kotlina, który zrobiłem, aby odzyskać kontekst Wiosny.
Nie jestem specjalistą, więc jestem otwarty na krytykę, recenzje i porady:]}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;
}
}
}
Teraz publicznie dostępny jest kontekst spring, który może wywoływać tę samą metodę niezależnie od kontekstu (junit tests, beans, manually instantiated classes), jak w tej Javie Servlet:
@WebServlet(name = "MyWebHook", value = "/WebHook")
public class MyWebServlet extends HttpServlet {
private MyBean byBean
= SpringUtils.INSTANCE.ctx(this, true).getBean(MyBean.class);
public MyWebServlet() {
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-27 12:49:10