Spring中ApplicationContextAware如何工作?


82

在春季,如果实现了bean ApplicationContextAware,则它可以访问applicationContext。因此,它能够获得其他豆类。例如

public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;     

    public void setApplicationContext(ApplicationContext context) throws BeansException {
      applicationContext = context;
    }

    public static ApplicationContext getApplicationContext() {
      return applicationContext;
    }
}

然后SpringContextUtil.getApplicationContext.getBean("name")可以得到bean的“名称”。

要做到这一点,我们应该把这个SpringContextUtil里面的applications.xml,如

<bean class="com.util.SpringContextUtil" />

这里的beanSpringContextUtil不包含属性applicationContext。我想当spring bean初始化时,就设置了这个属性。但是,这是怎么做的呢?该方法如何setApplicationContext调用?


12
春天是魔术。拥抱魔法
rosenthal '16

Answers:


98

当spring实例化bean时,它会寻找几个接口,例如ApplicationContextAwareInitializingBean。如果找到它们,则将调用这些方法。例如(非常简化)

Class<?> beanClass = beanDefinition.getClass();
Object bean = beanClass.newInstance();
if (bean instanceof ApplicationContextAware) {
    ((ApplicationContextAware) bean).setApplicationContext(ctx);
}

请注意,在较新的版本中,使用注释可能比实现特定于Spring的接口更好。现在您可以简单地使用:

@Inject // or @Autowired
private ApplicationContext ctx;

4
非常感谢,这就是我想要的!也许我需要阅读一些Spring代码以了解Spring的工作原理。
吉米

2
在大多数情况下,最好使用@Autowired,但在其他情况下可能无法使用,例如,当您拥有“ @Component”为单例但需要注入具有会话作用域的bean时。由于在应用程序上下文创建中自动关联了依赖项,因此您实际上不会注入会话Bean,通过引用应用程序上下文,您可以以编程方式检索会话Bean,这将正确返回会话Bean实例。
raspacorp

我希望Spring会注入一个动态生成的代理类-这样的类具有应用程序作用域,但是在访问时,它委托给一个会话作用域实例,或者抛出异常,即没有任何请求绑定到当前运行的线程
xorcus

@raspacorp如果无法通过注入获得sesson范围bean ApplicationContext,则也不能从ApplicationContextAware instance其中之一获得它。因为ApplicationContextAware instance从与applicationContext注入的对象相同的对象中获取bean 。
蒂娜(Tiina)

10

Spring源代码解释
在使用ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
InAbstractApplicationContext类时ApplicationContextAware如何工作,该refresh()方法具有以下代码:

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

输入此方法,beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));将ApplicationContextAwareProcessor添加到AbstractrBeanFactory。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        beanFactory.setBeanClassLoader(getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
        // Configure the bean factory with context callbacks.
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
...........

当springAbstractAutowireCapableBeanFactory在方法中的中初始化bean时,initializeBean调用applyBeanPostProcessorsBeforeInitialization来实现bean的后期处理。该过程包括注入applicationContext。

@Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
            if (result == null) {
                return result;
            }
        }
        return result;
    }

当BeanPostProcessor实现Object来执行postProcessBeforeInitialization方法时,例如ApplicationContextAwareProcessor之前添加的方法。

private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
                        new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }


-1

ApplicationContextAware接口,当前的应用程序上下文,通过它可以调用spring容器服务。我们可以通过类中的以下方法获取当前的applicationContext实例

public void setApplicationContext(ApplicationContext context) throws BeansException.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.