22.spring系列- aop原理理解-1

本文主要分5部分

  1. AOP原理介绍
  2. 介绍AOP相关的一些类
  3. 通过源码详解aop代理的创建过程
  4. 通过源码详解aop代理的调用过程
  5. aop代理的一些特性使用案例

Spring AOP原理

原理比较简单,主要就是使用jdk动态代理和cglib代理来创建代理对象,通过代理对象来访问目标对象,而代理对象中融入了增强的代码,最终起到对目标对象增强的效果。

我们在回顾下上节我们说的几个类

连接点(JoinPoint)

public interface Joinpoint {

    /**
     * 转到拦截器链中的下一个拦截器
     */
    Object proceed() throws Throwable;

    /**
     * 返回保存当前连接点静态部分【的对象】,这里一般指被代理的目标对象
     */
    Object getThis();

    /**
     * 返回此静态连接点  一般就为当前的Method(至少目前的唯一实现是MethodInvocation,所以连接点得静态部分肯定就是本方法)
     */
    AccessibleObject getStaticPart();

}

在这里插入图片描述Invocation接口

/**
 * 此接口表示程序中的调用
 * 调用是一个连接点,可以被拦截器拦截。
 */
public interface Invocation extends Joinpoint {

    /**
     * 将参数作为数组对象获取,可以更改此数组中的元素值以更改参数。
     * 通常用来获取调用目标方法的参数
     */
    Object[] getArguments();
}

MethodInvocation接口


/**
 * 方法调用的描述,在方法调用时提供给拦截器。
 * 方法调用是一个连接点,可以被方法拦截器拦截。
 */
public interface MethodInvocation extends Invocation {

    /**
     * 返回正在被调用得方法~~~  返回的是当前Method对象。
     * 此时,效果同父类的AccessibleObject getStaticPart() 这个方法
     */
    Method getMethod();

}

ProxyMethodInvocation接口

ublic interface ProxyMethodInvocation extends MethodInvocation {

    /**
     * 获取被调用的代理对象
     */
    Object getProxy();

    /**
     * 克隆一个方法调用器MethodInvocation
     */
    MethodInvocation invocableClone();

    /**
     * 克隆一个方法调用器MethodInvocation,并为方法调用器指定参数
     */
    MethodInvocation invocableClone(Object... arguments);

    /**
     * 设置要用于此链中任何通知的后续调用的参数。
     */
    void setArguments(Object... arguments);

    /**
     * 添加一些扩展用户属性,这些属性不在AOP框架内使用。它们只是作为调用对象的一部分保留,用于特殊的拦截器。
     */
    void setUserAttribute(String key, @Nullable Object value);

    /**
     * 根据key获取对应的用户属性
     */
    @Nullable
    Object getUserAttribute(String key);

}

通俗点理解:连接点表示方法的调用过程,内部包含了方法调用过程中的所有信息,比如被调用的方法、目标、代理对象、执行拦截器链等信息。

上面定义都是一些接口,最终有2个实现。

ReflectiveMethodInvocation
当代理对象是采用jdk动态代理创建的,通过代理对象来访问目标对象的方法的时,最终过程是由ReflectiveMethodInvocation来处理的,内部会通过递归调用方法拦截器,最终会调用到目标方法。

CglibMethodInvocation
功能和上面的类似,当代理对象是采用cglib创建的,通过代理对象来访问目标对象的方法的时,最终过程是由CglibMethodInvocation来处理的,内部会通过递归调用方法拦截器,最终会调用到目标方法。

Advice

通知用来定义需要增强的逻辑。
在这里插入图片描述

通知的底层接口

public interface Advice {
}

BeforeAdvice接口

方法前置通知,内部空的

public interface BeforeAdvice extends Advice {
}

Interceptor接口

此接口表示通用拦截器

public interface Interceptor extends Advice {
}

MethodInterceptor接口

方法拦截器,所有的通知均需要转换为MethodInterceptor类型的,最终多个MethodInterceptor组成一个方法拦截器连。

@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
    /**
     * 拦截目标方法的执行,可以在这个方法内部实现需要增强的逻辑,以及主动调用目标方法
     */
    Object invoke(MethodInvocation invocation) throws Throwable;
}

AfterAdvice接口

后置通知的公共标记接口

public interface AfterAdvice extends Advice {
}

MethodBeforeAdvice接口

方法执行前通知,需要在目标方法执行前执行一些逻辑的,可以通过这个实现。


public interface MethodBeforeAdvice extends BeforeAdvice {

    /**
     * 调用目标方法之前会先调用这个before方法
     * method:需要执行的目标方法
     * args:目标方法的参数
     * target:目标对象
     */
    void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}

AfterReturningAdvice接口

方法执行后通知,需要在目标方法执行之后执行增强一些逻辑的,可以通过这个实现。

public interface AfterReturningAdvice extends AfterAdvice {

    /**
     * 目标方法执行之后会回调这个方法
     * method:需要执行的目标方法
     * args:目标方法的参数
     * target:目标对象
     */
    void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;

}

ThrowsAdvice接口

public interface ThrowsAdvice extends AfterAdvice {

}

此接口上没有任何方法,因为方法由反射调用,实现类必须实现以下形式的方法,前3个参数是可选的,最后一个参数为需要匹配的异常的类型。

void afterThrowing([Method, args, target], ThrowableSubclass);

有效方法的一些例子如下:

public void afterThrowing(Exception ex)
public void afterThrowing(RemoteException)
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)

通知包装器

负责将各种非MethodInterceptor类型的通知(Advice)包装为MethodInterceptor类型。

3个包装器类:

  • MethodBeforeAdviceInterceptor
  • AfterReturningAdviceInterceptor
  • ThrowsAdviceInterceptor

MethodBeforeAdviceInterceptor类

这个类实现了MethodInterceptor接口,负责将MethodBeforeAdvice方法前置通知包装为MethodInterceptor类型,创建这个类型的对象的时候需要传递一个MethodBeforeAdvice类型的参数,重点是invoke方法

@SuppressWarnings("serial")
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {

    private final MethodBeforeAdvice advice;

    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }


    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        //负责调用前置通知的方法
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        //继续执行方法调用链
        return mi.proceed();
    }

}

AfterReturningAdviceInterceptor类

这个类实现了MethodInterceptor接口,负责将AfterReturningAdvice方法后置通知包装为MethodInterceptor类型,创建这个类型的对象的时候需要传递一个AfterReturningAdvice类型的参数,重点是invoke方法

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {

    private final AfterReturningAdvice advice;

    public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }


    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        //先执行方法调用链,可以获取目标方法的执行结果
        Object retVal = mi.proceed();
        //执行后置通知
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        //返回结果
        return retVal;
    }

}

ThrowsAdviceInterceptor类

这个类实现了MethodInterceptor接口,负责将ThrowsAdvice异常通知包装为MethodInterceptor类型,创建这个类型的对象的时候需要传递一个Object类型的参数,通常这个参数是ThrowsAdvice类型的,重点是invoke方法

public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {

    private static final String AFTER_THROWING = "afterThrowing";

    private final Object throwsAdvice;

    //创建ThrowsAdviceInterceptor
    public ThrowsAdviceInterceptor(Object throwsAdvice) {
        Assert.notNull(throwsAdvice, "Advice must not be null");
        this.throwsAdvice = throwsAdvice;
        //获取异常通知中定义的所有方法(public、默认的、protected、private)
        Method[] methods = throwsAdvice.getClass().getMethods();
        //轮询methods
        for (Method method : methods) {
            //方法名称为afterThrowing && 方法参数为1或者4
            if (method.getName().equals(AFTER_THROWING) &&
                    (method.getParameterCount() == 1 || method.getParameterCount() == 4)) {
                //获取方法的最后一个参数类型
                Class<?> throwableParam = method.getParameterTypes()[method.getParameterCount() - 1];
                //判断方法参数类型是不是Throwable类型的
                if (Throwable.class.isAssignableFrom(throwableParam)) {
                    // 缓存异常处理方法到map中(异常类型->异常处理方法)
                    this.exceptionHandlerMap.put(throwableParam, method);
                }
            }
        }
        //如果exceptionHandlerMap,抛出异常,所以最少要有一个异常处理方法
        if (this.exceptionHandlerMap.isEmpty()) {
            throw new IllegalArgumentException(
                    "At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");
        }
    }


    /**
     * 获取异常通知中自定义的处理异常方法的数量
     */
    public int getHandlerMethodCount() {
        return this.exceptionHandlerMap.size();
    }


    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            //调用通知链
            return mi.proceed();
        }
        catch (Throwable ex) {
            //获取异常通知中自定义的处理异常的方法
            Method handlerMethod = getExceptionHandler(ex);
            //当处理的方法不为空
            if (handlerMethod != null) {
                //调用异常处理方法
                invokeHandlerMethod(mi, ex, handlerMethod);
            }
            //继续向外抛出异常
            throw ex; //@1
        }
    }

    /**
     * 获取throwsAdvice中处理exception参数指定的异常的方法
     */
    @Nullable
    private Method getExceptionHandler(Throwable exception) {
        //获取异常类型
        Class<?> exceptionClass = exception.getClass();
        //从缓存中获取异常类型对应的方法
        Method handler = this.exceptionHandlerMap.get(exceptionClass);
        //来一个循环,查询处理方法,循环条件:方法为空 && 异常类型!=Throwable
        while (handler == null && exceptionClass != Throwable.class) {
            //获取异常的父类型
            exceptionClass = exceptionClass.getSuperclass();
            //从缓存中查找异常对应的处理方法
            handler = this.exceptionHandlerMap.get(exceptionClass);
        }
        //将查找结果返回
        return handler;
    }

    //通过反射调用异常通知中的异常方法
    private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {
        //构建方法请求参数
        Object[] handlerArgs;
        //若只有1个参数,参数为:异常对象
        if (method.getParameterCount() == 1) {
            handlerArgs = new Object[] {ex};
        }
        else {
            //4个参数(方法、方法请求参数、目标对象、异常对象)
            handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};
        }
        try {
            //通过反射调用异常通知中的方法
            method.invoke(this.throwsAdvice, handlerArgs);
        }
        catch (InvocationTargetException targetEx) {
            throw targetEx.getTargetException();
        }
    }

}

从上面可以看出,异常通知,自定义处理异常的方法有几个特点:

  1. 方法名称必须为afterThrowing
  2. 方法参数必须1个或4个,最后一个参数是Throwable类型或其子类型
  3. 可以在异常处理中记录一些异常信息,这个还是比较有用的,但是注意一点目标方法抛出的异常最后还是会向外继续抛出@1

案例

先来一个类,用来模拟用户资金操作:充值、提现、查询资金余额;提现的时候余额不足的时候,会抛出异常。

public class FundsService {

    //账户余额
    private BigDecimal balance = new BigDecimal(1000);

    //模拟提现
    public BigDecimal recharge(String userName, BigDecimal price) {
        System.out.println(String.format("%s提现%s", userName, price));
        return balance.add(price);
    }

    //模拟提现
    public BigDecimal cashOut(String userName, BigDecimal price) {
        if (balance.compareTo(price) < 0) {
            throw new RuntimeException("余额不足!");
        }
        System.out.println(String.format("%s提现%s", userName, price));
        return balance.subtract(price);
    }

}

案例1:允许指定的用户进行账户操作

@Test
    public void testAOP3() {
        ProxyFactory proxyFactory = new ProxyFactory(new FundsService());
        proxyFactory.addAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                if (Objects.nonNull(args)) {
                    String userName = (String) args[0];
                    if (!"aop".equals(userName)) {
                        throw new RuntimeException(String.format("[%s]禁止访问!", userName));
                    }
                }
            }
        });
        FundsService proxy = (FundsService) proxyFactory.getProxy();
        proxy.cashOut("aop", new BigDecimal(100));
        proxy.cashOut("spring", new BigDecimal(100));
    }

运行结果:

aop提现100
java.lang.RuntimeException: [spring]禁止访问!
...

案例2:通过异常通知 记录异常

public class SendMsgThrowsAdvice implements ThrowsAdvice {

    //注意方法名称必须为afterThrowing
    public void afterThrowing(Method method, Object[] args, Object target, RuntimeException e) {
        //监控到异常后发送消息通知开发者
        System.out.println("异常警报:");
        System.out.println(String.format("method:[%s],args:[%s]", method.toGenericString(), Arrays.stream(args).collect(Collectors.toList())));
        System.out.println(e.getMessage());
        System.out.println("请尽快修复bug!");
    }
}

测试:

    @Test
    public void testAop4(){
        ProxyFactory proxyFactory = new ProxyFactory(new FundsService());
        proxyFactory.addAdvice(new SendMsgThrowsAdvice());
        FundsService proxy = (FundsService) proxyFactory.getProxy();
        proxy.cashOut("spring", new BigDecimal(10000));
    }

运行结果:

异常警报:
method:[public java.math.BigDecimal com.spring.beanAOP1.FundsService.cashOut(java.lang.String,java.math.BigDecimal)],args:[[spring, 10000]]
余额不足!
请尽快修复bug!

切入点(PointCut)相关类

通知(Advice)用来指定需要增强的逻辑,但是哪些类的哪些方法中需要使用这些通知呢?这个就是通过切入点来配置的。限于篇幅的原因,源码我就不在贴出了。大家可以看上一篇
在这里插入图片描述

顾问(Advisor)

在spring aop中,你可以将advisor理解为切面,切面中通常有2个关键信息:
(限于篇幅的原因,源码我就不在贴出了。大家可以看上一篇)

  • 需要增强的目标方法列表,这个通过切入点(Pointcut)来指定
  • 需要在目标方法中增强的逻辑,这个通过(Advice)通知来指定
    在这里插入图片描述
    下面开始2个重点工作:
  • 通过源码介绍aop中代理创建过程
  • 通过源码介绍代理方法的调用执行过程

代理创建过程源码解析

我们先拿案例的测试代码看一下

@Test
    public void testAOP3() {
        ProxyFactory proxyFactory = new ProxyFactory(new FundsService());
        proxyFactory.addAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                if (Objects.nonNull(args)) {
                    String userName = (String) args[0];
                    if (!"aop".equals(userName)) {
                        throw new RuntimeException(String.format("[%s]禁止访问!", userName));
                    }
                }
            }
        });
        FundsService proxy = (FundsService) proxyFactory.getProxy();
        proxy.cashOut("aop", new BigDecimal(100));
        proxy.cashOut("spring", new BigDecimal(100));
    }
//通过代理工厂创建代理
FundsService proxy = (FundsService) proxyFactory.getProxy();

我们把上面的代码改造一下,如下:

//1.创建代理所需参数配置(如:采用什么方式的代理、通知列表等)
AdvisedSupport advisedSupport = new AdvisedSupport();
//如:添加一个前置通知
advisedSupport.addAdvice(new MethodBeforeAdvice() {
    @Override
    public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
        String userName = (String) args[0];
        //如果不是路人的时候,抛出非法访问异常
        if (!"aop".equals(userName)) {
            throw new RuntimeException(String.format("[%s]非法访问!", userName));
        }
    }
});
//设置被代理的目标对象
FundsService target = new FundsService();
advisedSupport.setTarget(target);

//2.根据配置信息获取AopProxy对象,AopProxy用来负责创建最终的代理对象
// AopProxy接口有2个实现类(JDK动态代理、cglib代理)
// 具体最终会使用哪种方式,需要根据AdvisedSupport中指定的参数来判断
// 创建AopProxy使用了简单工厂模式
AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
//通过AopProxy工厂获取AopProxy对象
AopProxy aopProxy = aopProxyFactory.createAopProxy(advisedSupport);

//3.通过AopProxy创建代理对象
Object proxy = aopProxy.getProxy();

创建代理3大步骤

  1. 创建代理所需参数配置
  2. 根据代理参数获取AopProxy对象
  3. 通过AopProxy获取代理对象

创建代理所需参数配置

创建代理所需参数配置主要是通过AdvisedSupport这个类来做的,看一下类图,下面一个个来介绍。
在这里插入图片描述根据代理参数获取AopProxy对象

TargetClassAware接口:

比较简单的一个接口,定义了一个方法,用来获取目标对象类型。

public interface TargetClassAware {
    @Nullable
    Class<?> getTargetClass();
}

ProxyConfig类:

/**
 * 对外提供统一的代理参数配置类,以确保所有代理创建程序具有一致的属性
 */
public class ProxyConfig implements Serializable {

    // 标记是否直接对目标类进行代理,而不是通过接口产生代理
    private boolean proxyTargetClass = false;

    // 标记是否对代理进行优化。启动优化通常意味着在代理对象被创建后,增强的修改将不会生效,因此默认值为false。
    // 如果exposeProxy设置为true,即使optimize为true也会被忽略。
    private boolean optimize = false;

    // 标记是否需要阻止通过该配置创建的代理对象转换为Advised类型,默认值为false,表示代理对象可以被转换为Advised类型
    boolean opaque = false;

    // 标记代理对象是否应该被aop框架通过AopContext以ThreadLocal的形式暴露出去。
    // 当一个代理对象需要调用它自己的另外一个代理方法时,这个属性将非常有用。默认是是false,以避免不必要的拦截。
    boolean exposeProxy = false;

    // 标记该配置是否需要被冻结,如果被冻结,将不可以修改增强的配置。
    // 当我们不希望调用方修改转换成Advised对象之后的代理对象时,这个配置将非常有用。
    private boolean frozen = false;


    //省略了属性的get set方法
}

Advised接口

这个接口中定义了操作Aop代理配置的各种方法(比如指定被代理的目标对象、添加通知、添加顾问等等)。

所有由spring aop创建的代理对象默认都会实现这个接口。

public interface Advised extends TargetClassAware {

    /**
     * 返回配置是否已冻结,被冻结之后,无法修改已创建好的代理对象中的通知
     */
    boolean isFrozen();

    /**
     * 是否对目标类直接创建代理,而不是对接口创建代理,通俗点讲:如果是通过cglib创建代理,此方法返回true,否则返回false
     */
    boolean isProxyTargetClass();

    /**
     * 获取配置中需要代理的接口列表
     */
    Class<?>[] getProxiedInterfaces();

    /**
     * 判断某个接口是否被代理
     */
    boolean isInterfaceProxied(Class<?> intf);

    /**
     * 设置被代理的目标源,创建代理的时候,通常需要传入被代理的对象,最终被代理的对象会被包装为TargetSource类型的
     */
    void setTargetSource(TargetSource targetSource);

    /**
     * 返回被代理的目标源
     */
    TargetSource getTargetSource();

    /**
     * 设置是否需要将代理暴露在ThreadLocal中,这样可以在线程中获取到被代理对象,这个配置挺有用的,稍后会举例说明使用场景
     */
    void setExposeProxy(boolean exposeProxy);

    /**
     * 返回exposeProxy
     */
    boolean isExposeProxy();

    /**
     * 设置此代理配置是否经过预筛选,以便它只包含适用的顾问(匹配此代理的目标类)。
     * 默认设置是“假”。如果已经对advisor进行了预先筛选,则将其设置为“true”
     * 这意味着在为代理调用构建实际的advisor链时可以跳过ClassFilter检查。
     */
    void setPreFiltered(boolean preFiltered);

    /**
     * 返回preFiltered
     */
    boolean isPreFiltered();

    /**
     * 返回代理配置中干掉所有Advisor列表
     */
    Advisor[] getAdvisors();

    /**
     * 添加一个Advisor
     */
    void addAdvisor(Advisor advisor) throws AopConfigException;

    /**
     * 指定的位置添加一个Advisor
     */
    void addAdvisor(int pos, Advisor advisor) throws AopConfigException;

    /**
     * 移除一个Advisor
     */
    boolean removeAdvisor(Advisor advisor);

    /**
     * 移除指定位置的Advisor
     */
    void removeAdvisor(int index) throws AopConfigException;

    /**
     * 查找某个Advisor的位置
     */
    int indexOf(Advisor advisor);

    /**
     * 对advisor列表中的a替换为b
     */
    boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;

    /**
     * 添加一个通知
     */
    void addAdvice(Advice advice) throws AopConfigException;

    /**
     * 向指定的位置添加一个通知
     */
    void addAdvice(int pos, Advice advice) throws AopConfigException;

    /**
     * 移除一个通知
     */
    boolean removeAdvice(Advice advice);

    /**
     * 获取通知的位置
     */
    int indexOf(Advice advice);

    /**
     * 将代理配置转换为字符串,这个方便排错和调试使用的
     */
    String toProxyConfigString();

}

AdvisedSupport类

这个类是个重点,AOP代理配置管理器的基类,继承了ProxyConfig并且实现了Advised接口,创建aop代理之前,所有需要配置的信息都是通过这个类来操作的。

比如:设置是否为目标类创建代理、设置目标对象、配置通知列表等等。

public class AdvisedSupport extends ProxyConfig implements Advised {

    public static final TargetSource EMPTY_TARGET_SOURCE = EmptyTargetSource.INSTANCE;

    TargetSource targetSource = EMPTY_TARGET_SOURCE;

    /** 建议器是否已经针对特定的目标类进行筛选 */
    private boolean preFiltered = false;

    /** 调用链工厂,用来获取目标方法的调用链 */
    AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();

    /** 方法调用链缓存:以方法为键,以顾问链表为值的缓存。 */
    private transient Map<MethodCacheKey, List<Object>> methodCache;

    //代理对象需要实现的接口列表。保存在列表中以保持注册的顺序,以创建具有指定接口顺序的JDK代理。
    private List<Class<?>> interfaces = new ArrayList<>();

    //配置的顾问列表。所有添加的Advise对象都会被包装为Advisor对象
    private List<Advisor> advisors = new ArrayList<>();

    //数组更新了对advisor列表的更改,这更容易在内部操作。
    private Advisor[] advisorArray = new Advisor[0];


    //无参构造方法
    public AdvisedSupport() {
        this.methodCache = new ConcurrentHashMap<>(32);
    }

    //有参构造方法,参数为:代理需要实现的接口列表
    public AdvisedSupport(Class<?>... interfaces) {
        this();
        setInterfaces(interfaces);
    }

    //设置需要被代理的目标对象,目标对象会被包装为TargetSource格式的对象
    public void setTarget(Object target) {
        setTargetSource(new SingletonTargetSource(target));
    }

    //设置被代理的目标源
    @Override
    public void setTargetSource(@Nullable TargetSource targetSource) {
        this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
    }

    //获取被代理的目标源
    @Override
    public TargetSource getTargetSource() {
        return this.targetSource;
    }

    //设置被代理的目标类
    public void setTargetClass(@Nullable Class<?> targetClass) {
        this.targetSource = EmptyTargetSource.forClass(targetClass);
    }

    //获取被代理的目标类型
    @Override
    @Nullable
    public Class<?> getTargetClass() {
        return this.targetSource.getTargetClass();
    }

    /** 
     * 设置此代理配置是否经过预筛选,这个什么意思呢:通过目标方法调用代理的时候,
     * 需要通过匹配的方式获取这个方法上的调用链列表,查找过程需要2个步骤:
     * 第一步:类是否匹配,第二步:方法是否匹配,当这个属性为true的时候,会直接跳过第一步,这个懂了不
     */
    @Override
    public void setPreFiltered(boolean preFiltered) {
        this.preFiltered = preFiltered;
    }

    // 返回preFiltered
    @Override
    public boolean isPreFiltered() {
        return this.preFiltered;
    }

    /**
     * 设置顾问链工厂,当调用目标方法的时候,需要获取这个方法上匹配的Advisor列表,
     * 获取目标方法上匹配的Advisor列表的功能就是AdvisorChainFactory来负责的
     */
    public void setAdvisorChainFactory(AdvisorChainFactory advisorChainFactory) {
        Assert.notNull(advisorChainFactory, "AdvisorChainFactory must not be null");
        this.advisorChainFactory = advisorChainFactory;
    }

    // 返回顾问链工厂对象
    public AdvisorChainFactory getAdvisorChainFactory() {
        return this.advisorChainFactory;
    }


    //设置代理对象需要实现的接口
    public void setInterfaces(Class<?>... interfaces) {
        Assert.notNull(interfaces, "Interfaces must not be null");
        this.interfaces.clear();
        for (Class<?> ifc : interfaces) {
            addInterface(ifc);
        }
    }

    //为代理对象添加需要实现的接口
    public void addInterface(Class<?> intf) {
        Assert.notNull(intf, "Interface must not be null");
        if (!intf.isInterface()) {
            throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
        }
        if (!this.interfaces.contains(intf)) {
            this.interfaces.add(intf);
            adviceChanged();
        }
    }

    //移除代理对象需要实现的接口
    public boolean removeInterface(Class<?> intf) {
        return this.interfaces.remove(intf);
    }

    //获取代理对象需要实现的接口列表
    @Override
    public Class<?>[] getProxiedInterfaces() {
        return ClassUtils.toClassArray(this.interfaces);
    }

    //判断代理对象是否需要实现某个接口
    @Override
    public boolean isInterfaceProxied(Class<?> intf) {
        for (Class<?> proxyIntf : this.interfaces) {
            if (intf.isAssignableFrom(proxyIntf)) {
                return true;
            }
        }
        return false;
    }

    //获取配置的所有顾问列表
    @Override
    public final Advisor[] getAdvisors() {
        return this.advisorArray;
    }

    //添加顾问
    @Override
    public void addAdvisor(Advisor advisor) {
        int pos = this.advisors.size();
        addAdvisor(pos, advisor);
    }

    //指定的位置添加顾问
    @Override
    public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
        //这块先忽略,以后讲解
        if (advisor instanceof IntroductionAdvisor) {
            validateIntroductionAdvisor((IntroductionAdvisor) advisor);
        }
        addAdvisorInternal(pos, advisor);
    }

    //移除指定的顾问
    @Override
    public boolean removeAdvisor(Advisor advisor) {
        int index = indexOf(advisor);
        if (index == -1) {
            return false;
        }
        else {
            removeAdvisor(index);
            return true;
        }
    }

    //移除指定位置的顾问
    @Override
    public void removeAdvisor(int index) throws AopConfigException {
        //当配置如果是冻结状态,是不允许对顾问进行修改的,否则会抛出异常
        if (isFrozen()) {
            throw new AopConfigException("Cannot remove Advisor: Configuration is frozen.");
        }
        if (index < 0 || index > this.advisors.size() - 1) {
            throw new AopConfigException("Advisor index " + index + " is out of bounds: " +
                    "This configuration only has " + this.advisors.size() + " advisors.");
        }
        //移除advisors中的顾问
        Advisor advisor = this.advisors.remove(index);
        if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            // We need to remove introduction interfaces.
            for (Class<?> ifc : ia.getInterfaces()) {
                removeInterface(ifc);
            }
        }
        //更新advisorArray
        updateAdvisorArray();
        //通知已改变,内部会清除方法调用链缓存信息。
        adviceChanged();
    }

    @Override
    public int indexOf(Advisor advisor) {
        Assert.notNull(advisor, "Advisor must not be null");
        return this.advisors.indexOf(advisor);
    }

    @Override
    public boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException {
        Assert.notNull(a, "Advisor a must not be null");
        Assert.notNull(b, "Advisor b must not be null");
        int index = indexOf(a);
        if (index == -1) {
            return false;
        }
        removeAdvisor(index);
        addAdvisor(index, b);
        return true;
    }

    //批量添加顾问
    public void addAdvisors(Advisor... advisors) {
        addAdvisors(Arrays.asList(advisors));
    }

    //批量添加顾问
    public void addAdvisors(Collection<Advisor> advisors) {
        //配置如果是冻结状态,会抛出异常
        if (isFrozen()) {
            throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
        }
        if (!CollectionUtils.isEmpty(advisors)) {
            for (Advisor advisor : advisors) {
                if (advisor instanceof IntroductionAdvisor) {
                    validateIntroductionAdvisor((IntroductionAdvisor) advisor);
                }
                Assert.notNull(advisor, "Advisor must not be null");
                this.advisors.add(advisor);
            }
            updateAdvisorArray();
            adviceChanged();
        }
    }

    //此方法先忽略,用来为目标类引入接口的
    private void validateIntroductionAdvisor(IntroductionAdvisor advisor) {
        advisor.validateInterfaces();
        // If the advisor passed validation, we can make the change.
        Class<?>[] ifcs = advisor.getInterfaces();
        for (Class<?> ifc : ifcs) {
            addInterface(ifc);
        }
    }

    //指定的位置添加顾问
    private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
        Assert.notNull(advisor, "Advisor must not be null");
        if (isFrozen()) {
            throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
        }
        if (pos > this.advisors.size()) {
            throw new IllegalArgumentException(
                    "Illegal position " + pos + " in advisor list with size " + this.advisors.size());
        }
        this.advisors.add(pos, advisor);
        updateAdvisorArray();
        adviceChanged();
    }

    //将advisorArray和advisors保持一致
    protected final void updateAdvisorArray() {
        this.advisorArray = this.advisors.toArray(new Advisor[0]);
    }

    //获取顾问列表
    protected final List<Advisor> getAdvisorsInternal() {
        return this.advisors;
    }

    //添加通知
    @Override
    public void addAdvice(Advice advice) throws AopConfigException {
        int pos = this.advisors.size();
        addAdvice(pos, advice);
    }

    //指定的位置添加通知
    @Override
    public void addAdvice(int pos, Advice advice) throws AopConfigException {
        //此处会将advice通知包装为DefaultPointcutAdvisor类型的Advisor
        addAdvisor(pos, new DefaultPointcutAdvisor(advice));
    }

    //移除通知
    @Override
    public boolean removeAdvice(Advice advice) throws AopConfigException {
        int index = indexOf(advice);
        if (index == -1) {
            return false;
        }
        else {
            removeAdvisor(index);
            return true;
        }
    }

    //获取通知的位置
    @Override
    public int indexOf(Advice advice) {
        Assert.notNull(advice, "Advice must not be null");
        for (int i = 0; i < this.advisors.size(); i++) {
            Advisor advisor = this.advisors.get(i);
            if (advisor.getAdvice() == advice) {
                return i;
            }
        }
        return -1;
    }

    //是否包含某个通知
    public boolean adviceIncluded(@Nullable Advice advice) {
        if (advice != null) {
            for (Advisor advisor : this.advisors) {
                if (advisor.getAdvice() == advice) {
                    return true;
                }
            }
        }
        return false;
    }

    //获取当前配置中某种类型通知的数量
    public int countAdvicesOfType(@Nullable Class<?> adviceClass) {
        int count = 0;
        if (adviceClass != null) {
            for (Advisor advisor : this.advisors) {
                if (adviceClass.isInstance(advisor.getAdvice())) {
                    count++;
                }
            }
        }
        return count;
    }


    //基于当前配置,获取给定方法的方法调用链列表(即org.aopalliance.intercept.MethodInterceptor对象列表)
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
        MethodCacheKey cacheKey = new MethodCacheKey(method);
        //先从缓存中获取
        List<Object> cached = this.methodCache.get(cacheKey);
        //缓存中没有时,从advisorChainFactory中获取
        if (cached == null) {
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                    this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        return cached;
    }

    //通知更改时调用,会清空当前方法调用链缓存
    protected void adviceChanged() {
        this.methodCache.clear();
    }

    //将other中的配置信息复制到当前对象中
    protected void copyConfigurationFrom(AdvisedSupport other) {
        copyConfigurationFrom(other, other.targetSource, new ArrayList<>(other.advisors));
    }

    //将other中的配置信息复制到当前对象中
    protected void copyConfigurationFrom(AdvisedSupport other, TargetSource targetSource, List<Advisor> advisors) {
        copyFrom(other);
        this.targetSource = targetSource;
        this.advisorChainFactory = other.advisorChainFactory;
        this.interfaces = new ArrayList<>(other.interfaces);
        for (Advisor advisor : advisors) {
            if (advisor instanceof IntroductionAdvisor) {
                validateIntroductionAdvisor((IntroductionAdvisor) advisor);
            }
            Assert.notNull(advisor, "Advisor must not be null");
            this.advisors.add(advisor);
        }
        updateAdvisorArray();
        adviceChanged();
    }

    //构建此AdvisedSupport的仅配置副本,替换TargetSource。
    AdvisedSupport getConfigurationOnlyCopy() {
        AdvisedSupport copy = new AdvisedSupport();
        copy.copyFrom(this);
        copy.targetSource = EmptyTargetSource.forClass(getTargetClass(), getTargetSource().isStatic());
        copy.advisorChainFactory = this.advisorChainFactory;
        copy.interfaces = this.interfaces;
        copy.advisors = this.advisors;
        copy.updateAdvisorArray();
        return copy;
    }
}

上面几个类有几个结论,这里说一下:

  • 配置中添加的Advice对象最终都会被转换为DefaultPointcutAdvisor对象,此时DefaultPointcutAdvisor未指定pointcut,大家可以去看一下DefaultPointcutAdvisor中pointcut有个默认值,默认会匹配任意类的任意方法。
  • 当配置被冻结的时候,即frozen为true的时,此时配置中的Advisor列表是不允许修改的。
  • 上面的getInterceptorsAndDynamicInterceptionAdvice方法,通过代理调用目标方法的时候,最后需要通过方法和目标类的类型,从当前配置中会获取匹配的方法拦截器列表,获取方法拦截器列表是由AdvisorChainFactory负责的。getInterceptorsAndDynamicInterceptionAdvice会在调用代理的方法时会执行,稍后在执行阶段会详解。
  • 目标方法和其关联的方法拦截器列表会被缓存在methodCache中,当顾问列表有变化的时候,methodCache缓存会被清除。

配置阶段完成之后,下面进入AopProxy获取阶段。

由于篇幅原因,我们下一章再说。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值