有没有一种在Spring应用程序中静态/全局请求ApplicationContext副本的方法?
假设主类启动并初始化应用程序上下文,是否需要将其通过调用堆栈传递到需要它的任何类中,还是有一种方法可供类请求先前创建的上下文? (我认为必须是单例模式?)
有没有一种在Spring应用程序中静态/全局请求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);
我使用一种简单标准的方法来允许外部访问我的任何单例Spring Bean。通过这种方法,我继续让Spring实例化Bean。 我的做法如下:
this
。如果该类没有构造函数,则添加一个默认构造函数以设置该变量。以下是示例:
@Component
public class MyBean {
...
private static MyBean singleton = null;
public MyBean() {
...
singleton = this;
}
...
public void someMethod() {
...
}
...
public static MyBean get() {
return singleton;
}
}
我可以通过以下方式在我的代码中的任何地方调用单例bean上的someMethod
:
MyBean.get().someMethod();
ApplicationContext
,您可以直接将此机制添加到其中。否则,您可以仅为此目的而对其进行子类化,或者将此机制添加到任何具有访问ApplicationContext
权限的bean中,然后使用它从任何地方访问ApplicationContext
。重要的是,正是这种机制让您进入了Spring环境。Do autowire in Spring bean as below:
@Autowired
private ApplicationContext appContext;
ApplicationContext
对象。方法一:您可以通过实现ApplicationContextAware接口来注入ApplicationContext。参考link。
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private ApplicationContext applicationContext;
public ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
方法二:在任何由Spring管理的bean中自动装配应用程序上下文。
@Component
public class SpringBean {
@Autowired
private ApplicationContext appContext;
}
参考 链接。
我知道这个问题已经有答案了,但我想分享一下我编写的用于检索Spring上下文的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;
}
}
}
@WebServlet(name = "MyWebHook", value = "/WebHook")
public class MyWebServlet extends HttpServlet {
private MyBean byBean
= SpringUtils.INSTANCE.ctx(this, true).getBean(MyBean.class);
public MyWebServlet() {
}
}
private static final ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
beans.xml
应该是 src/main/resources
的一部分,这意味着在 war 包中它应该是 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>
在ClassPathXmlApplicationContext
构造函数中提及applicationContext.xml
路径是困难的。 ClassPathXmlApplicationContext(“META-INF / spring / applicationContext.xml”)
将无法定位该文件。
因此,最好使用注释来使用现有的applicationContext
。
@Component
public class OperatorRequestHandlerFactory {
public static ApplicationContext context;
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
context = applicationContext;
}
}
@Component
public class SpringContext implements ApplicationContextAware{
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws
BeansException {
this.applicationContext=applicationContext;
}
}
然后,您可以根据需要在同一类中实现一个getter方法,例如通过以下方式获取已实现的类引用:
applicationContext.getBean(String serviceName,Interface.Class)
ApplicationContextAware
单例有一个优点,就是将遗留映射隔离到一个单一的点上,一旦迁移完成(经过X年之后..),它可以很容易地被移除掉。 - undefined