ApplicationContextAware接口

来源:互联网 发布:电路分析软件 编辑:程序博客网 时间:2024/06/07 09:43

前言

部分情况下我们想在一个new出来的对象里获得spring容器管理的bean对象,但是因为该类不是由spring对象创建出来的,所以该对象的域不会被spring通过依赖注入的方式实例话,意味着如果我们还向之前那么使用实例属性的话,那就等着空指针吧。那么我们如果在自己new出来的对象里,想使用Spring的bean(例如mybatis相关mapper)该怎么办呢?搜遍互联网,大家会告诉你有一个ApplicationContextAware 的东西,你可以在spring管理的bean里面拿到applicationContext,那么曲线救国的情况下,就会有如下这样的一个工具类
有的时候在spring的管理下,实现一些基于设计模式的想法会有些讨厌
SpringContextUtils.class

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package 保密;import java.util.Map;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;public class SpringContextUtils implements ApplicationContextAware {    private static ApplicationContext applicationContext;    public SpringContextUtils() {    }    public void setApplicationContext(ApplicationContext arg0) throws BeansException {        applicationContext = arg0;    }    public static ApplicationContext getApplicationContext() {        return applicationContext;    }    public static Object getBeanById(String id) {        return applicationContext.getBean(id);    }    public static Object getBeanByClass(Class c) {        return applicationContext.getBean(c);    }    public static Map getBeansByClass(Class c) {        return applicationContext.getBeansOfType(c);    }}

把这个类纳入到spring的管理下,我们就可以通过SpringContextUtils.getBeanById(beanName)的方式拿到具体需要使用的bean实例了。
但是这个功能是怎么实现的嘞,为什么通过实现org.springframework.context.ApplicationContextAware就能拿到ApplicationContext呢?那就只能打开源码看看了。带着疑问打开该接口,看看文档注释。
org.springframework.context.ApplicationContextAware

/** * Interface to be implemented by any object that wishes to be notified * of the {@link ApplicationContext} that it runs in. * * <p>Implementing this interface makes sense for example when an object * requires access to a set of collaborating beans. Note that configuration * via bean references is preferable to implementing this interface just * for bean lookup purposes. * * <p>This interface can also be implemented if an object needs access to file * resources, i.e. wants to call {@code getResource}, wants to publish * an application event, or requires access to the MessageSource. However, * it is preferable to implement the more specific {@link ResourceLoaderAware}, * {@link ApplicationEventPublisherAware} or {@link MessageSourceAware} interface * in such a specific scenario. * * <p>Note that file resource dependencies can also be exposed as bean properties * of type {@link org.springframework.core.io.Resource}, populated via Strings * with automatic type conversion by the bean factory. This removes the need * for implementing any callback interface just for the purpose of accessing * a specific file resource. * * <p>{@link org.springframework.context.support.ApplicationObjectSupport} is a * convenience base class for application objects, implementing this interface. * * <p>For a list of all bean lifecycle methods, see the * {@link org.springframework.beans.factory.BeanFactory BeanFactory javadocs}. * * @author Rod Johnson * @author Juergen Hoeller * @author Chris Beams * @see ResourceLoaderAware * @see ApplicationEventPublisherAware * @see MessageSourceAware * @see org.springframework.context.support.ApplicationObjectSupport * @see org.springframework.beans.factory.BeanFactoryAware */public interface ApplicationContextAware extends Aware {    /**     * Set the ApplicationContext that this object runs in.     * Normally this call will be used to initialize the object.     * <p>Invoked after population of normal bean properties but before an init callback such     * as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}     * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},     * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and     * {@link MessageSourceAware}, if applicable.     * @param applicationContext the ApplicationContext object to be used by this object     * @throws ApplicationContextException in case of context initialization errors     * @throws BeansException if thrown by application context methods     * @see org.springframework.beans.factory.BeanInitializationException     */    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;}

英文略渣

Interface to be implemented by any object that wishes to be notified of the {@link ApplicationContext} that it runs in.”
任何想要在ApplicationContext运行时得到通知的对象,都可以实现这个接口。

在哪调用这个接口void setApplicationContext(ApplicationContext applicationContext) throws BeansException;的呢?ctrl+alt+h
这里写图片描述
除了duboo和自己的类中会用到,剩下的只有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(this.embeddedValueResolver);            }            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);            }        }    }

可见会根据几种aware调用不同的类的不同方法,那么调用invokeAwareInterfaces(Object bean)又是谁?

@Override    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {        AccessControlContext acc = null;        if (System.getSecurityManager() != null &&                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {            acc = this.applicationContext.getBeanFactory().getAccessControlContext();        }        if (acc != null) {            AccessController.doPrivileged(new PrivilegedAction<Object>() {                @Override                public Object run() {                    invokeAwareInterfaces(bean);//看这里                    return null;                }            }, acc);        }        else {            invokeAwareInterfaces(bean);//看这里        }        return bean;    }

等等。postProcessBeforeInitialization(final Object bean, String beanName)这个方法名字好熟悉啊,既然有@Override 注解,我们看看他继承的类或是实现的接口是谁。

class ApplicationContextAwareProcessor implements BeanPostProcessor 

这个类实现了一个org.springframework.beans.factory.config.BeanPostProcessor至于这个接口是做什么的,那就先不去详细表了。他是下边这个用途。

BeanPostProcessor接口作用是:如果我们需要在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。
Spring中Bean的实例化过程图示:
这里写图片描述
道友文章Spring中BeanPostProcessor

这个BeanPostProcessor 是什么时候被注册进来的?

/**     * Configure the factory's standard context characteristics,     * such as the context's ClassLoader and post-processors.     * @param beanFactory the BeanFactory to configure     */    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {        // Tell the internal bean factory to use the context's class loader etc.        //.................        // Configure the bean factory with context callbacks.        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));        //..................    }
原创粉丝点击