前言
部分情况下我们想在一个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));
//..................
}