Aware接口介绍
Aware是一个具有标识作用的超级接口,具体实现是有子接口去决定的,但是子接口至少要有一个带一个参数的且返回是空的方法。实现该接口的bean是具有被spring 容器通知的能力的,而被通知的方式就是通过回调。也就是说:直接或间接实现了这个接口的类,都具有被spring容器通知的能力。
Aware翻译过来是adj. 知道的,明白的,察觉到的,意识到的,所以这些接口从字面意思应该是能感知到所有Aware前面的含义。
比如实现了ApplicationContextAware接口的类,能够获取到ApplicationContext,实现了BeanFactoryAware接口的类,能够获取到BeanFactory对象。
package org.springframework.beans.factory;
/**
* 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常用子接口如下:
org.springframework.context.ApplicationContextAware
org.springframework.beans.factory.BeanFactoryAware
org.springframework.beans.factory.BeanClassLoaderAware
org.springframework.beans.factory.BeanNameAware
org.springframework.context.EnvironmentAware
org.springframework.context.ResourceLoaderAware
org.springframework.context.annotation.ImportAware
1.ApplicationContextAware
实现该接口的类可以获取spring容器上下文信息 ApplicationContext , ApplicationContextAware接口源码如下:
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
下面demo可通过类的静态方法调用来获取applicationContext上下文信息:
@Component
public class ApplicationContextStaticProvider implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return context;
}
/**
* 通过beanName获取Bean
*
* @param beanName
* @return
*/
public static Object getBean(String beanName) {
return getApplicationContext().getBean(beanName);
}
/**
* 通过class获取bean
*
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
/**
* 通过name,以及Clazz返回指定的bean
*
* @param beanName
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(String beanName, Class<T> clazz) {
return getApplicationContext().getBean(beanName, clazz);
}
}
@Service
public class DemoBean {
public void test(String str){
System.out.println(str);
}
}
public class AnnotationConfigApplicationContextTests {
@Test
public void scanAndRefreshTestAware() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("org.springframework.context.annotation7");
context.refresh();
DemoBean demoBean= (DemoBean) ApplicationContextStaticProvider.getBean("demoBean");
demoBean.test("test applicationContextAware");
}
}
1.1 调用过程分析
Spring在初始化Bean时,如何回调ApplicationContextAware接口setApplicationContext方法呢?我们来看如下调用顺序:
1.AbstractApplicationContext#refresh() ;
2.AbstractApplicationContext#prepareBeanFactory() —> beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
3.AbstractApplicationContext#finishBeanFactoryInitialization();
4.DefaultListableBeanFactory#preInstantiateSingletons()—>getBean(beanName);
5.AbstractAutowireCapableBeanFactory#doCreateBean();
6.AbstractAutowireCapableBeanFactory#initializeBean();填充bean属性后,初始化bean。
7.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization()
8.执行ApplicationContextAwareProcessor.postProcessBeforeInitialization()
9.ApplicationContextAwareProcessor#invokeAwareInterfaces()
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.setApplicationContext()方法
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
第一步: AbstractApplicationContext#refresh()
第二步:给bean工厂配置ApplicationContextAware回调处理
AbstractApplicationContext#prepareBeanFactory() —> beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
第三步:初始化bean的过程(实例化(一般调用构造方法实例化bean)、属性注入、bean初始化),属性注入后,bean初始化前,调用ApplicationContextAware实现类setApplicationContext()方法
2.BeanFactoryAware
Spring Ioc 中最顶层的父接口就是BeanFactory。实现这个BeanFactoryAware接口的子类可以获取spring容器的BeanFactory 对象,进而可以动态的去操作 要在spring容器中注入的bean。
ApplicationContext接口是BeanFactory的子接口,所以继承ApplicationContextAware的实现类拿到ApplicationContext 对象比实现BeanFactoryAware接口拿到BeanFactory 对象 可以获取更多的信息。
BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能提前发现一些Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean(单例)。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。 相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。BeanFacotry延迟加载,如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常;而ApplicationContext则在初始化自身时检验,这样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用 ApplicationContext。应用上下文则会在上下文启动后预载入所有的单实例Bean。通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
3.BeanNameAware
这个接口的含义就是让实现类知道自己在spring容器中定义的beanName是什么,实际开发一般没啥用。
4.BeanClassLoaderAware
获取spring 容器的类加载器ClassLoader 对象;
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
正常使用的是: Thread.currentThread().getContextClassLoader();
5.EnvironmentAware
实现这个接口的类能获取Environmet对象,进而可以各种系统变量信息,也可以设置 变量的优先级别等等。
通过Environment 对象可以获取spring boot框架中的application.properties中定义的变量值。
5.ResourceLoaderAware
获取资源加载器ResourceLoader 对象,可以获得外部资源文件。