日积月累,水滴石穿 😄
Aware
Aware 接口定义如下:
/**
* A marker superinterface indicating that a bean is eligible to be notified by the
* Spring container of a particular framework object through a callback-style method.
* The actual method signature is determined by individual subinterfaces but should
* typically consist of just one void-returning method that accepts a single argument.
*
* <p>Note that merely implementing {@link Aware} provides no default functionality.
* Rather, processing must be done explicitly, for example in a
* {@link org.springframework.beans.factory.config.BeanPostProcessor}.
* Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
* for an example of processing specific {@code *Aware} interface callbacks.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
*/
public interface Aware {
}
从某翻译软件得出大意是:Aware 接口是一个具有标识作用的超级接口,指示 bean 是具有被 Spring 容器通知的能力,通知的方式是采用回调的方式。Aware 接口是一个空接口,具体的实现由各个子接口决定,且该接口通常只包含一个单个参数并且返回值为void的方法。可以理解就是 set 方法。该方法的命名方式为 set + 去掉接口名中的 Aware 后缀,即 XxxAware 接口,则方法定义为 setXxx(),例如 BeanNameAware(setBeanName),ApplicationContextAware(setApplicationContext)。注意,仅实现Aware接口,不会提供任何默认功能,需要明确的指定实现哪个子接口。
Spring 中提供了一些以Aware结尾的接口:
-
BeanClassLoaderAware:加载Spring Bean的类加载器
-
BeanFactoryAware:让 Bean 获取配置它们的 BeanFactory 的引用
-
BeanNameAware:让 Bean 获取自己在 BeanFactory 配置中的 Name
-
ApplicationContextAware:让 Bean 获取 ApplicationContext 上下文对象
-
EmbeddedValueResolverAware:让 Bean 获取配置文件内容(解析配置文件,与@Value 功能类似)
-
MessageSourceAware:对 MessageSource 的一个包装,处理国际化
-
ResourceLoaderAware:底层访问资源的加载器
-
ApplicationEventPublisherAware:应用事件
实践
Aware 的子接口挺多的,这里实践几个比较眼熟的。为什么说眼熟呢!因为在看源码的时候看到它们了。实践 BeanNameAware、BeanFactoryAware、BeanClassLoaderAware、ApplicationContextAware。下面就这前三个接口来做一个简单的演示,先看各自的定义:
public interface BeanClassLoaderAware extends Aware {
/**
* 为bean实例提供 BeanClassLoader 的回调函数
*/
void setBeanClassLoader(ClassLoader classLoader);
}
public interface BeanFactoryAware extends Aware {
/**
* 为bean实例提供 BeanFactory 的回调函数
*/
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
public interface BeanNameAware extends Aware {
/**
* 创建此bean的bean工厂中设置bean的名称
*/
void setBeanName(String name);
}
下面简单演示下上面三个接口的使用方法:
public class TestAware implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {
private String beanName;
private BeanFactory beanFactory;
private ClassLoader classLoader;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("调用了 setBeanClassLoader()");
this.classLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("调用了 setBeanFactory()");
this.beanFactory = beanFactory;
}
@Override
public void setBeanName(String name) {
System.out.println("调用了 setBeanName()");
this.beanName = name;
}
public void test(){
System.out.println("beanName = " + beanName);
System.out.println("bean对象 = " + beanFactory.getBean(beanName));
}
}
xml配置:
<bean class="com.gongj.aware.TestAware" id="testAware"></bean>
启动类:
public static void main(String[] args) {
ClassPathResource resource = new ClassPathResource("spring-config.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);
TestAware testAware = (TestAware)factory.getBean("testAware");
testAware.test();
}
结果:
调用了 setBeanName()
调用了 setBeanClassLoader()
调用了 setBeanFactory()
beanName = testAware
bean对象 = com.gongj.aware.TestAware@6e5e91e4
看到结果,我们可以得出实现这些 Aware 接口的Bean在被初始化之后,可以获取相对应的资源。例如实现BeanFactoryAware的Bean在实例化后,Spring容器将会注入BeanFactory的实例。具体源码解析前往:Spring源码(九)-初始化Bean-initializeBean
ApplicationContextAware
为什么要将这个接口单独拎出来将呢?其实是这个接口其实用的比较多。那它的实用场景是什么呢?当没有注册到 Spirng 容器的类(工具类)想要使用 Spirng 容器中的 Bean 的时候,就需要使用 ApplicationContextAware来开发一个SpringUtil类。
- SpirngUtil
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return applicationContext.getBean(name, requiredType);
}
public static <T> T getBean(String name) throws BeansException {
return (T) applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> clz) throws BeansException {
return applicationContext.getBean(clz);
}
}
创建 SpringUtil类,并实现 ApplicationContextAware接口,在类中提供几个获取 Bean 的方法。
- DemoUtil
public class DemoUtil {
public static void test(){
TestAware testAware = SpringUtil.getBean("testAware", TestAware.class);
testAware.test();
}
}
提供静态方法 test,使用 SpringUtil获取Spring容器中的 Bean 。
- xml 配置增加
SpirngUtil的 Bean 配置
<bean class="com.gongj.aware.SpringUtil" id="spirngUtil"></bean>
- Main
public static void main(String[] args) {
ClassPathResource resource = new ClassPathResource("spring-config.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);
DemoUtil.test();
}
从该运行结果可以看出,竟然发生了异常,这是因为使用的容器是
BeanFactory, BeanFactory里的getBean() 方法在激活Aware 接口时只检测了 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 三个 Aware 接口。需要使用ClassPathXmlApplicationContext容器。
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
DemoUtil.test();
}
结果:
调用了 setBeanName()
调用了 setBeanClassLoader()
调用了 setBeanFactory()
beanName = testAware
bean对象 = com.gongj.aware.TestAware@2cdf8d8a
ApplicationContextAware那这个Aware是在什么时候被激活的呢?逻辑位于
ApplicationContextAwareProcessor的invokeAwareInterfaces方法里,内容如下:
private void invokeAwareInterfaces(Object bean) {
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);
}
}
当前 bean 实现了什么接口,就给这个 bean 设置相对应的对象实例。至于ApplicationContextAwareProcessor 类是一个BeanPostProcessor。
- 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。