第一次遇见这个接口,是在Bean的初始化过程中。初始化的第一步就是 invokeAwareMethods ,执行Aware子接口的相关set方法。
网上查资料,大多是术语比如:感知自己的属性。不明白的是,有什么实际应用?
先看抛出一个常见需求,我需要在一个类A里获取一个Bean,但是类A不是一个Bean(不由Spring管理,没办法Autowired来注入其它Bean)。
那么我们首先要获取到上下文的实例,然后获取任何Bean就不成问题了。
这个时候我们就可以利用Aware接口的特性来帮助我们获取到ApplicationContext实例了。
实现Aware接口
import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * Aware接口的实际应用 */ public class ApplicationContextUtils implements ApplicationContextAware,BeanNameAware { private static ApplicationContext applicationContext; private static String name; /** * 设置当前应用程序上下文 * @param applicationContext * @throws BeansException */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { ApplicationContextUtils.applicationContext = applicationContext; } public static <T> T getBean(String name, Class<T> clazz){ return applicationContext.getBean(name, clazz); } /** * 设置当前Bean的名称 * @param name */ @Override public void setBeanName(String name) { ApplicationContextUtils.name = name; } public static String getName(){ return name; } }
这里我实现了两个接口,分别“感知”自己的上下文和bean名称
一个简单实体类
import lombok.Getter; @Getter public class User { private String name = "AAA"; }
配置类
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SimpleConfig { /** * 配置工具类,默认以方法名称为bean名称(实现Aware接口的类要交给Spring管理) * @return */ @Bean public ApplicationContextUtils applicationContextUtils(){ return new ApplicationContextUtils(); } @Bean("user") public User getUser(){ return new User(); } }
启动
import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) throws Exception { // 启动容器 ApplicationContext context = new AnnotationConfigApplicationContext(SimpleConfig.class); // 使用工具类来“感知”应用程序上下文,进而手动getBean User user = ApplicationContextUtils.getBean("user", User.class); System.out.println(user.getName()); // 感知bean名称 System.out.println(ApplicationContextUtils.getName()); } }
输出
总结
这么一来,Aware接口的作用就清晰明了了。
1. Aware接口是个标记接口,标记这一类接口是用来“感知”自己属性的。
2. Aware的众多子接口则是实现了:我具体要“感知”什么属性
3. Aware子接口的实现类则是:我要拿到你能“感知”到的属性,为我所用。
另附Aware子接口
对于初始化的时候涉及的Aware接口:
初始化方法全路径:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
invokeAwareMethods方法:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods
这里涉及三个Aware子接口:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
实际上另外一些接口
在容器启动,刷新方法第三步:org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory
其中有一行:
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));后面这个类里有个 postProcessBeforeInitialization 方法,在每个Bean初始化之前调用。
里面有个 invokeAwareInterfaces 方法
这里涉及:EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware