Spring获取当前ApplicationContext

130

我正在使用Spring MVC框架开发我的Web应用程序。我的bean是在"spring-servlet.xml"文件中编写的。

现在我有一个名为MyClass的类,我想使用Spring Bean来访问这个类。

spring-servlet.xml文件中,我已经编写了以下内容:

TBD

<bean id="myClass" class="com.lynas.MyClass" />

现在我需要使用 ApplicationContext 来访问它。

ApplicationContext context = ??

以便我能够做到

MyClass myClass = (MyClass) context.getBean("myClass");

如何做到这一点??


3
@Autowired MyClass myClass应该能胜任这个工作! - Mannekenpix
12个回答

189

简单地注入它...

@Autowired
private ApplicationContext appContext;

或者实现这个接口:ApplicationContextAware


也许这个可以工作:https://dev59.com/RmbWa4cB1Zd3GeqPYZlM - gipinani
1
以下 ApplicationContextProvider.java 的答案似乎是最可靠的解决方案。 - Ionut
5
每次返回的都是NULL。需要注意的是,我正在一个普通类中执行此操作,该类既不是"@RestController"也不是"@Component"。 - zulkarnain shah
1
根据Spring文档,最好避免使用@Autowired,因为存在一些问题。这是链接https://spring.io/understanding/application-context。最好的选择是实现ApplicationContextAware接口。 - Durja
3
我不确定这个回答是否能解决问题。在Spring无法管理的对象中,你无法自动装配应用程序上下文。 - TriCore

112

我认为这个 链接 展示了获取应用上下文的最佳方法,即使在非bean类中也可以。我觉得这非常有用。希望你也这样认为。以下是它的抽象代码:

创建一个新的类ApplicationContextProvider.java

package com.java2novice.spring;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class ApplicationContextProvider implements ApplicationContextAware{

    private static ApplicationContext context;

    public static ApplicationContext getApplicationContext() {
        return context;
    }

    @Override
    public void setApplicationContext(ApplicationContext ac)
            throws BeansException {
        context = ac;
    }
}

在application-context.xml中添加一个条目

<bean id="applicationContextProvider"
                        class="com.java2novice.spring.ApplicationContextProvider"/>

在注释的情况下(而不是application-context.xml文件)

@Component
public class ApplicationContextProvider implements ApplicationContextAware{
...
}

像这样获取上下文

TestBean tb = ApplicationContextProvider.getApplicationContext().getBean("testBean", TestBean.class);

干杯!!


2
我编写的代码与Vivek类似。但我避免了每次需要从上下文调用getBean()时都创建一个新的ApplicationContextProvider()。我所做的是拥有 静态ApplicationContextProvider.getApplicationContext() 方法。然后,当需要当前应用程序上下文时,我调用: ApplicationContextProvider appContext = ApplicationContextProvider.getApplicationContext() - Panini Luncher
1
是的,Panini Luncher,那仍然不错。根据您的建议,我会这样更改。 :) - Vivek
4
ApplicationContextProvider 上添加 @Component 注解可以避免在 aplication-context.xml 中进行配置。 - bluearrow
1
注意:上下文的getter和setter应该被同步。这将避免很多头疼,特别是在单元/集成测试中。在我的情况下,类似的ApplicationContextProvider保存了旧的上下文(从以前的集成测试),引起了很多棘手的错误。 - Oleksandr_DJ

54

如果您需要从未由Spring实例化的HttpServlet中访问上下文(因此@Autowire和ApplicationContextAware都无法工作)...

WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

或者
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);

关于其他回复,在你这样做之前三思:

new ClassPathXmlApplicationContext("..."); // are you sure?

由于这样做并不能为您提供当前上下文,而是为您创建另一个上下文实例。这意味着1)占用了大量的内存,2)这两个应用程序上下文之间不共享bean。


SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this) - 在Liferay门户动作过滤器的init()方法中,这个方法为我完成了工作。 - Igor Baiborodine
太棒了,processInjectionBasedOnCurrentContext函数完成了我需要做的所有工作。非常感谢@Jaroslav。 - Jad B.
ApplicationContextAware在我这里是有效的,当它使用@Component注解时,就像Vivek的解决方案中一样(我通过扩展AbstractContextLoaderInitializer / createRootApplicationContext手动初始化Spring上下文)。 - hello_earth
请注意... SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); 不会立即执行,因此您不能将其用作构造函数中的第一行。 - SledgeHammer
这在传统的Java Web应用程序中完美运行(非Spring-MVC管理)。 - lainatnavi
在我的类中应该在哪里调用SpringBeanAutowiringSupport?SledgeHammer说“不要在构造函数的第一行”...那么在哪里呢? - Alex Worden

35
如果你正在实现一个不由Spring实例化的类,比如JsonDeserializer,你可以使用:
WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
MyClass myBean = context.getBean(MyClass.class);

12
对我来说它不起作用。我的类已经超出了Spring上下文。我尝试使用你的代码,但它给我一个null作为响应。我在谈论ContextLoader.getCurrentWebApplicationContext() - R. Karlus

10

将此添加到您的代码中

@Autowired
private ApplicationContext _applicationContext;

//Add below line in your calling method
MyClass class = (MyClass) _applicationContext.getBean("myClass");

// Or you can simply use this, put the below code in your controller data member declaration part.
@Autowired
private MyClass myClass;

这将简单地将myClass注入到您的应用程序中


8
基于Vivek的回答,但我认为以下会更好:
@Component("applicationContextProvider")
public class ApplicationContextProvider implements ApplicationContextAware {

    private static class AplicationContextHolder{

        private static final InnerContextResource CONTEXT_PROV = new InnerContextResource();

        private AplicationContextHolder() {
            super();
        }
    }

    private static final class InnerContextResource {

        private ApplicationContext context;

        private InnerContextResource(){
            super();
        }

        private void setContext(ApplicationContext context){
            this.context = context;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return AplicationContextHolder.CONTEXT_PROV.context;
    }

    @Override
    public void setApplicationContext(ApplicationContext ac) {
        AplicationContextHolder.CONTEXT_PROV.setContext(ac);
    }
}

从实例方法向静态字段写入是一种不好的做法,如果正在操纵多个实例,则会很危险。

有一个名为org.springframework.core.io.ContextResource的接口。我建议选择不同的名称来命名内部类ContextResource,以避免混淆。 - Alexander Radchenko
@AlexanderRadchenko 好的,我已将其更改为InnerContextResource。 - Juan

1

在Spring应用程序中,有许多获取应用程序上下文的方法。以下是这些方法:

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

在这个 setApplicationContext(ApplicationContext applicationContext) 方法中,您将获得应用程序上下文。

  1. Via Autowired:

    @Autowired
    private ApplicationContext applicationContext;
    

这里的@Autowired关键字将提供applicationContext。

更多信息请访问this thread

谢谢 :)


1
即使添加了@Autowire,如果您的类不是RestController或Configuration类,则applicationContext对象仍为null。尝试创建以下新类,它可以正常工作:
@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)

0

步骤1:在类中注入以下代码

@Autowired
private ApplicationContext _applicationContext;

步骤2:编写Getter和Setter

步骤3:在定义bean的xml文件中定义autowire="byType"


0

另一种方法是通过servlet注入applicationContext。

这是在使用Spring Web服务时注入依赖项的示例。

<servlet>
        <servlet-name>my-soap-ws</servlet-name>
        <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
        <init-param>
            <param-name>transformWsdlLocations</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:my-applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>5</load-on-startup>

</servlet>

另一种方法是在你的 web.xml 文件中添加应用程序上下文,如下所示

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/classes/my-another-applicationContext.xml
        classpath:my-second-context.xml
    </param-value>
</context-param>

基本上,您正在尝试告诉servlet它应该查找在这些上下文文件中定义的bean。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接