IT@程序员猿媛

【Spring 笔记】AOP 拦截器链相关整理

2020-02-13  本文已影响0人  58bc06151329

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

1. 概述

expose-proxy

<!-- spring.xml -->
<bean id="testServiceImpl" class="spring.test.aop.TestServiceImpl"/>

<aop:aspectj-autoproxy expose-proxy="true"/>
<!-- 普通 bean,包含 AOP 切面逻辑 -->
<bean id="aopTest" class="spring.test.aop.AopTest"/>

<!-- 由 @Aspect 注解修饰的切面类 -->
<bean id="annotationAopTest" class="spring.test.aop.AnnotationAopTest"/>

<aop:config expose-proxy="true">
    <aop:aspect ref="aopTest">
        <!-- pointcut -->
        <aop:pointcut id="testPointcut" expression="execution(* spring.test.aop.*.find*(..))" />

        <!-- advoce -->
        <aop:before method="before" pointcut-ref="testPointcut"/>
        <aop:after method="after" pointcut-ref="testPointcut"/>
    </aop:aspect>
</aop:config>
// TestServiceImpl.java
public class TestServiceImpl implements TestService {

    public void save(String name) {
    }

    public void update(String name) {
    }

    public void delete(String name) {
        System.out.println("TestServiceImpl`s delete");
    }

    public String findOne(String name) {
        System.out.println("TestServiceImpl`s " + name);
        return "";
    }

    public List<String> findAll() {
        System.out.println("TestServiceImpl`s findAll");
        findOne("findOne");
        return new ArrayList<String>();
    }
}

public class Test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        TestService testService = (TestService) context.getBean("testServiceImpl");
        testService.findAll();
        testService.delete("");
    }
}

/* print

AopTest`s before
TestServiceImpl`s findAll
TestServiceImpl`s findOne
AopTest`s after
AnnotationAopTest`s before
TestServiceImpl`s delete
AnnotationAopTest`s after
*/
public class TestServiceImpl implements TestService {

    public void save(String name) {
    }

    public void update(String name) {
    }

    public void delete(String name) {
        System.out.println("TestServiceImpl`s delete");
    }

    public String findOne(String name) {
        System.out.println("TestServiceImpl`s " + name);
        return "";
    }

    public List<String> findAll() {
        System.out.println("TestServiceImpl`s findAll");
        ((TestService) AopContext.currentProxy()).findOne("findOne");
        return new ArrayList<String>();
    }
}

/* print

AopTest`s before
TestServiceImpl`s findAll
AopTest`s before
TestServiceImpl`s findOne
AopTest`s after
AopTest`s after
AnnotationAopTest`s before
TestServiceImpl`s delete
AnnotationAopTest`s after
*/
Exception in thread "main" java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.

2. 原理

2.1 JdkDynamicAopProxy

AopProxy 体系
// JdkDynamicAopProxy.java
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodInvocation invocation;
    Object oldProxy = null;
    boolean setProxyContext = false;

    TargetSource targetSource = this.advised.targetSource;
    Class<?> targetClass = null;
    Object target = null;

    try {
        ......
        Object retVal;

        // 1. 如果 expose-proxy 属性为 true,则暴露代理对象
        if (this.advised.exposeProxy) {
            // 向 AopContext 中设置代理对象
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        // 2. 获取适合当前方法的拦截器
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // 3. 如果拦截器链为空,则直接执行目标方法
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            // 通过反射执行目标方法
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            // 4. 创建一个方法调用器,并将拦截器链传入其中
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 5. 执行拦截器链
            retVal = invocation.proceed();
        }

        // 6. 获取方法返回值类型
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // 如果方法返回值为 this,即 return this; 则将代理对象 proxy 赋值给 retVal 
            retVal = proxy;
        }
        // 如果返回值类型为基础类型,比如 int,long 等,当返回值为 null,抛出异常
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            throw new AopInvocationException(
                    "Null return value from advice does not match primitive return type for: " + method);
        }
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

MethodBeforeAdviceInterceptor

// MethodBeforeAdviceInterceptor.java
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
    
    /** 前置通知 */
    private 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());
        // 通过 MethodInvocation 调用下一个拦截器,若所有拦截器均执行完,则调用目标方法
        return mi.proceed();
    }
}

2.1.1 获取拦截器链

getInterceptorsAndDynamicInterceptionAdvice

// AdvisedSupport.java
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    // 2.1 从缓存中获取
    List<Object> cached = this.methodCache.get(cacheKey);
    // 缓存未命中,则进行下一步处理
    if (cached == null) {
        // 2.2 获取所有的拦截器
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this, method, targetClass);
        // 2.3 存入缓存
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

// DefaultAdvisorChainFactory.java
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, Class<?> targetClass) {

    List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    // registry 为 DefaultAdvisorAdapterRegistry 类型
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

    // 2.2.1 遍历通知器列表
    for (Advisor advisor : config.getAdvisors()) {
        if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            /*
             * 2.2.2 调用 ClassFilter 对 bean 类型进行匹配,无法匹配则说明当前通知器
             * 不适合应用在当前 bean 上
             */
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                // 将 advisor 中的 advice 转成相应的拦截器
                MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                // 通过方法匹配器对目标方法进行匹配
                if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                    // 若 isRuntime 返回 true,则表明 MethodMatcher 要在运行时做一些检测
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    }
                    else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            // IntroductionAdvisor 类型的通知器,仅需进行类级别的匹配即可
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

// DefaultAdvisorAdapterRegistry.java
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
    List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
    Advice advice = advisor.getAdvice();
    /*
     * 若 advice 是 MethodInterceptor 类型的,直接添加到 interceptors 中即可。
     * 比如 AspectJAfterAdvice 就实现了 MethodInterceptor 接口
     */
    if (advice instanceof MethodInterceptor) {
        interceptors.add((MethodInterceptor) advice);
    }

    /*
     * 2.2.3 对于 AspectJMethodBeforeAdvice 等类型的通知,由于没有实现 MethodInterceptor 
     * 接口,所以这里需要通过适配器进行转换
     */ 
    for (AdvisorAdapter adapter : this.adapters) {
        if (adapter.supportsAdvice(advice)) {
            interceptors.add(adapter.getInterceptor(advisor));
        }
    }
    if (interceptors.isEmpty()) {
        throw new UnknownAdviceTypeException(advisor.getAdvice());
    }
    return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
// MethodBeforeAdviceAdapter.java
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof MethodBeforeAdvice);
    }

    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
        // 创建 MethodBeforeAdviceInterceptor 拦截器
        return new MethodBeforeAdviceInterceptor(advice);
    }
}

2.1.2 启动拦截器链

ReflectiveMethodInvocation

// ReflectiveMethodInvocation.java
public class ReflectiveMethodInvocation implements ProxyMethodInvocation {

    private int currentInterceptorIndex = -1;

    public Object proceed() throws Throwable {
        // 拦截器链中的最后一个拦截器执行完后,即可执行目标方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            // 执行目标方法
            return invokeJoinpoint();
        }

        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            /*
             * 调用具有三个参数(3-args)的 matches 方法动态匹配目标方法,
             * 两个参数(2-args)的 matches 方法用于静态匹配
             */
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                // 调用拦截器逻辑
                return dm.interceptor.invoke(this);
            }
            else {
                // 如果匹配失败,则忽略当前的拦截器
                return proceed();
            }
        }
        else {
            // 调用拦截器逻辑,并传递 ReflectiveMethodInvocation 对象
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
}

AspectJAfterAdvice

// AspectJAfterAdvice.java
public class AspectJAfterAdvice extends AbstractAspectJAdvice
        implements MethodInterceptor, AfterAdvice, Serializable {

    public AspectJAfterAdvice(
            Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

        super(aspectJBeforeAdviceMethod, pointcut, aif);
    }


    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            // 调用 proceed
            return mi.proceed();
        }
        finally {
            // 调用后置通知逻辑
            invokeAdviceMethod(getJoinPointMatch(), null, null);
        }
    }

    //...
}
拦截器链执行流程

invokeJoinpoint

// ReflectiveMethodInvocation.java
protected Object invokeJoinpoint() throws Throwable {
    return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}

// AopUtils.java
public abstract class AopUtils {
    public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
            throws Throwable {

        try {
            ReflectionUtils.makeAccessible(method);
            // 通过反射执行目标方法
            return method.invoke(target, args);
        }
        catch (InvocationTargetException ex) {...}
        catch (IllegalArgumentException ex) {...}
        catch (IllegalAccessException ex) {...}
    }
}
上一篇下一篇

猜你喜欢

热点阅读