Spring AOP原理
经过前面的分析,大致已经了解了Spring的原理,其中在使用的时候,有一个很重要的点就是AOP编程,什么是AOP,就不多做概述了,一句话:面向切面编程,在原有业务逻辑上,通过动态代理进行功能增强。
在Spring中主要是利用了BeanPostProcessor可以在Bean生命周期进行拦截的特性。因此主要有两步:
- 解析xml的时候,注册aop相关的BeanPostProcessor
- 普通Bean初始化的时候BeanPostProcessor的作用
1.1 AnnotationAwareAspectJAutoProxyCreator 的解析
在ApplicationContext.xml 中,如果要使用aop需要有这样一个标签
<beans>
<aop:aspectj-auto />
</beans>
在前面配置文件的解析分析中,说明了针对这种自定义的标签,一定会有一个对应的NameSpaceHandler处理器。针对aop标签的处理器就是AopNamespaceHandler
public void init() {
this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
// 这里是解析的开始处
this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
一直进入到下面这个方法
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
// 在这里就可以看到 AnnotationAwareAspectJAutoProxyCreator 这个类了
// 这个类就是aop相关的BeanPostProcessor实现类
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
具体是获取的就不详细分析了。
1.2 AnnotationAwareAspectJAutoProxyCreator 在运行期如何创建代理的
来看这个类的代码
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
private List<Pattern> includePatterns;
private AspectJAdvisorFactory aspectJAdvisorFactory;
private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
public AnnotationAwareAspectJAutoProxyCreator() {
}
public void setIncludePatterns(List<String> patterns) {
}
public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) {
}
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
protected List<Advisor> findCandidateAdvisors() {
}
protected boolean isInfrastructureClass(Class<?> beanClass) {
}
protected boolean isEligibleAspectBean(String beanName) {
}
private class BeanFactoryAspectJAdvisorsBuilderAdapter extends BeanFactoryAspectJAdvisorsBuilder {
public BeanFactoryAspectJAdvisorsBuilderAdapter(ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
super(beanFactory, advisorFactory);
}
protected boolean isEligibleBean(String beanName) {
return AnnotationAwareAspectJAutoProxyCreator.this.isEligibleAspectBean(beanName);
}
}
}
在这个类的方法中,并没有典型的几个切面方法,所以需要去看它的父类,来看一下这个类的继承关系
可以看到AnnotationAwareAspectJAutoProxyCreator 中实现了BeanPostProcessor 和 InstantionAwareBeanPostProcessor ,而且基类是AbstarctAutoProxyCreator 类,在这个类中就可以看到我们想要看的东西
// bean实例化前执行的方法
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = this.getCacheKey(beanClass, beanName);
if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
if (beanName != null) {
TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
this.targetSourcedBeans.add(beanName);
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
return null;
}
// 实例化后注入属性前 执行
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
return true;
}
// 上面的方法执行后,再执行这个方法
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
return pvs;
}
// 注入属性后,bean执行初始化方法前,执行。
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
// 注入属性后,bean执行初始化方法后,执行。
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
观察上面几个切面方法,可以看到只有两个方法有实质性意义:
- bean实例化前执行的方法
public Object postProcessBeforeInstantiation - 注入属性后,bean执行初始化方法后,再执行。
public Object postProcessAfterInitialization
1.2.1 postProcessBeforeInstantiation 方法解析
第一个方法作用是判断当前Bean可不可以被代理。
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
// 创造一个缓存key
Object cacheKey = this.getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 是否已经包含这个cacheKey,即是否已经包含当前Bean了
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
/*
这个判断非常重要,第一个方法表示 是否是advice | PointCut | Advisor 等aop基类,是的话,先把这个类存储到advisedBeans中,标志位false,即不能代理。
第二个方法,是通过shouldSkip()方法,把当前Bean的所有通知和切面结合成Advisor通知器。最后判断是否应该跳过。
*/
if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 这里是问是否要自定义目标代理的,通常是返回null,所以,虽然下面代码也有创建代理
// 但通常不会执行,实际创建代理还是在postProcessAfterInitialization中
TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} else {
return null;
}
}
1.2.2 postProcessAfterInitialization 方法解析
第二个方法就是根据第一个方法,实际生成代理类的地方
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) { // 继续进入方法中,这个是核心方法。
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 这里就是根据第一个取值去判断是否应该去获取代理类
// 很明显,如果前面存了false的就会直接返回。
else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 这里又出现了这两个方法,是为了保险起见的重复判断
// 在shouldSkip方法中,虽然也对切面进行了获取,但只是为了判断,
// 下面的getAdvicesAndAdvisorsForBean方法才会返回切面
else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
// 这个方法中,会将所有的通知器(切面) Advisors 返回到specificInterceptors 中。
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理
Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} else {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
} else {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
上面的方法,就是经过一系列判断,最后到达最后两个步骤:
- 获取当前Bean相关的通知器(通知和切点的结合,也可以叫切面)
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 继续调用findEligibleAdvisors方法,
List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);
// 根据获取到的通知器集合,判断是返回null,还是集合。
return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 这是获取所有通知器的方法
List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
// 这是过滤出当前Bean应该应用的通知器的方法
List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
this.extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
由于通常使用的aop都是由注解来完成的,因此findCandidateAdvisors()方法应该也查看 AnnotationAwareAspectJAutoProxyCreator 类中的
protected List<Advisor> findCandidateAdvisors() {
//调用父类的方法,作用是获取配置文件中的 通知
List<Advisor> advisors = super.findCandidateAdvisors();
if (this.aspectJAdvisorsBuilder != null) {
// this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 这个方法是根据注解了@Aspect的类去获取通知器
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
- 根据获取的通知器,创建代理
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (this.shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
this.evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
// 把通知器放到生成代理的工厂中
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
this.customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (this.advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 生成代理,里面会判断是采用JDK动态代理,还是cglib动态代理。
return proxyFactory.getProxy(this.getProxyClassLoader());
}
总结:
aop的应用主要是利用了BeanPostProcessor的在Bean生命周期有前置和后置方法的特性,来在Bean初始化完成后,进行动态代理,使运行时使用的类,已经是被动态代理的代理类。
主要步骤:
- 通过AopNamespaceHandler 注册实现了BeanPostProcessor接口的AnnotationAwareAspectJAutoProxyCreator 类。
- 在容器中的Bean实例化的时候,根据实例化前的前置方法 postProcessBeforeInstantiation 判断是否可以被代理。
- 根据初始化后的后置方法 postProcessAfterInitialization 进行实际的代理创建,其中包括两步:获取当前Bean的所有切面(通知器)集合; 根据条件选择jdk动态代理或者cglib进行动态代理。
Spring中的事务,就是利用了AOP代理来实现的,Spring扩展的大部分功能都是通过AOP代理实现的。
ps:终于磕磕碰碰的写到了这里,这个系列就结束了。