返回介绍

7.3.1 获取增强器

发布于 2025-04-22 22:09:14 字数 18811 浏览 0 评论 0 收藏 0

由于我们分析的是使用注解进行的 AOP,所以对于 findCandidateAdvisors 的实现其实是由 AnnotationAwareAspectJAutoProxyCreator 类完成的,我们继续跟踪 AnnotationAwareAspectJAuto ProxyCreator 的 findCandidateAdvisors 方法。

@Override

protected List<Advisor> findCandidateAdvisors() {

 //当使用注解方式配置 AOP 的时候并不是丢弃了对 XML 配置的支持,

 //在这里调用父类方法加载配置文件中的 AOP 声明

  List<Advisor> advisors = super.findCandidateAdvisors();

  // Build Advisors for all AspectJ aspects in the bean factory.

 advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());

  return advisors;

}

AnnotationAwareAspectJAutoProxyCreator 间接继承了 AbstractAdvisorAutoProxyCreator,在实现获取增强的方法中除了保留父类的获取配置文件中定义的增强外,同时添加了获取 Bean 的注解增强的功能,那么其实现正是由 this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 来实现的。

在真正研究代码之前读者可以尝试着自己去想象一下解析思路,看看自己的实现与 Spring 是否有差别呢?或者我们一改以往的方式,先来了解函数提供的大概功能框架,读者可以在头脑中尝试实现这些功能点,看看是否有思路。

(1)获取所有 beanName,这一步骤中所有在 beanFacotry 中注册的 Bean 都会被提取出来。

(2)遍历所有 beanName,并找出声明 AspectJ 注解的类,进行进一步的处理。

(3)对标记为 AspectJ 注解的类进行增强器的提取。

(4)将提取结果加入缓存。

现在我们来看看函数实现,对 Spring 中所有的类进行分析,提取 Advisor。

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>();

   //获取所有的 beanName

    String[] beanNames =BeanFactoryUtils.beanNamesForTypeIncludingAncestors

    (this.beanFactory, Object.class, true, false);

   //循环所有的 beanName 找出对应的增强方法

    for (String beanName : beanNames) {

    //不合法的 bean 则略过,由子类定义规则,默认返回 true

     if (!isEligibleBean(beanName)) {

    continue;

    }

    //获取对应的 bean 的类型

     Class beanType = this.beanFactory.getType(beanName);

     if (beanType == null) {

    continue;

    }

    //如果存在 Aspect 注解

     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);

      //解析标记 AspectJ 注解中的增强方法

       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.EMPTY_LIST;

 }

 //记录在缓存中

  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;

}

至此,我们已经完成了 Advisor 的提取,在上面的步骤中最为重要也最为繁杂的就是增强器的获取。而这一功能委托给了 getAdvisors 方法去实现(this.advisorFactory.getAdvisors(factory))。

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {

 //获取标记为 AspectJ 的类

  final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();

 //获取标记为 AspectJ 的 name

  final String aspectName = maaif.getAspectMetadata().getAspectName();

 //验证

 validate(aspectClass);

  final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory

  =new LazySingletonAspectInstanceFactoryDecorator(maaif);

  final List<Advisor> advisors = new LinkedList<Advisor>();

  ReflectionUtils.doWithMethods(aspectClass, new

  ReflectionUtils.MethodCallback() {

   public void doWith(Method method) throws IllegalArgumentException {

   //声明为 Pointcut 的方法不处理

    if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {

     Advisor advisor = getAdvisor(method, lazySingletonAspectInstance

     Factory, advisors.size(), aspectName);

     if (advisor != null) {

     advisors.add(advisor);

    }

   }

  }

 });

  if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspect

  Metadata().isLazilyInstantiated()) {

  //如果寻找的增强器不为空而且又配置了增强延迟初始化那么需要在首位加入同步实例化增强器

   Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor (lazySingleton

  AspectInstanceFactory);

   advisors.add(0, instantiationAdvisor);

 }

 //获取 DeclareParents 注解

  for (Field field : aspectClass.getDeclaredFields()) {

   Advisor advisor = getDeclareParentsAdvisor(field);

   if (advisor != null) {

   advisors.add(advisor);

  }

 }

  return advisors;

}

函数中首先完成了对增强器的获取,包括获取注解以及根据注解生成增强的步骤,然后考虑到在配置中可能会将增强配置成延迟初始化,那么需要在首位加入同步实例化增强器以保证增强使用之前的实例化,最后是对 DeclareParents 注解的获取,下面将详细介绍一下每个步骤。

1.普通增强器的获取

普通增强器的获取逻辑通过 getAdvisor 方法实现,实现步骤包括对切点的注解的获取以及根据注解信息生成增强。

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif,

int declarationOrderInAspect, String aspectName) {

 validate(aif.getAspectMetadata().getAspectClass());

 //切点信息的获取

  AspectJExpressionPointcut ajexp =

  getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());

  if (ajexp == null) {

   return null;

 }

//根据切点信息生成增强器

  return new InstantiationModelAwarePointcutAdvisorImpl(

  this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect,

 aspectName);

}

(1)切点信息的获取。所谓获取切点信息就是指定注解的表达式信息的获取,如 @Before("test()")。

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?>

candidateAspectClass) {

 //获取方法上的注解

  AspectJAnnotation<?> aspectJAnnotation =

 AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod

 (candidateAdviceMethod);

  if (aspectJAnnotation == null) {

   return null;

 }

  //使用 AspectJExpressionPointcut 实例封装获取的信息

  AspectJExpressionPointcut ajexp =

  new AspectJExpressionPointcut(candidateAspectClass, new String[0],

  new Class[0]);

 //提取得到的注解中的表达式如:

 //@Pointcut("execution(* *.*test*(..))") 中的 execution(* *.*test*(..))

ajexp.setExpression(aspectJAnnotation.getPointcutExpression());

  return ajexp;

}

protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method) {

 //设置敏感的注解类

  Class<? extends Annotation>[] classesToLookFor = new Class[] {

  Before.class, Around.class, After.class, AfterReturning.class,

   AfterThrowing.class, Pointcut.class};

  for (Class<? extends Annotation> c : classesToLookFor) {

   AspectJAnnotation foundAnnotation = findAnnotation(method, c);

   if (foundAnnotation != null) {

    return foundAnnotation;

  }

 }

  return null;

}

//获取指定方法上的注解并使用 AspectJAnnotation 封装

private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method,

Class<A> toLookFor) {

  A result = AnnotationUtils.findAnnotation(method, toLookFor);

  if (result != null) {

   return new AspectJAnnotation<A>(result);

 }

  else {

   return null;

 }

}

(2)根据切点信息生成增强。所有的增强都由 Advisor 的实现类 InstantiationModelAware PointcutAdvisorImpl 统一封装的。

public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJ

ExpressionPointcut ajexp,

  MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect,

  String aspectName) {

 //test()

  this.declaredPointcut = ajexp;

  //public void test.AspectJTest.beforeTest()

  this.method = method;

  this.atAspectJAdvisorFactory = af;

  this.aspectInstanceFactory = aif;

 //0

  this.declarationOrder = declarationOrderInAspect;

 //test.AspectJTest

  this.aspectName = aspectName;

  if (aif.getAspectMetadata().isLazilyInstantiated()) {

   // Static part of the pointcut is a lazy type.

   Pointcut preInstantiationPointcut =

   Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(),

   this.declaredPointcut);

   this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut,

   preInstantiationPointcut, aif);

   this.lazy = true;

  }else {

   // A singleton aspect.

   this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);

   this.pointcut = declaredPointcut;

   this.lazy = false;

 }

}

在封装过程中只是简单地将信息封装在类的实例中,所有的信息单纯地赋值,在实例初始化的过程中还完成了对于增强器的初始化。因为不同的增强所体现的逻辑是不同的,比如 @Before(“test()”)与 @After(“test()”)标签的不同就是增强器增强的位置不同,所以就需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应的增强器就是在 instantiateAdvice 函数中实现的。

private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {

  return this.atAspectJAdvisorFactory.getAdvice(

  this.method, pcut, this.aspectInstanceFactory, this.declarationOrder,

 this.aspectName);

}

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,

MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect,

String aspectName) {

  Class<?> candidateAspectClass = aif.getAspectMetadata().getAspectClass();

 validate(candidateAspectClass);

AspectJAnnotation<?> aspectJAnnotation =

  AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod (candidate

 AdviceMethod);

if (aspectJAnnotation == null) {

  return null;

}

// If we get here, we know we have an AspectJ method.

// Check that it's an AspectJ-annotated class

if (!isAspect(candidateAspectClass)) {

  throw new AopConfigException("Advice must be declared inside an aspect type: " +

  "Offending method '" + candidateAdviceMethod + "' in class [" +

  candidateAspectClass.getName() + "]");

}

if (logger.isDebugEnabled()) {

  logger.debug("Found AspectJ method: " + candidateAdviceMethod);

}

AbstractAspectJAdvice SpringAdvice;

//根据不同的注解类型封装不同的增强器

switch (aspectJAnnotation.getAnnotationType()) {

 case AtBefore:

   SpringAdvice = newAspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);

  break;

 case AtAfter:

   SpringAdvice = newAspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);

  break;

 case AtAfterReturning:

   SpringAdvice = newAspectJAfterReturningAdvice(candidateAdviceMethod,

   ajexp, aif);

  AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.

 getAnnotation();

   if (StringUtils.hasText(afterReturningAnnotation.returning())) {

   SpringAdvice.setReturningName(afterReturningAnnotation.returning());

  }

  break;

 case AtAfterThrowing:

   SpringAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod,

   ajexp, aif);

   AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.

  getAnnotation();

   if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {

 SpringAdvice.setThrowingName(afterThrowingAnnotation.throwing());

  }

  break;

 case AtAround:

   SpringAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);

  break;

  case AtPointcut:

   if (logger.isDebugEnabled()) {

    logger.debug("Processing pointcut '" + candidateAdviceMethod.

    getName() + "'");

   }

    return null;

  default:

   throw new UnsupportedOperationException(

   "Unsupported advice type on method " + candidateAdviceMethod);

 }

  // Now to configure the advice...

 SpringAdvice.setAspectName(aspectName);

 SpringAdvice.setDeclarationOrder(declarationOrderInAspect);

  String[] argNames = this.parameterNameDiscoverer.getParameterNames (candidateAdvice

 Method);

  if (argNames != null) {

  SpringAdvice.setArgumentNamesFromStringArray(argNames);

 }

 SpringAdvice.calculateArgumentBindings();

  return SpringAdvice;

}

从函数中可以看到,Spring 会根据不同的注解生成不同的增强器,例如 AtBefore 会对应 AspectJMethodBeforeAdvice,而在 AspectJMethodBeforeAdvice 中完成了增强方法的逻辑。我们尝试分析下几个常用的增强器实现。

MethodBeforeAdviceInterceptor。

我们首先查看 MethodBeforeAdviceInterceptor 类的内部实现。

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

  private MethodBeforeAdvice advice;

 /**

  * Create a new MethodBeforeAdviceInterceptor for the given advice.

  * @param advice the MethodBeforeAdvice to wrap

  */

  public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {

   Assert.notNull(advice, "Advice must not be null");

   this.advice = advice;

 }

  public Object invoke(MethodInvocation mi) throws Throwable {

  this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );

   return mi.proceed();

 }

}

其中的属性 MethodBeforeAdvice 代表着前置增强的 AspectJMethodBeforeAdvice,跟踪 before 方法:

public void before(Method method, Object[] args, Object target) throws Throwable {

 invokeAdviceMethod(getJoinPointMatch(), null, null);

}

protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable

ex) throws Throwable {

  return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch,

  returnValue, ex));

}

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {

  Object[] actualArgs = args;

  if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {

   actualArgs = null;

 }

  try {

  ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);

  //激活增强方法

   return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory. getAspect

   Instance(), actualArgs);

 }

  catch (IllegalArgumentException ex) {

   throw new AopInvocationException("Mismatch on arguments to advice method [" +

    this.aspectJAdviceMethod + "]; pointcut expression [" +

    this.pointcut.getPointcutExpression() + "]", ex);

 }

  catch (InvocationTargetException ex) {

   throw ex.getTargetException();

 }

}

invokeAdviceMethodWithGivenArgs 方法中的 aspectJAdviceMethod 正是对于前置增强的方法,在这里实现了调用。

AspectJAfterAdvice。

后置增强与前置增强有稍许不一致的地方。回顾之前讲过的前置增强,大致的结构是在拦截器链中放置 MethodBeforeAdviceInterceptor,而在 MethodBeforeAdviceInterceptor 中又放置了 AspectJMethodBeforeAdvice,并在调用 invoke 时首先串联调用。但是在后置增强的时候却不一样,没有提供中间的类,而是直接在拦截器链中使用了中间的 AspectJAfterAdvice。

public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor,

AfterAdvice {

  public AspectJAfterAdvice(

   Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut,

   AspectInstanceFactory aif) {

  super(aspectJBeforeAdviceMethod, pointcut, aif);

 }

  public Object invoke(MethodInvocation mi) throws Throwable {

   try {

    return mi.proceed();

  }

   finally {

   //激活增强方法

   invokeAdviceMethod(getJoinPointMatch(), null, null);

  }

 }

  public boolean isBeforeAdvice() {

   return false;

 }

  public boolean isAfterAdvice() {

   return true;

 }

}

2.增加同步实例化增强器

如果寻找的增强器不为空而且又配置了增强延迟初始化,那么就需要在首位加入同步实例化增强器。同步实例化增强器 SyntheticInstantiationAdvisor 如下:

protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor {

  public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) {

   super(aif.getAspectMetadata().getPerClausePointcut(), new MethodBeforeAdvice() {

   //目标方法前调用,类似 @Before

    public void before(Method method, Object[] args, Object target) {

    //简单初始化 aspect

    aif.getAspectInstance();

   }

  });

 }

}

3.获取 DeclareParents 注解

DeclareParents 主要用于引介增强的注解形式的实现,而其实现方式与普通增强很类似,只不过使用 DeclareParentsAdvisor 对功能进行封装。

private Advisor getDeclareParentsAdvisor(Field introductionField) {

  DeclareParents declareParents = (DeclareParents) introductionField.getAnnotation

 (DeclareParents.class);

  if (declareParents == null) {

   // Not an introduction field

   return null;

 }

  if (DeclareParents.class.equals(declareParents.defaultImpl())) {

   // This is what comes back if it wasn't set. This seems bizarre...

   // TODO this restriction possibly should be relaxed

   throw new IllegalStateException("defaultImpl must be set on Declare

  Parents");

 }

  return new DeclareParentsAdvisor(

  introductionField.getType(), declareParents.value(), declareParents.

 defaultImpl());

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。