spring-aop

先来看下提纲

  • AOP 概念、目标
  • AOP实现分析、源码细节
  • 示例
  • 总结

基于5.1.3.RELEASE分析

AOP 概念、目标

是什么

​ 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。

​ AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。

​ 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。(日志记录,性能统计,安全控制,事务处理,异常处理等等)

(来源百度百科)

Spring中的AOP

参考官网文档简单翻译一下

Concepts(概念)

先来了解下涉及的相关概念

Aspect (切面)

​ 关注点的模块化,跨多个类。事务管理是企业Java应用程序中横切关注的一个很好的例子。在Spring AOP中,切面是通过使用类(xml配置)或使用带有@Aspect注解的类来实现的。(通常是一个功能,一个类)

Join point(连接点)

​ 程序执行过程中的一个点,例如方法的执行或异常的处理。在Spring AOP中,切点始终代表方法的执行。(通常为需要拦截的方法)

Advice(通知)

​ 在连接点的行为, 可以简单认为是拦截器.

拦截类型

  • Before advice 执行前拦截
  • After returning advice 执行后拦截
  • After throwing advice 异常时拦截
  • After (finally) advice 返回前最终拦截
  • Around advice 自定义拦截
Pointcut(切点)

​ 简单理解为一个集合体(连接点的), 通知是面向切点,看代码好理解点

@Pointcut(value="execution(* aop.ServerImpl.*(..))")
private void pointCut(){}

@Before(value="pointCut()")
public void before(JoinPoint joinPoint){
  System.out.println("@Before前置通知:"+ Arrays.toString(joinPoint.getArgs()));
}
Target object(目标对象)

​ 连接点(需要拦截的)方法所在的类

AOP proxy(AOP代理)

​ 一个对象用于实现切面的功能(代理),在spring 中通常有两种呢实现JDK代理和CGLIB代理

Weaving(编织)

​ 完成通知(advice)和连接点(Join point)的编织, 这个动作可以在编译期(AspectJ compiler)、加载期(类加载)、运行时. SpringAOP的实现是通过动态代理的方式(运行时)

Capabilities(能力)

Spring AOP currently supports only method execution join points (advising the execution of methods on Spring beans).

Field interception is not implemented, although support for field interception could be added without breaking the core Spring AOP APIs.

If you need to advise field access and update join points, consider a language such as AspectJ.

spring AOP的粒度只支持方法级别,不支持字段级别(如果需要使用AspectJ)

goals(目标)

Spring AOP’s approach to AOP differs from that of most other AOP frameworks.

The aim is not to provide the most complete AOP implementation (although Spring AOP is quite capable).

Rather, the aim is to provide a close integration between AOP implementation and Spring IoC, to help solve common problems in enterprise applications.

目的不是提供最完整的AOP实现(尽管Spring AOP相当强大)。

相反,其目的是在AOP实现和Spring IoC之间提供紧密的集成,以帮助解决企业应用程序中的常见问题。(OOP的补充)

Packages overView(包预览)

Package Description
org.aopalliance.aop The core AOP Alliance advice marker.
org.aopalliance.intercept The AOP Alliance reflective interception abstraction.
org.springframework.aop Core Spring AOP interfaces, built on AOP Alliance AOP interoperability interfaces.
org.springframework.aop.aspectj AspectJ integration package.
org.springframework.aop.aspectj.annotation Classes enabling AspectJ 5 @Annotated classes to be used in Spring AOP.
org.springframework.aop.aspectj.autoproxy Base classes enabling auto-proxying based on AspectJ.
org.springframework.aop.config Support package for declarative AOP configuration, with XML schema being the primary configuration format.
org.springframework.aop.framework Package containing Spring’s basic AOP infrastructure, compliant with the AOP Alliance interfaces.
org.springframework.aop.framework.adapter SPI package allowing Spring AOP framework to handle arbitrary advice types.
org.springframework.aop.framework.autoproxy Bean post-processors for use in ApplicationContexts to simplify AOP usage by automatically creating AOP proxies without the need to use a ProxyFactoryBean.
org.springframework.aop.framework.autoproxy.target
org.springframework.aop.interceptor Provides miscellaneous interceptor implementations.
org.springframework.aop.scope Support for AOP-based scoping of target objects, with configurable backend.
org.springframework.aop.support Convenience classes for using Spring’s AOP API.
org.springframework.aop.support.annotation Annotation support for AOP pointcuts.
org.springframework.aop.target
org.springframework.aop.target.dynamic

AOP实现分析

​ 接下来我们来看下AOP在Spring 中是怎么实现的,我们简单分为两个方面,创建和执行

创建流程

​ 根据之前BeanFactory的分析, 我们都知道bean的创建流程. Spring AOP的实现就是通过Bean的后置通知实现的, 而在核心类 AnnotationAwareAspectJAutoProxyCreator中,它又把advisor和proxy的创建委派给其他类(ReflectiveAspectJAdvisorFactory,DefaultAopProxyFactory)

核心类预览

AnnotationAwareAspectJAutoProxyCreator类图

image-20200123210402304

需要关注的方法

  • AbstractAutoProxyCreator#wrapIfNecessary (判断是否需要包装)
  • AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean (获取通知(advices),包装为advisors)
  • AbstractAutoProxyCreator#createProxy(编织,创建代理类)
ReflectiveAspectJAdvisorFactory类图

image-20200123211728249

AspectJAdvisorFactory相关源码如下

/**
 * Interface for factories that can create Spring AOP Advisors from classes
 * annotated with AspectJ annotation syntax.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 2.0
 * @see AspectMetadata
 * @see org.aspectj.lang.reflect.AjTypeSystem
 */
public interface AspectJAdvisorFactory {

   boolean isAspect(Class<?> clazz);

   void validate(Class<?> aspectClass) throws AopConfigException;

   List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory);

   @Nullable
   Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrder, String aspectName);

   /**
    * Build a Spring AOP Advice for the given AspectJ advice method.
    * @param candidateAdviceMethod the candidate advice method
    * @param expressionPointcut the AspectJ expression pointcut
    * @param aspectInstanceFactory the aspect instance factory
    * @param declarationOrder the declaration order within the aspect
    * @param aspectName the name of the aspect
    * @return {@code null} if the method is not an AspectJ advice method
    * or if it is a pointcut that will be used by other advice but will not
    * create a Spring advice in its own right
    * @see org.springframework.aop.aspectj.AspectJAroundAdvice
    * @see org.springframework.aop.aspectj.AspectJMethodBeforeAdvice
    * @see org.springframework.aop.aspectj.AspectJAfterAdvice
    * @see org.springframework.aop.aspectj.AspectJAfterReturningAdvice
    * @see org.springframework.aop.aspectj.AspectJAfterThrowingAdvice
    */
   @Nullable
   Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName);

}
DefaultAopProxyFactory类图

image-20200123212809125

AopProxyFactory base on org.springframework.aop.framework.AdvisedSupport

public interface AopProxyFactory {

   /**
    * Create an {@link AopProxy} for the given AOP configuration.
    * @param config the AOP configuration in the form of an
    * AdvisedSupport object
    * @return the corresponding AOP proxy
    * @throws AopConfigException if the configuration is invalid
    */
   AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;

}

时序图及源码分析

我们可以创建流程分为3部分,回调类,advisor创建,代理类创建

image-20200123220926562

AnnotationAwareAspectJAutoProxyCreator执行流程

入口是AbstractAutoProxyCreator

因为实现了SmartInstantiationAwareBeanPostProcessor ,所以重写了两个方法

#postProcessBeforeInstantiation

在AspectJAwareAdvisorAutoProxyCreator#shouldSkip方法中初始化了advisor

@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 &&
            ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
         return true;
      }
   }
   return super.shouldSkip(beanClass, beanName);
}

在AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors中的调用就到了advisor的创建流程

#postProcessAfterInitialization

返回代理对象

    /**
     * Create a proxy with the configured interceptors if the bean is
     * identified as one to proxy by the subclass.
     * @see #getAdvicesAndAdvisorsForBean
     */
    @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                return 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;
     }
     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. 如果有adive创建代理
     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;
  }

​ 上面的方法简单来说做了一些判断, 主要是获取advice,并创建代理

Advisor创建流程

BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

/**
 * Look for AspectJ-annotated aspect beans in the current bean factory,
 * and return to a list of Spring AOP Advisors representing them.
 * <p>Creates a Spring Advisor for each AspectJ advice method.
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
public List<Advisor> buildAspectJAdvisors() {
   List<String> aspectNames = this.aspectBeanNames;
   //初次创建aspectNames为null,否则从缓存中获取
   if (aspectNames == null) {
     //double check
      synchronized (this) {
         aspectNames = this.aspectBeanNames;
         if (aspectNames == null) {
            List<Advisor> advisors = new ArrayList<>();
            aspectNames = new ArrayList<>();
            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                  this.beanFactory, Object.class, true, false);
            //遍历查找所有bean
            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;
               }
               //是否是Aspect的类(带了@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);
                    //获取advice的包装类advisors,并放置在缓存中 
                    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;
         }
      }
   }

  //从缓存中获取
  ...
   return advisors;
}

遍历beanFactory,找出切面(Aspect)类,获取通知(advice)的包装类(advisors)

ReflectiveAspectJAdvisorFactory#getAdvisors

  public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
     Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
     String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
     validate(aspectClass);

     // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
     // so that it will only instantiate once.
     MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
           new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

     List<Advisor> advisors = new ArrayList<>();
     for (Method method : getAdvisorMethods(aspectClass)) {
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
        if (advisor != null) { advisors.add(advisor); }
     }
     // If it's a per target aspect, emit the dummy instantiating aspect.
     ...
     // Find introduction fields.
     ...
     return advisors;
  }

    private List<Method> getAdvisorMethods(Class<?> aspectClass) {
        final List<Method> methods = new ArrayList<>();
        ReflectionUtils.doWithMethods(aspectClass, method -> {
            // Exclude pointcuts
            if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
                methods.add(method);
            }
        });
        methods.sort(METHOD_COMPARATOR);
        return methods;
    }

    @Override
    @Nullable
    public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
            int declarationOrderInAspect, String aspectName) {

        validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

        AspectJExpressionPointcut expressionPointcut = getPointcut(
                candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
        if (expressionPointcut == null) {
            return null;
        }

        return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    }

​ 所以我们可以知道Advisor 对应的类为InstantiationModelAwarePointcutAdvisorImpl

另外, 这里会有个细节就是顺序(影响后续的调用链chain的执行顺序),在getAdvisorMethods中

private static final Comparator<Method> METHOD_COMPARATOR;

static {
   Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
         new InstanceComparator<>(
               Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
         (Converter<Method, Annotation>) method -> {
            AspectJAnnotation<?> annotation =
               AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
            return (annotation != null ? annotation.getAnnotation() : null);
         });
   Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
   METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
}

​ 按照如下顺序 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 排序(从小到大),而在 AbstractAdvisorAutoProxyCreator#sortAdvisors 中会对所有通知(advice) 根据Order 再次排序(从大到小)

Proxy创建流程

在DefaultAopProxyFactory中

package org.springframework.aop.framework;
import java.io.Serializable;
import java.lang.reflect.Proxy;
import org.springframework.aop.SpringProxy;

/**
 * Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy
 * or a JDK dynamic proxy.
 *
 * <p>Creates a CGLIB proxy if one the following is true for a given
 * {@link AdvisedSupport} instance:
 * <ul>
 * <li>the {@code optimize} flag is set
 * <li>the {@code proxyTargetClass} flag is set
 * <li>no proxy interfaces have been specified
 * </ul>
 *
 * <p>In general, specify {@code proxyTargetClass} to enforce a CGLIB proxy,
 * or specify one or more interfaces to use a JDK dynamic proxy.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 12.03.2004
 * @see AdvisedSupport#setOptimize
 * @see AdvisedSupport#setProxyTargetClass
 * @see AdvisedSupport#setInterfaces
 */
@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

   @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)) {
            return new JdkDynamicAopProxy(config);
         }
         return new ObjenesisCglibAopProxy(config);
      }
      else {
         return new JdkDynamicAopProxy(config);
      }
   }

   /**
    * Determine whether the supplied {@link AdvisedSupport} has only the
    * {@link org.springframework.aop.SpringProxy} interface specified
    * (or no proxy interfaces specified at all).
    */
   private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
      Class<?>[] ifcs = config.getProxiedInterfaces();
      return (ifcs.length == 0 || 
              (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
   }

}

三种情况下使用cglib(默认使用jdk)

  • the {@code optimize} flag is set
  • the {@code proxyTargetClass} flag is set
  • no proxy interfaces have been specified

其中当targetClass 为接口或者是代理类时,使用jdk代理

执行流程

注意这里,执行流程是按照代码分析的

核心类预览

JdkDynamicAopProxy类图
image-20200123232546312
ReflectiveMethodInvocation类图
image-20200123232624501
MethodInterceptor类图

image-20200123233448201

时序图及源码分析

整个时序图流程非常简单, 首先JdkDynamicAopProxy 实现invoke,之后执行chain 调用链

image-20200123231701249

JdkDynamicAopProxy 实现了InvocationHandler(代理实现需要), 重写了invoke方法

    /**
     * Implementation of {@code InvocationHandler.invoke}.
     * <p>Callers will see exactly the exception thrown by the target,
     * unless a hook method throws an exception.
     */
    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // Get the interception chain for this method.
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            // Check whether we have any advice. If we don't, we can fallback on direct
            // reflective invocation of the target, and avoid creating a MethodInvocation.
            if (chain.isEmpty()) {
                // 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 = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                // We need to create a method invocation...
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }
        //...
    }

​ 可以发现只是简单的取出调用链,并将实际操作委派给ReflectiveMethodInvocation ,注意这里根据join PointCut,去匹配命中的方法, 找出对应的调用链

ReflectiveMethodInvocation

@Override
@Nullable
public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }

   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
      if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

依次执行dvice,即切面中的各个通知, 通过反射实现方法调用,实例是通过工厂方法创建LazySingletonAspectInstanceFactoryDecorator

org.springframework.aop.interceptor.ExposeInvocationInterceptor

org.springframework.aop.aspectj.AspectJAfterThrowingAdvice

org.springframework.aop.aspectj.AspectJAfterAdvice

org.springframework.aop.aspectj.AspectJMethodBeforeAdvice

最后用反射调用方法

简单示例

切面类

注意这里为了简单,所以只写了三个通知(advice)

package aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import java.util.Arrays;

/**
 * @author zhengyumin
 * @description 切面demo
 * @date 2020-01-22 9:46 PM
 * EnableAspectJAutoProxy 等同于xml中 <aop:aspectj-autoproxy>
 * proxyTargetClass为true时 开启cglib(比较规范是写在一个配置类里)
 */
@Aspect
@Component
@EnableAspectJAutoProxy(proxyTargetClass = false)
public class AspectInterceptor {
    @Pointcut(value="execution(* aop.ServerImpl.*(..))")
    private void pointCut(){
        //定义一个切入点 后面的通知直接引入切入点方法pointCut即可
        // ServerImpl下面的所有方法
    }
    /**
     * 前置通知(进入环绕后执行,下一步执行方法)
     * @param joinPoint
     */
    @Before(value="pointCut()")
    public void before(JoinPoint joinPoint){
        System.out.println("@Before前置通知:"+ Arrays.toString(joinPoint.getArgs()));
    }

    /**
     * 异常通知(出错时执行)
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(value="pointCut()",throwing="ex")
    public void doAfterThrow(JoinPoint joinPoint,Throwable ex){
        System.out.println("@AfterThrowing例外通知(异常通知)"+Arrays.toString(joinPoint.getArgs()));
        System.out.println("@AfterThrowing异常信息:"+ex);
    }

    /**
     * 后置通知(返回之前执行)
     */
    @After(value="pointCut()")
    public void after(){
        System.out.println("@After后置通知...");
    }

}

目标对象接口

/**
 * @author zhengyumin
 * @description target Object
 * @date 2020-01-22 9:52 PM
 */
public interface Server {
     void doSomething();
}

目标接口实现类

/**
 * @author zhengyumin
 * @description target Object Impl
 * @date 2020-01-22 9:53 PM
 */
@Component
public class ServerImpl implements Server {

    @Override
    public void doSomething() {
        System.out.println("do something.....");
    }
}

启动类

package aop;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author zhengyumin
 * @description 启动器类
 * @date 2020-01-14 9:25 PM
 * @see AspectInterceptor
 */
public class AopStarter {
    public static void main(String[] args) {
        //scan package 'aop'
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext("aop");
        //构建代理
        Server server = (Server) applicationContext.getBean("serverImpl");
        //执行拦截的方法
        server.doSomething();
    }
}

执行结果

image-20200123234554918总结

通过以上分析,我们知道了Aop的实现是通过代理的方式实现的,这里我们分为两部分讨论

一是代理类的创建

​ 代理类的创建是通过BeanPostProcess(具体子类)的回调实现的,主要是从BeanFactory中找出切面(Aspect)类,并获取类中的通知(advice), 根据配置、目标类(是否接口、代理类)决定代理方式

二是代理类执行(我们以jdk代理的分析)

​ 执行主要是实现了InvocationHandler,并按顺序执行chain调用链(advice),最后执行方法本身(join point)


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 951488791@qq.com

文章标题:spring-aop

字数:3.9k

本文作者:zhengyumin

发布时间:2020-01-23, 23:54:29

最后更新:2020-04-29, 17:02:30

原始链接:http://zyumin.github.io/2020/01/23/spring-aop/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。