使用过Spring的人应该都知道他是一套很强大的应用开发框架,他的IOC、AOP等特性也是我们开发中最常用的一些特性,而Spring强大的不仅仅与在他的应用上,而且也在于他能与其他的框架集成,也可以通过二次开发形成更适合企业业务的框架。对于Spring的二次开发其实就不得不说到Spring的钩子方法了,这里我们把Spring提供的回调方法称为钩子方法,也就是我们常用的扩展点。
对于这个接口官方给出的解释是
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.
这里的意思其实就是Aware接口就是一个标记,继承Aware的接口就表示Spring容器可以通过回调方法将bean通知给特定的框架对象,并且他的返回值一般为void。
其实更通俗的解释可以是:我只要实现了Aware接口,Spring就需要为我把我需要的bean赋值进来给我
这也是为什么一些Aware的实现类可以用作工具类,可以使得非bean对象也能够使用spring中的bean。
而Aware接口的常见实现有BeanFactoryAware, BeanNameAware, ApplicationContextAware, EnvironmentAware,BeanClassLoaderAware等
这里的BeanFactoryAware和ApplicationContextAware实际上都是设置上下文的接口,我们下面以ApplicationContextAware来演示一下
@Component
public class HunterBeanFactoryAware implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@SuppressWarnings("static-access")
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> clazz){
if (clazz != null){
return applicationContext.getBean(clazz);
}
return null;
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
HunterBeanFactoryAware bean = getBean(HunterBeanFactoryAware.class);
System.out.println(bean);
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210522213514555.png
以上这个实现其实很常见,在一些工具类等经常可以看到,它使得在非Spring管理的对象能够用上bean,我们可以看到这接口可以手动setApplicationContext设置上Spring的下文,同时,当没有手动设置上下文时,是默认使用当前容器加载的上下文的。
顾名思义,这个回调的方法是和Bean的名字相关的,具体作用是能够获取到Bean的名字。
使用如下:
运行后可从容器获取名字:
顾名思义,这个EnvironmentAware很可能是与环境变量相关的一个接口,我们可以看一下他的接口以及需要实现的方法
public interface EnvironmentAware extends Aware {
/**
* Set the {@code Environment} that this component runs in.
*/
void setEnvironment(Environment environment);
}
这个其实很明显,和其他的方法都差不多是setxxx方法,实际上继承该方法后能得到Spring的注入。
@Component
public class HunterBeanFactoryAware implements EnvironmentAware {
private static Environment environment;
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Environment environment = getEnvironment();
System.out.println(environment);
}
@SuppressWarnings("static-access")
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
public static Environment getEnvironment(){
return environment;
}
}
输出显示:
因此,很明显,我们可以通过Aware的相关接口来获取到我们需要的Bean。
这个是不是很神奇?我们可以思考一下,为什么我们继承了这个方法以后,Spring就会自动帮我们注入进来我们需要的Bean呢,它是什么时候注入进来的?
下面我们可以分析一下源码:
首先我们从入口开始
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
在这里声明了一个上下文并且规定了我们的包扫描范围
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
//调用默认无参构造器,主要初始化AnnotatedBeanDefinitionReader
//以及路径扫描器ClassPathBeanDefinitionScanner
//这里由于他有父类,故而回显调用父类的构造方法,然后才会调用自己的构造方法
//在这里构造方法中初始一个读取器和扫描器
this();
/**
* 把传入的Class进行注册,Class既可以有@注解,也可以没有@Configuration注解
* 如何把注册委托给org.springframework.context.annotation.AnnotationedBeanDefinitionReader.register方法进行注册
* 包装传入Class生成BeanDefinition,注入到BeanDefinitionRegistry
*/
register(componentClasses);
refresh();
}
继续往下走,我们本章先忽略spring初始化的其他内容,进入到refresh()方法
@Override
public void refresh() throws BeansException, IllegalStateException {
//给容器refresh加锁,避免容器处在refresh阶段时,容器进行了初始化或销毁的操作
synchronized (this.startupShutdownMonitor) {
// 调用容器准备刷新的方法,获取容器的当前时间,同时给容器设置同步标识,具体方法.
prepareRefresh();
// 告诉子类启动refreshBeanFactory方法,Bean定义资源文件的载入从子类的
//refreshBeanFactory()方法启动,里面有抽象方法
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 对BeanFactory进行各种功能填充.
prepareBeanFactory(beanFactory);
try {
//允许容器的子类去注册PostProcessor,TODO 钩子方法
postProcessBeanFactory(beanFactory);
//激活各种BeanFactory处理器
invokeBeanFactoryPostProcessors(beanFactory);
//注册拦截Bean创建的Bean处理器,这里只是注册,真正的注册是在getBean时候.
registerBeanPostProcessors(beanFactory);
// 为上下文初始化Message源,即不同语言的消息体,国际化处理.
//找到"messageSource"的Bean提供给ApplicationContext使用,
//使得ApplicationContext具有国际化能力
initMessageSource();
// 初始化应用消息广播器,并放入"applicationEventMulticaster" bean中.
//初始化APplicationEventMulticaster该类为事件发布者
//可以存储所有事件监听者信息,并根据不同的事件,通知不同的时间监听者
initApplicationEventMulticaster();
//预留给AbstractApplicationContext的子类用于初始化其它特殊的bean,
//该方法需要在所有单例bean初始化之前调用
//比如Web容器就会去初始化一些和主题展示相关的Bean(ThemeSource)
onRefresh();
// 在所有注册的bean中查找Listener bean,注册到消息广播器中.
registerListeners();
// 设置自定义的类型转化器ConversionService
//设置自定义AOP相关的类LoadTimeWeaverAware
//清除临时的ClassLoader
//实例化所有的类(懒加载的类除外)
finishBeanFactoryInitialization(beanFactory);
// 完成刷新过程,通知声明周期处理器lifecycleProcessor刷新过程,
// 同时发出ContextRefreshEvent通知别人
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
refresh()方法其实Spring中最核心的方法之一,也是我们重点分析的一个方法,Spring容器创建之后,会调用它的refresh方法刷新Spring应用的上下文,并设置一些生命周期回调的管理类,也就是在Bean初始化能够“接入的方法”,这里需要注意的是prepareBeanFactory()方法,其主要做的是对Bean工厂初始化的准备。
此处添加的BeanPostProcessor相关的接口其实是Spring最重要的生命周期回调接口,我们可以来看一下他的接口方法
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
是两个默认实现的空方法,他们分别在Bean初始化之前和初始化之后进行调用,入参分别是bean和beanName,回调方法可以对相信的信息进行判断和处理。
我们进一步看一下他的实现类
我们这里需要注意的是ApplicationContextAwareProcessor这个类,因为他正是我们前面在prepareBeanFactory方法中new出来的对象(前面第二张图中的代码)。
我们来看一下这个ApplicationContextAwareProcessor的在对bean的初始化前所回调的方法做了写什么
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
很明显可以看出来,这个方法主要是用来对特定的几个Aware实现类进行处理的,我们进入到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);
}
}
走到这里其实我们已经大概明白了,因为我们对所有被spring管理的bean都会循环处理,所以这里可以对所有被spring管理的bean一个个的做判断,只要有一个属于规定的其中的Aware实现类,我们就对他进行初始化,并且把我们现在容器所存在的bean用set的形式放进去。这就是为什么只要我们实现了这个接口,并且该接口的实现类是被Spring所管理的,就会为我们自动赋上相应的bean。