Java教程

Spring AOP源码详解

本文主要是介绍Spring AOP源码详解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Spring两大强大的特性就是IOC以及AOP,我们知道Spring实现AOP的过程是在SpringBean后置处理器中处理的,在Bean初始化的时候执行,我们接下来来详细看看源码是怎么做的

 生成代理对象的方法都会委托到InvocationHandler.Proxy执行,我们首先来看JdkDynamicAopProxy中invoke方法的实现

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;
        TargetSource targetSource = this.advised.targetSource;
        Object target = null;

        Class var8;
        try {
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                Boolean var18 = this.equals(args[0]);
                return var18;
            }

            if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                Integer var17 = this.hashCode();
                return var17;
            }

            if (method.getDeclaringClass() != DecoratingProxy.class) {
                Object retVal;
                if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                    retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
                    return retVal;
                }

                if (this.advised.exposeProxy) {
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }

                target = targetSource.getTarget();
                Class<?> targetClass = target != null ? target.getClass() : null;
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                if (chain.isEmpty()) {
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                } else {
                    MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                    retVal = invocation.proceed();
                }

                Class<?> returnType = method.getReturnType();
                if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                    retVal = proxy;
                } 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);
                }

                Object var12 = retVal;
                return var12;
            }

            var8 = AopProxyUtils.ultimateTargetClass(this.advised);
        } finally {
            if (target != null && !targetSource.isStatic()) {
                targetSource.releaseTarget(target);
            }

            if (setProxyContext) {
                AopContext.setCurrentProxy(oldProxy);
            }

        }

        return var8;
    }

我们只看其中几个重要的方法

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

Spring实现AOP用到了责任链模式,而这个方法的作用就是获得该链

我们可以这么理解,这条链就是用来获取用来增强目标对象的方法的集合(按照执行顺序),如果我们得到的链条为空,则直接返回原切面,返回原对象;如果有则触发拦截器链(该链)的执行。

                    MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                    retVal = invocation.proceed();

我们再来看一下proceed方法

    @Nullable
    public Object proceed() throws Throwable {
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.invokeJoinpoint();
        } else {
            Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();
                return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
            } else {
                return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
            }
        }
    }

我们都知道增强方法的链接在目标方法上的实际有五个

分别是 : 后置通知、返回通知、异常通知、环绕通知、前置通知

他们触发执行的顺序,也就是添加的顺序是

1、around

2、before

3、after

4、afterReturning

5、afterThrowing

我们的proceed方法首先会按照顺序,判断我们是否配置了相应阶段的方法,如果有,则执行当前的增强方法,如果没有,会通过递归调用的方式再次进行下一方法的判断;同时,该链上会维护一个计数,用来管理所判断的阶段。

举个例子

我们获取到拦截器链后,首先会进入around阶段的判断

1、我们首先会判断,在around阶段我怕们是否配置了相应的增强方法,此时,链的计数加一,表示即将进入下一阶段的判断。

2、如果在around处有该方法的增强实现,则执行该增强方法。

3、如果没有,递归调用proceed方法,进入下一阶段的判断

这个地方要注意,我们这里使用递归调用进入方法的判断,也就是说,每进行完一个阶段的判断以后,我们会回到拦截器链中,由拦截器告诉我们应该下一次进入那个阶段进行判断。

这里回到拦截器链的目的是因为我们在配置过程中不一定按照既定的顺序进行增强方法的配置,如果不由拦截器链来指定判断,则会发生阶段顺序错乱。

这篇关于Spring AOP源码详解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!