服务器之家

服务器之家 > 正文

spring源码阅读--aop实现原理讲解

时间:2022-01-21 01:05     来源/作者:一撸向北

aop实现原理简介

首先我们都知道aop的基本原理就是动态代理思想,在设计模式之代理模式中有介绍过这两种动态代理的使用与基本原理,再次不再叙述。

这里分析的是,在spring中是如何基于动态代理的思想实现aop的。为了方便了解接下来的源码分析,这里简单化了一个流程图分析aop的基本实现思想。

spring源码阅读--aop实现原理讲解

so,基于上面的流程,一步步分析spring源码中的aop实现方式。

采用一个简单的aop例子,利用基于注解配置方式的切面配置,分析一个简单的Before AOP例子。在spring boot下运行以下简单例子。

AOP的advisor和advice配置。

@Component
@Aspect
public class AopConfig {
  @Pointcut("execution(* com.garine.debug.testcase.model.AopObject..*(..))")
  public void mypoint(){
      //切面定义
  }
  @Before("mypoint()")
  public void doAround() throws Throwable {
      System.out.println("before logic");
  }
}

AopObject,被代理拦截对象。

@Component
public class AopObject {
  public void aoped(){
      System.out.println("logic");
  }
}

 

代理实现的处理器(BeanPostProcessor)

首先是第一步内容,对我们在AopConfig中的AOP配置内容进行解析并且保存到BeanFactory中,这个过程就是解析保存切面信息。

代理实现的源头CAnnotationAwareAspectJAutoProxyCreator

经过一遍的代码跟踪,我了解到注解方式的AOP配置,都离不开一个类CAnnotationAwareAspectJAutoProxyCreator,这个类继承了BeanPostProcessor接口,我们都知道BeanPostProcessor的实现类有多个执行处理节点,其中一个执行节点就是在Bean实例化之后。也就是在这个时机AnnotationAwareAspectJAutoProxyCreator拦截bean的初始化过程,根据提前解析得到的切面信息,对bean的方法进行尝试适配,如果有匹配则需要进行代理创建。

这里先分析的就是AnnotationAwareAspectJAutoProxyCreator,在bean实例化第一次查询所有切面信息时,就会解析保存Aop的信息到实例中,跟踪以下代码。

AbstractApplicationContext#refresh (上下文初始化主干方法)

AbstractApplicationContext#registerBeanPostProcessors (执行实例化并保存所有实现BeanPostProcessor接口的类)

按照上面的逻辑,registerBeanPostProcessors 会比一般的bean实例化逻辑要早执行,因此我们接下来只需要分析AnnotationAwareAspectJAutoProxyCreator的初始化过程。

AnnotationAwareAspectJAutoProxyCreator的继承结构

spring源码阅读--aop实现原理讲解

通过上图可以知道,AnnotationAwareAspectJAutoProxyCreator是继承了BeanfactoryAware接口,所以在实例化时,会执行setFactory方法。而所有切面信息解析的执行者BeanFactoryAspectJAdvisorsBuilderAdapter初始化的时机也是在setFactory方法。

跟踪代码如下。

AbstractAdvisorAutoProxyCreator#setBeanFactory

AnnotationAwareAspectJAutoProxyCreator#initBeanFactory

在这个方法里面会新建一个BeanFactoryAspectJAdvisorsBuilderAdapter,这个对象会根据Beanfactory内的aop配置信息,进行解析保存。但是需要注意,此时虽然新建了BeanFactoryAspectJAdvisorsBuilderAdapter对象.但是此时还不会马上解析aop配置,需要在第一次个普通bean实例化时才执行解析aop配置。解析的方法就是

BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors,会在初次执行AnnotationAwareAspectJAutoProxyCreator调用postProcessBeforeInitialization时开始执行。

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 super.initBeanFactory(beanFactory);
  //aspectJAdvisorsBuilder#buildAspectJAdvisors就是解析配置入口
 this.aspectJAdvisorsBuilder =
       new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}

 

代理对象(Proxy)的创建

解析并缓存切面

上面提到继承结构图中,AnnotationAwareAspectJAutoProxyCreator是实现了InstantiationAwareBeanPostProcessor接口的,InstantiationAwareBeanPostProcessor接口定义的postProcessBeforeInitialization方法是一个可以对已经注入依赖属性的bean对象实例进行编辑操作的接口,会在

AbstractAutowireCapableBeanFactory#doCreateBean

AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)

AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation

方法中执行InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation,初次初始化缓存切面信息的话就是在这个方法里面。。

具体的调用链如上所示。这里的postProcessBeforeInstantiation方法实际上是AnnotationAwareAspectJAutoProxyCreator的实例进行调用,AnnotationAwareAspectJAutoProxyCreator实现InstantiationAwareBeanPostProcessor接口。

下面进入InstantiationAwareBeanPostProcessor#postProcessBeforeInitialization方法分析代码。

AbstractAutoProxyCreator#postProcessBeforeInstantiation

AspectJAwareAdvisorAutoProxyCreator#shouldSkip (关键代码)

进入如下代码AbstractAutoProxyCreator,这个实例也就是之前一开始初始化的AnnotationAwareAspectJAutoProxyCreator实例,进入实例的shouldSkip 方法

	@Override
	protected boolean shouldSkip(Class<?> beanClass, String beanName) {
		// TODO: Consider optimization by caching the list of the aspect names
      //预先解析缓存切面信息
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		for (Advisor advisor : candidateAdvisors) {
			if (advisor instanceof AspectJPointcutAdvisor) {
				if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
					return true;
				}
			}
		}
		return super.shouldSkip(beanClass, beanName);
	}

AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors

方法findCandidateAdvisors代码如下,这里是预先解析缓存所有切面advisor信息,注意这一步操作是在AbstractAutoProxyCreator#postProcessBeforeInitialization处理,也就是开头提到的切面解析操作,解析完成就进行缓存。

@Override
protected List<Advisor> findCandidateAdvisors() {
 // Add all the Spring advisors found according to superclass rules.
 List<Advisor> advisors = super.findCandidateAdvisors();
 // Build Advisors for all AspectJ aspects in the bean factory.
  //这里就是前面提到的BeanFactoryAspectJAdvisorsBuilder解析所有切面信息的调用点
 advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
 return advisors;
}

然后继续在这里先提前看一下是如何解析aop配置的。跟踪BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

public List<Advisor> buildAspectJAdvisors() {
 List<String> aspectNames = null;
 synchronized (this) {
    aspectNames = this.aspectBeanNames;
    if (aspectNames == null) {
       List<Advisor> advisors = new LinkedList<Advisor>();
       aspectNames = new LinkedList<String>();
        //查询出Beanfactory中所有已经注册的BeanName
       String[] beanNames =
             BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
       for (String beanName : beanNames) {
          if (!isEligibleBean(beanName)) {
             continue;
          }
          // We must be careful not to instantiate beans eagerly as in this
          // case they would be cached by the Spring container but would not
          // have been weaved
          Class<?> beanType = this.beanFactory.getType(beanName);
          if (beanType == null) {
             continue;
          }
           //判断Bean是否是切面Bean,isAspect方法判断[标注1]
          if (this.advisorFactory.isAspect(beanType)) {
             aspectNames.add(beanName);
             AspectMetadata amd = new AspectMetadata(beanType, beanName);
             if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                MetadataAwareAspectInstanceFactory factory =
                      new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                 //解析aop class的配置,包返回Advisor对象[标注2]
                List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                if (this.beanFactory.isSingleton(beanName)) {
                   this.advisorsCache.put(beanName, classAdvisors);
                }
                else {
                   this.aspectFactoryCache.put(beanName, factory);
                }
                advisors.addAll(classAdvisors);
             }
             else {
                // Per target or per this.
                if (this.beanFactory.isSingleton(beanName)) {
                   throw new IllegalArgumentException("Bean with name '" + beanName +
                         "' is a singleton, but aspect instantiation model is not singleton");
                }
                MetadataAwareAspectInstanceFactory factory =
                      new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                this.aspectFactoryCache.put(beanName, factory);
                advisors.addAll(this.advisorFactory.getAdvisors(factory));
             }
          }
       }
       this.aspectBeanNames = aspectNames;
       return advisors;
    }
 }
 if (aspectNames.isEmpty()) {
    return Collections.emptyList();
 }
 List<Advisor> advisors = new LinkedList<Advisor>();
 for (String aspectName : aspectNames) {
    List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
    if (cachedAdvisors != null) {
       advisors.addAll(cachedAdvisors);
    }
    else {
       MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
       advisors.addAll(this.advisorFactory.getAdvisors(factory));
    }
 }
 return advisors;
}

**[标注1]如何判断类是否是aop切面配置类? **

通过以下代码。

@Override
public boolean isAspect(Class<?> clazz) {
 return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
private boolean hasAspectAnnotation(Class<?> clazz) {
  //包含@Aspect注解
 return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}

[标注2]如何解析为Advisor对象?

ReflectiveAspectJAdvisorFactory#getAdvisors 遍历所有没被@PointCut注解标注的方法,也就是遍历切面内容方法

ReflectiveAspectJAdvisorFactory#getAdvisor 处理所有没被@PointCut注解标注的方法,候选切面内容方法

代码如下。

@Override
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
    int declarationOrderInAspect, String aspectName) {
 validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
 //解析判断候选方法是否有@Before,@After,@Around等注解,如果有,就继续执行新建Advisor对象。
 AspectJExpressionPointcut expressionPointcut = getPointcut(
       candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
 if (expressionPointcut == null) {
    return null;
 }
//创建advisor
 return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
       this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

最终循环解析,@Before,@After,@Around等标注的方法都会新建一个Advisor对象。新建的Advisor对象都保存在BeanFactoryAspectJAdvisorsBuilder#advisorsCache中,当AnnotationAwareAspectJAutoProxyCreator拦截bean的创建过程时,从这里面适配是否有切面可用。

这里解析得到的Advisor,大概有以下信息。下面的信息中,并没有对@PointCut注解做处理,pointCut属性只得出一个"mypoint()",此时还不知道Advisor实际对应的拦截表达式。

spring源码阅读--aop实现原理讲解

拦截表达式还是空的,会在AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInstantiation第一次执行时解析拦截表达式。

spring源码阅读--aop实现原理讲解

适配切面

在AbstractAutoProxyCreator#postProcessAfterInitialization执行时,找到上面AbstractAutoProxyCreator#postProcessBeforeInitialization缓存的所有的切面信息,之后是如何进行切面适配,从而决定是否需要进行代理对象的创建呢?

在调用AbstractAutoProxyCreator#postProcessAfterInitialization方法时,进行切面适配,并且会根据适配创建代理对象。根据以下调用链。

AbstractAutoProxyCreator#postProcessAfterInitialization

AbstractAutoProxyCreator#wrapIfNecessary

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
 if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
    return bean;
 }
 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    return bean;
 }
 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
 }
 // Create proxy if we have advice.
  //查找匹配切面
 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
 if (specificInterceptors != DO_NOT_PROXY) {
    this.advisedBeans.put(cacheKey, Boolean.TRUE);
     //创建代理对象
    Object proxy = createProxy(
          bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;
 }
 this.advisedBeans.put(cacheKey, Boolean.FALSE);
 return bean;
}

AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean

AbstractAdvisorAutoProxyCreator#findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  //从缓存取出所有切面信息
 List<Advisor> candidateAdvisors = findCandidateAdvisors();
  //根据advisor信息中的表达式进行方法对class的匹配
 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
 extendAdvisors(eligibleAdvisors);
 if (!eligibleAdvisors.isEmpty()) {
    eligibleAdvisors = sortAdvisors(eligibleAdvisors);
 }
 return eligibleAdvisors;
}

此时如果是第一次执行适配方法findAdvisorsThatCanApply的话,candidateAdvisors中的拦截表达式还是空的,需要进行表达式获取,也就是@Pointcut的value。spring的操作的在第一次执行findAdvisorsThatCanApply时解析获取拦截表达式的值,获得拦截表达式值之后就跟当前class的方法进行匹配看是否需要进行代理。

继续往下跟踪代码

AopUtils#canApply(org.springframework.aop.Advisor, java.lang.Class<?>, boolean)

AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)

AspectJExpressionPointcut#getClassFilter

AspectJExpressionPointcut#checkReadyToMatch

private void checkReadyToMatch() {
 if (getExpression() == null) {
    throw new IllegalStateException("Must set property 'expression' before attempting to match");
 }
 if (this.pointcutExpression == null) {
    this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
          ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
          ClassUtils.getDefaultClassLoader());
     //解析得到拦截表达式,例如根据@Before的value来关联查询出对应的表达式
    this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
 }
}

最终解析完之后,advisor中的表达式信息结构如下图。包含在pointcut属性中,匹配时就根据pointcutExpression循环进行匹配class的方法。有兴趣的可以继续调试看看是如何实现匹配表达式的。

spring源码阅读--aop实现原理讲解

##  创建代理对象

如果在上面的匹配切面过程中,发现适配的切面,那就需要进行代理对象的创建了。

我们回到上面的AbstractAutoProxyCreator#wrapIfNecessary,主要看代码如下。

// Create proxy if we have advice.
  //查找匹配切面
 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
 if (specificInterceptors != DO_NOT_PROXY) {
    this.advisedBeans.put(cacheKey, Boolean.TRUE);
     //创建代理对象  
    Object proxy = createProxy(
          bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;
 }

所以,继续看

AbstractAutoProxyCreator#createProxy

的创建代理对象方法。设置ProxyFactory创建Proxy需要的一切信息。

protected Object createProxy(
    Class<?> beanClass, String beanName, 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 (shouldProxyTargetClass(beanClass, beanName)) {
       proxyFactory.setProxyTargetClass(true);
    }
    else {
       evaluateProxyInterfaces(beanClass, proxyFactory);
    }
 }
  //设置拦截切面
 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
 for (Advisor advisor : advisors) {
    proxyFactory.addAdvisor(advisor);
 }
  //设置被代理对象
 proxyFactory.setTargetSource(targetSource);
 customizeProxyFactory(proxyFactory);
 proxyFactory.setFrozen(this.freezeProxy);
 if (advisorsPreFiltered()) {
    proxyFactory.setPreFiltered(true);
 }
//创建代理对象
 return proxyFactory.getProxy(getProxyClassLoader());
}

下面看ProxyFactory是如何创建代理对象,继续跟踪proxyFactory.getProxy(getProxyClassLoader());

public Object getProxy(ClassLoader classLoader) {
 return createAopProxy().getProxy(classLoader);
}

createAopProxy()作用是根据class的种类判断采用的代理方式,看如下实现

DefaultAopProxyFactory#createAopProxy

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
		Class<?> targetClass = config.getTargetClass();
		if (targetClass == null) {
			throw new AopConfigException("TargetSource cannot determine target class: " +
					"Either an interface or a target is required for proxy creation.");
		}
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
          //采用jdk动态代理必须基于接口
			return new JdkDynamicAopProxy(config);
		}
      //基于cglib实现代理不需要接口
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

所以在当前调试的例子中,使用cglib代理。所以执行如下代理。

@Override
public Object getProxy(ClassLoader classLoader) {
   //。。。。。。
    // Configure CGLIB Enhancer...
    Enhancer enhancer = createEnhancer();
    if (classLoader != null) {
       enhancer.setClassLoader(classLoader);
       if (classLoader instanceof SmartClassLoader &&
             ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
          enhancer.setUseCache(false);
       }
    }
    enhancer.setSuperclass(proxySuperClass);
    enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
    enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
	//获取拦截回调函数
    Callback[] callbacks = getCallbacks(rootClass);
    Class<?>[] types = new Class<?>[callbacks.length];
    for (int x = 0; x < types.length; x++) {
       types[x] = callbacks[x].getClass();
    }
    // fixedInterceptorMap only populated at this point, after getCallbacks call above
    enhancer.setCallbackFilter(new ProxyCallbackFilter(
          this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
    enhancer.setCallbackTypes(types);
    // Generate the proxy class and create a proxy instance.
  //返回一个cglib代理对象
    return createProxyClassAndInstance(enhancer, callbacks);
 }
 catch (CodeGenerationException ex) {
     //、、、、、、
 }
}

getCallbacks(rootClass);在这个获取回调函数的方法中,普通的aop采用的回调函数是如下的方式。

// Choose an "aop" interceptor (used for AOP calls).
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

cglib 的aop回调函数如下。

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
 Object oldProxy = null;
 boolean setProxyContext = false;
 Class<?> targetClass = null;
 Object target = null;
 try {
     //这里注入的advised就是之前创建的ProxyFactory对象
    if (this.advised.exposeProxy) {
       // Make invocation available if necessary.
       oldProxy = AopContext.setCurrentProxy(proxy);
       setProxyContext = true;
    }
    // May be null. Get as late as possible to minimize the time we
    // "own" the target, in case it comes from a pool...
    target = getTarget();
    if (target != null) {
       targetClass = target.getClass();
    }
     //根据切面信息创建切面内容调用链
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    Object retVal;
    // Check whether we only have one InvokerInterceptor: that is,
    // no real advice, but just reflective invocation of the target.
    if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
       // We can skip creating a MethodInvocation: just invoke the target directly.
       // Note that the final invoker must be an InvokerInterceptor, so we know
       // it does nothing but a reflective operation on the target, and no hot
       // swapping or fancy proxying.
       Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
       retVal = methodProxy.invoke(target, argsToUse);
    }
    else {
       // We need to create a method invocation...
        //创建一个方法调用对象,具体调用实现没分析,Before逻辑大概是先调用切面,在反射调用目标方法
       retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
    }
    retVal = processReturnType(proxy, target, method, retVal);
    return retVal;
 }
 finally {
    if (target != null) {
       releaseTarget(target);
    }
    if (setProxyContext) {
       // Restore old proxy.
       AopContext.setCurrentProxy(oldProxy);
    }
 }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/qq_20597727/article/details/84800176

标签:

相关文章

热门资讯

蜘蛛侠3英雄无归3正片免费播放 蜘蛛侠3在线观看免费高清完整
蜘蛛侠3英雄无归3正片免费播放 蜘蛛侠3在线观看免费高清完整 2021-08-24
yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
2021年耽改剧名单 2021要播出的59部耽改剧列表
2021年耽改剧名单 2021要播出的59部耽改剧列表 2021-03-05
返回顶部