Spring AOP动态代理实现源码解析

写在AOP之前

一、静态代理和动态代理

静态代理:在编译期生成.class字节码文件

动态代理:在运行时运用反射机制动态创建

1)静态代理:

目标对象和代理对象需要实现相同的接口

代理对象需要持有目标对象(一般是目标对象实现的接口)

2)动态代理

JDK动态代理:

Proxy.NewProxyInstance()

InvocationHandler接口

CGLIB动态代理:

实现MethodInterceptor接口,重写intercept方法

Spring AOP源码解析

入口:

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)

至此,注册了AnnotationAwareAspectJAutoProxyCreator到容器中。

可以看到,AnnotationAwareAspectJAutoProxyCreator是一个BeanPostProcessor后置处理器,并且实现了Ordered接口

它的父类AbstractAutoProxyCreator重写了postProcessBeforeInitialization和postProcessAfterInitialization方法

随后容器会自动注册这个BeanPostProcessor。

接下来,在初始化Bean的时候,会调用这个BeanPostProcessor的初始化后处理

然后进到AbstractBeanFactory的getBean()方法,最终进到Bean的初始化方法

在这里进行BeanPostProcessor后置处理

调用AbstractAutoProxyCreator的postProcessAfterInitialization方法

获取所有的Advisor

遍历,找出@Aspect注解的Bean

获取以上Bean里的所有Advisor,方法和Advisor一对一

方法1获取类里所有的没有@Pointcut注解的Method(可能包含普通的方法),可能是以下几种:

  1. @Before
  2. @Aroud
  3. @After
  4. @AfterReturing
  5. @AfterThrowing

方法2获取以上通知方法的expressionPointcut 切点表达式(普通方法会被过滤掉)

方法getPointcut():

初始化一个增强器

根据不同的通知类型,创建不同的增强器

遍历所有的Advisors,是否有任意的Advisors的切点matches(当前的bean)。筛选出所有matches的Advisor

注:此处是动态代理的核心!!!

方法1:检查目标对象是否实现了接口,如果是则调用proxyFactory.addInterface(ifc);方法,这样在后面的判断hasNoUserSuppliedProxyInterfaces(config)时就为false

如果否则设置proxyTargetClass属性为true(只有在proxyTargetClass=false的情况下才会进到此方法)

方法2:生成代理对象

动态代理选择的判断逻辑:

平时我们说AOP原理三句话就能概括:

1.对类生成代理使用CGLIB

2.对接口生成代理使用JDK原生的Proxy

3.可以通过配置文件指定对接口使用CGLIB生成代理(配置proxy-target-class=true)

这三句话的出处就是createAopProxy方法。

默认使用JDK自带的Proxy生成代理,碰到以下三种情况例外:

1.ProxyConfig的isOptimize方法为true,这表示让Spring自己去优化而不是用户指定

2.ProxyConfig的isProxyTargetClass方法为true,这表示配置了proxy-target-class="true"

3.ProxyConfig满足hasNoUserSuppliedProxyInterfaces方法执行结果为true,这表示<bean>对象没有实现任何接口或者实现的接口是SpringProxy接口

注:SpringBoot的AOP是自动开启的(spring.aop.auto = true)

可配置spring.aop.proxy-target-class = true强制使用CGLIB动态代理

接下来创建代理对象

Proxy.newProxyInstance()方法是执行的关键,有三个参数:

ClassLoader loader,

Class<?>[] interfaces,

InvocationHandler h

底层实际是调用InvocationHandler.invoke()方法,在这里,也就是调用JdkDynamicAopProxy.invoke()方法。

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;

        // 如果 expose-proxy 属性为 true,则暴露代理对象

        if (this.advised.exposeProxy) {

            // 向 AopContext 中设置代理对象

            oldProxy = AopContext.setCurrentProxy(proxy);

            setProxyContext = true;

        }

        // 获取适合当前方法的拦截器

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

        // 如果拦截器链为空,则直接执行目标方法

        if (chain.isEmpty()) {

            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);

            // 通过反射执行目标方法

            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);

        }

        else {

            // 创建一个方法调用器,并将拦截器链传入其中

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

            // 如果方法返回值为 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);

        }

    }

}

invoke方法主要逻辑如下:

1. 检测 expose-proxy 是否为 true,若为 true,则暴露代理对象

2. 获取适合当前方法的拦截器链

3. 如果拦截器链为空,则直接通过反射执行目标方法

4. 若拦截器链不为空,则创建方法调用器 ReflectiveMethodInvocation 对象

5. 调用 ReflectiveMethodInvocation 对象的 proceed() 方法启动拦截器链

6. 处理返回值,并返回该值

看下以上的步骤2的代码:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {

    MethodCacheKey cacheKey = new MethodCacheKey(method);

    // 从缓存中获取

    List<Object> cached = this.methodCache.get(cacheKey);

    // 缓存未命中,则进行下一步处理

    if (cached == null) {

        // 获取所有的拦截器

        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(

                this, method, targetClass);

        // 存入缓存

        this.methodCache.put(cacheKey, cached);

    }

    return cached;

}

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

    // 遍历通知器列表

    for (Advisor advisor : config.getAdvisors()) {

        if (advisor instanceof PointcutAdvisor) {

            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;

            /*

             * 调用 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;

}

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

    }

    /*

     * 对于 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()]);

}

以上代码逻辑总结如下:

1. 从缓存中获取当前方法的拦截器链

2. 若缓存未命中,则调用 getInterceptorsAndDynamicInterceptionAdvice 获取拦截器链

3. 遍历通知器列表

4. 对于 PointcutAdvisor 类型的通知器,这里要调用通知器所持有的切点(Pointcut)对类和方法进行匹配,匹配成功说明应向当前方法织入通知逻辑

5. 调用 getInterceptors 方法对非 MethodInterceptor 类型的通知进行转换(如:@Before @AfterReturning @AfterThrowing)

6. 返回拦截器数组,并在随后存入缓存中

接下来就是调用 ReflectiveMethodInvocation 对象的 proceed() 方法启动拦截器链

interceptorOrInterceptionAdvice).invoke(this);

这里会先执行一个默认MethodInterceptor的invoke()方法,即ExposeInvocationInterceptor

然后递归调用ReflectiveMethodInvocation.proceed()方法,以@Before前置通知为例:

此时这里调用的是MethodBeforeAdviceInterceptor.invoke()方法

先执行前置通知切面逻辑,然后递归调用下一个拦截器的invoke()方法

最终,通过反射调用执行织入的通知逻辑

至此,JDK动态代理源码分析完毕。

注:JDK动态代理字节码文件分析

测试类:

生成的字节码文件:

附:不同的Aspect和Advice的执行顺序

https://blog.csdn.net/qq_32331073/article/details/80596084

CGLIB动态代理

入口:

主流程:

核心逻辑:

方法执行的时候,实际上是回调的CglibAopProxy.DynamicAdvisedInterceptor.intercept()方法。

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object oldProxy = null;
			boolean setProxyContext = false;
			Object target = null;
			TargetSource targetSource = this.advised.getTargetSource();
			try {
				if (this.advised.exposeProxy) {
					// Make invocation available if necessary.
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}
				// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
				target = targetSource.getTarget();
				Class<?> targetClass = (target != null ? target.getClass() : null);
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
				Object retVal;
				// Check whether we only have one InvokerInterceptor: that is,
				// no real advice, but just reflective invocation of the target.
				if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
					// 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 = methodProxy.invoke(target, argsToUse);
				}
				else {
					// We need to create a method invocation...
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null && !targetSource.isStatic()) {
					targetSource.releaseTarget(target);
				}
				if (setProxyContext) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

逻辑和JDK动态代理基本一致:

1. 检测 expose-proxy 是否为 true,若为 true,则暴露代理对象

2. 获取适合当前方法的拦截器链

3. 如果拦截器链为空并且该方法是public修饰的,则直接通过反射执行目标方法

4. 若拦截器链不为空,则创建方法调用器 CglibMethodInvocation 对象

5. 调用 CglibMethodInvocation 对象的 proceed() 方法启动拦截器链

6. 处理返回值,并返回该值

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章