05-spring Spring Aware接口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/my_momo_csdn/article/details/91532750

Aware接口

  • Aware是Spring的一个重要顶层接口,包含很多子接口,相关的接口功能都很类似,Aware体系接口可以理解为一种能力,
    它表示spring容器会通过回调方法来将特定的框架对象通知给这个bean。有点拗口,举个例子,Aware的一个子接口ApplicationContextAware
public interface ApplicationContextAware extends Aware {

	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

  • 在这里,setApplicationContext就是前面所说的回调方法,applicationContext对象就是特定的框架对象,在bean初始化的某个特定时机,会调
    用该方法,将applicationContext对象传递给实现了ApplicationContextAware接口的bean。

一、子接口

  • Aware是顶层接口,包含很多子接口,每一个子接口代表具体的一种场景,比如前面的ApplicationContextAware就是具体的一种。

  • BeanNameAware

  • BeanClassLoaderAware

  • BeanFactoryAware

  • EnvironmentAware

  • ApplicationContextAware

  • EmbeddedValueResolverAware

  • ResourceLoaderAware

  • ApplicationEventPublisherAware

    扫描二维码关注公众号,回复: 6500033 查看本文章
  • MessageSourceAware

  • ImportAware

  • LoadTimeWeaverAware

  • NotificationPublisherAware

二、常用子接口

  • 常用的子接口通常都是用来对bean注入一个属性,比如BeanNameAware将beanName注入给bean。下面表格中小结了常用的接口功能,
    其中感知某种属性实际上就是一个回调的set方法将对应的属性set到当前的bean中。
接口 作用 备注
BeanNameAware 感知Bean的beanName 获取bean名称
BeanClassLoaderAware 感知当前Bean工厂用来加载当前Bean的ClassLoader 主要是框架的类实现该接口,使用BeanClassLoader加载外部对应的Resource资源
BeanFactoryAware 感知BeanFactoryAware 获取IOC容器
ApplicationContextAware 感知ApplicationContextAware 获取应用上下文
EnvironmentAware 感知Environment 获取Environment

三、回调时机

  • 这部分我们看看这些回调方法的调用时机。

3.1 BeanPostProcessor之前处理

接口
BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
  • 我们很好奇Aware子接口的方法是在什么时候调用的,这个问题实际上也是bean的生命周期的一部分,方法的回调肯定是在生命周期的某个阶段。
    我们通过bean的生命周期源码的方法跟进,跟进到
    AbstractAutowireCapableBeanFactory#initializeBean()#1685
    (可以参考03-spring BeanPostProcessor文章中的BeanPostProcessor方法的调用时机小节)
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		//1.这一步就是调用Aware方法
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

        //2.调用BeanPostProcessor前置方法
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

        //3.初始化过程
		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		//4.调用BeanPostProcessor后置方法
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}
  • AbstractAutowireCapableBeanFactory#invokeAwareMethods#line 1716
//invokeAwareMethods方法会判断bean是否实现了对应的接口,然后调用对应接口的回调方法,包含BeanNameAware,BeanClassLoaderAware,BeanFactoryAware这三种。
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);
			}
		}
	}
  • 通过上面的2个方法我们可以看到,如果一个bean实现了BeanNameAware,BeanClassLoaderAware和BeanFactoryAware三个接口中的某一个或者多个的话,那么
    对应的回调方法会在BeanPostProcessor后置处理器的前置方法之前被调用,即遵循这样的处理流程:Aware回调方法->BeanPostProcessor前置方法->Bean初始化->BeanPostProcessor后置方法

3.2 BeanPostProcessor中处理

  • 我们在3.1其实只看到了BeanNameAware,BeanClassLoaderAware,BeanFactoryAware这三个接口的调用源码,也知道了对应回调方法的调用时机。那么其余的接口回调方法呢?
接口
EnvironmentAware
ApplicationContextAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
  • 上面的5个接口的回调方法是在ApplicationContextAwareProcessor类中处理的,一看类名我们就知道这个是一个BeanPostprocessor接口的实现类,如下:
class ApplicationContextAwareProcessor implements BeanPostProcessor {

	private final ConfigurableApplicationContext applicationContext;

	private final StringValueResolver embeddedValueResolver;


	/**
	 * Create a new ApplicationContextAwareProcessor for the given context.
	 */
	public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
	}


    //重写BeanPostProcessor的前置方法,进行Aware子接口的相关判断和回调方法执行
	@Override
	@Nullable
	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((PrivilegedAction<Object>) () -> {
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}

    //执行回调方法,包括EnvironmentAware,ApplicationContextAware,EmbeddedValueResolverAware,ResourceLoaderAware,ApplicationEventPublisherAware,MessageSourceAware五个接口的处理
	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);
			}
		}
	}

    //重写BeanPostProcessor的后置方法,直接返回bean
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		return bean;
	}

}
  • 代码逻辑比较简单,ApplicationContextAwareProcessor是一个BeanPostprocessor接口实现类,因此他会处理每一个普通的bean,在处理时候在他的前置处理方法中会判断是否实现了指定的接口,
    并调用指定的方法。因此这里的五个接口的处理是在BeanPostprocessor的前置处理方法中调用的。即遵循这样的处理流程:BeanPostProcessor前置方法(Aware回调方法)->Bean初始化->BeanPostProcessor后置方法

3.3 特殊

接口
ImportAware
LoadTimeWeaverAware
NotificationPublisherAware

3.3.1 ImportAware

  • ImportAware接口方法的回调是在ConfigurationClassPostProcessor.ImportAwareBeanPostProcessor类中实现的,分析代码发现ImportAwareBeanPostProcessor也是BeanPostProcessor的
    子类,并且也是在BeanPostProcessor的后置回调方法中执行的,这一点和3.2是一样的。如下:
private static class ImportAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {

		private final BeanFactory beanFactory;

		public ImportAwareBeanPostProcessor(BeanFactory beanFactory) {
			this.beanFactory = beanFactory;
		}

		@Override
		public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {

			// Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
			// postProcessPropertyValues method attempts to autowire other configuration beans.
			if (bean instanceof EnhancedConfiguration) {
				((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
			}
			return pvs;
		}

        //在BeanPostProcessor的后置回调方法中回调ImportAware.setImportMetadata方法
		@Override
		public Object postProcessBeforeInitialization(Object bean, String beanName)  {
			if (bean instanceof ImportAware) {
				ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
				AnnotationMetadata importingClass = ir.getImportingClassFor(bean.getClass().getSuperclass().getName());
				if (importingClass != null) {
					((ImportAware) bean).setImportMetadata(importingClass);
				}
			}
			return bean;
		}
	}
  • 关于ImportAware接口的作用,发现资料不多,我用代码试验了是这样的作用。比如我们自己写的一个配置类A,在配置类A中import一个配置类B,类B实现ImportAware接口,那么在类B的
    setImportMetadata方法中就可以获取关于类A的很多元信息,可能主要用在框架内部,暂时没有去研究它的使用场景,示例代码如下:
@Import(Cap11Config.class)
@Configuration
@ComponentScan("com.intellif.ch11")
@PropertySource(value="classpath:/application-01.properties")
public class Cap11MainConfig {
    
}


@Configuration
public class Cap11Config implements ImportAware {

    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        System.out.println("Cap11Config setImportMetadata function execute:  " + importMetadata.toString());
        Set<String> annotationTypes = importMetadata.getAnnotationTypes();
        for (String annotation: annotationTypes) {
            System.out.println(annotation);
        }
    }
    
}

//部分打印如下,可以看到在Cap11Config配置类中获得了Cap11MainConfig配置类的相关信息:
Cap11Config setImportMetadata function execute:  org.springframework.core.type.StandardAnnotationMetadata@670002
org.springframework.context.annotation.Import
org.springframework.context.annotation.Configuration
org.springframework.context.annotation.ComponentScan
org.springframework.context.annotation.PropertySource

3.3.2 LoadTimeWeaverAware

  • LoadTimeWeaverAware接口的实现类,在框架源码中只有AspectJWeavingEnabler,其原理和AOP相关,在这里就不分析了,后续关于AOP的文章再做分析。

3.3.2 NotificationPublisherAware

  • NotificationPublisherAware是用来注入Spring JMX通知发布者,使用不多,在框架中都未找到源码,暂不做分析。

四、小结

  • 本文我们主要是小结了Aware接口体系的常用接口,简单分析了对应接口的回调方法的调用时机,Aware接口本身提供的功能比较容易理解,实际上就是让bean在其
    生命周期过程中获取到容器的一些信息(一般情况下可能容器作为bean的管理者,bean不需要知道容器的习惯细节,但是可能也会有一些情况bean需要知道容器的一些
    信息,来帮助bean完成一些功能,比如注入上下文来获取其他的bean,注入beanName等)。Aware的回调接口的时机一部分接口是在BeanPostProcessor前置处理方法之
    前调用,一部分接口直接就是在BeanPostProcessor前置处理方法中调用的,这样的情况实际上是由一个BeanPostProcessor的子类来完成处理的。
  • 结合Bean的生命周期和Aware回调方法的调用时机,我们可能在整体上掌握的更好。

五、参考

猜你喜欢

转载自blog.csdn.net/my_momo_csdn/article/details/91532750