1
头图

Detailed ApplicationContextAware

1. Enter the topic

The original meaning of Aware is "automatic". As the name implies, spring does something for us automatically. Spring has many classes ending with Aware, such as EnvironmentAware, ApplicationContextAware, MessageSourceAware, etc.

Here I mainly talk about ApplicationContextAware.

As quoted below, the documentation of ApplicationContextAware can be read Spring Core Technologies 1.4.6 Method Injection , Spring Core Technologies 1.6.2. ApplicationContextAware and BeanNameAware , Method Injection

To summarize, it is:

In most application scenarios, most beans in the container are singletons. When a singleton bean needs to collaborate with another singleton bean, or a non-singleton bean needs to collaborate with another non-singleton bean, the dependency is usually handled by defining a bean as an attribute of another bean. When the life cycle of the bean is different, problems arise. Suppose that singleton bean A needs to use non-singleton (prototype) bean B, possibly on every method call of A. The container only creates singleton bean A once, so there is only one opportunity to set the properties. The container cannot provide bean A with a new instance of bean B every time bean A is needed.

One solution is give up some inversion of control. aware of the container by implementing the ApplicationContextAware interface and making a getBean("B") call to the container every time bean A needs an instance of bean B.

Two, use

@Service("gatewayService")
public class GatewayServiceImpl implements IGatewayService,ApplicationContextAware {

    Map<ServiceBeanEnum,IGatewayBo> chargeHandlerMap=new HashMap<ServiceBeanEnum,IGatewayBo>();

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }
}

Implement the ApplicationContextAware interface in the service that we need to use the ApplicationContext. When the system starts, we can automatically inject the applicationContext object into our service, and we can get all the information in the ApplicationContext.

Three, principle analysis

We all know that the entry method of spring is in the refresh() method of AbstractApplicationContext. Let's take a look at the refresh().prepareBeanFactory() method first.

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()));

        // 添加ApplicationContextAware的处理器
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
                ...
    }

In other words, spring added a processor such as ApplicationContextAwareProcessor to us when it started, let's go in and see its implementation:

@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((PrivilegedAction)() -> {
            //核心方法,调用aware接口方法
            invokeAwareInterfaces(bean);
            return null;
        }, acc);
    } else {
        invokeAwareInterfaces(bean);
    }

    return bean;
}

//实现
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);
        }
        //针对实现了ApplicationContextAware的接口,spring都将调用其setApplicationContext,将applicationContext注入到当前bean对象。
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
        }
    }
}

When is the ApplicationContextAwareProcessor called? Let's look down, the original refresh() method also has a beanFactory.preInstantiateSingletons() method, which contains such a piece of code:

拿到所有的beanNames,然后依次判断是否需要加载,如果是,则调用getBean(beanName)方法实例化出来。
// Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                boolean isEagerInit;
                if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                    isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                        @Override
                        public Boolean run() {
                            return ((SmartFactoryBean<?>) factory).isEagerInit();
                        }
                    }, getAccessControlContext());
                }
                else {
                    isEagerInit = (factory instanceof SmartFactoryBean &&
                                   ((SmartFactoryBean<?>) factory).isEagerInit());
                }
                if (isEagerInit) {
                    getBean(beanName);
                }
            }
            else {
                getBean(beanName);
            }
        }
    }

Check the getBean() ->doGetBean()->createBean()->doCreateBean() method in turn:

// Initialize the bean instance.
Object exposedObject = bean;
try {
    populateBean(beanName, mbd, instanceWrapper);
    if (exposedObject != null) {
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
} catch (Throwable ex) {
    if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
        throw (BeanCreationException) ex;
    } else {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
    }
}

Take a look at the initializeBean method:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged(() -> {
            this.invokeAwareMethods(beanName, bean);
            return null;
        }, this.getAccessControlContext());
    } else {
        //调用setBeanName() 、setBeanClassLoaderAware、setBeanFactoryAware方法
        this.invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
    }

    try {
        //调用afterPropertiesSet()方法
        this.invokeInitMethods(beanName, wrappedBean, mbd);
    } catch (Throwable var6) {
        throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
    }
    //这里才是ApplicationContextProcessor的postProcessAfterInitialization()执行入口:
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

It turns out that the inititalBean() method in AbstractAutowireCapableBeanFactory is where BeanPostProcessor is called. However, unlike BeanNameAware and BeanFactoryAware, they are implemented directly by calling invokeAwareMethods in initialBean()

Four, sample

import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.Map;

/**
 * 通过Spring上下文获取bean工具类
 *
 * @author moon
 */
public class SpringContextUtils implements ApplicationContextAware {

    /**
     * Spring应用上下文环境
     */
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextUtils.initSpringContext(applicationContext);
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        return (T) applicationContext.getBean(name);
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    public static boolean isSingleton(String name) {
        return applicationContext.isSingleton(name);
    }

    /**
     * 根据class对象返回IOC容器中其对象和其子类的对象。
     * 未找到则返回空MAP。
     * KEY为BEAN ID或者NAME,VALUE为BEAN实例
     *
     * @param type 需要找的bean类型的CLASS对象
     * @return bean映射
     */
    public static <T> Map<String, T> getBeansByType(Class<T> type) {
        return BeanFactoryUtils.beansOfTypeIncludingAncestors(SpringContextUtils.getApplicationContext(), type);
    }

    /**
     * 初始化ApplicationContext
     *
     * @param applicationContext 上下文
     */
    public static void initSpringContext(ApplicationContext applicationContext) {
        SpringContextUtils.applicationContext = applicationContext;
    }

    /**
     * 获取业务线(业务线配置在配置文件中)
     *
     * @return 业务线
     */
    public static String getProjectBusinessLine() {
        if (applicationContext == null) {
            throw new RuntimeException("spring初始化失败");
        }
        return applicationContext.getEnvironment().getProperty("***.application.businessLine");
    }

    /**
     * 获取项目名称(项目名称配置在配置文件中)
     *
     * @return 项目名称
     */
    public static String getProjectName() {
        if (applicationContext == null) {
            throw new RuntimeException("spring初始化失败");
        }
        return applicationContext.getEnvironment().getProperty("***.application.name");
    }
}

莫小点还有救
219 声望26 粉丝

优秀是一种习惯!