Spring Aop JDK动态代理实现原理分析(源码)

spring动态代理的方式有两种,本文主要是介绍jdk方式,我们另外一篇主要介绍另外一种方式,也就是cglib方式

1、spring 的aop作用

spring 的aop的动态代理都是为了给实现了接口的类做增强(必须是实现了接口),比如增加日志的功能。

2、本文对你的收获:

我们从这个文章中应该能知道生成的代理对象是什么样的;同时就能知道代理对象对象方法执行流程,

首先我们看下代理后的对象张什么样,其中ConfigInterface是我们需要代理的对象。

//这里删掉了一些不重要的方法。
package com.sun.proxy;
#ConfigInterface 用户自己的接口,需要代理的接口
public final class $Proxy23 extends Proxy implements ConfigInterface, SpringProxy, Advised, DecoratingProxy {
    private static Method m1;
    private static Method m13;
    private static Method m24;
    private static Method m21;
    private static Method m16;
  

    public $Proxy23(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }


  

    public final void haha() throws  {
        try {
            super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

   lic final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

  

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("org.springframework.mytest.ConfigInterface").getMethod("haha");
                。。。省略
         
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

看到类的签名 public final class $Proxy23 extends Proxy implements ConfigInterface, SpringProxy, Advised, DecoratingProxy

其中ConfigInterface是我自己定义的,其他都是系统的。在代理类的静态代码块,分别初始化了各个方法。其中的haha方法是用户自定义的。

我们看看haha方法。

我们发现所有的方法都有h.invoke() 我们看看这个h是什么?

这里的super是Proxy,我们看下Proxy中有没有h。

父类中还真有一个h对象,h的类型是InvocationHandler。我们所谓的增强操作就是在这个InvocationHandler接口的实现类内部实现的。我们找下spring aop中的代理对象是什么时候指定了自己的InvocationHandler。(我们把增加日志,增加事务控制叫做增强,不叫通知)

我们发现Spring aop传入的InvocationHandler 就是 对象JdkDynamicAopProxy,也就是上文中关键的对象h就是JdkDynamicAopProxy吗?。那JdkDynamicAopProxy到底是不是InvocationHandler类型呢?我们看下类JdkDynamicAopProxy的签名。

果然是的。

那我们接下来应该看看 JdkDynamicAopProxy的invoke方法。因为前面代理类中方法都执行了InvocationHandler的invoke方法。那JdkDynamicAopProxy的invoke方法到底是怎样?

先不看代码,我们想下,接下来的invoke方法中应该有些什么逻辑。

1、用户自己定义的方法需要执行;2、那些匹配的切面,我有时候又称之为增强(比如日志,事务等)需要执行,

接下来看代码。

# JdkDynamicAopProxy 
@Override
	@Nullable
	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;

		try {
			//省略一些不打紧的。
			Object retVal;

			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				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();
			}

			//省略部分
			return retVal;
		}
		
	}

这段代码首先是获取拦截器链,然后 如果拦截器链为空,则直接执行用户自己的方法(目标方法)也就是没有对方法进行增强。(一个代理类并不是所有方法都被增强,只有匹配的才会);如果拦截器不为空,则将拦截器链与目标方法,封装为一个MethodInvocation的对象。这里的拦截器可以认为是那些切面中的增强方法。

我们看下MethodInvocation的proceed方法是怎样处理这些拦截器的。MethodInvocation只是一个接口,真正的实现类是ReflectiveMethodInvocation。我们截取其proceed 方法。

从这个方法的设计上来看,包含两块,一个是调用用户的方法,另一个是拦截器方法。

下面我们盗取人家大v的一张图片。

首先从MethodInvocation的proceed方法开始,进入前置拦截器执行,前置拦截器又递归调用MethodInvocation的proceed方法。如此依次递归所有的拦截器。

注意这里要区分不同类型拦截器的设计,有点像我们数据结构里面学的二叉树的遍历(先序遍历、后序遍历、中序遍历)
下图贴出一次完整的调用栈。

然后贴出前置拦截器的内部实现。

到此为止,一个方法被增强的方法的执行流程就说完了。
可能此时你已经知道一个代理对象实现是什么样?
执行逻辑是怎么样?

但是对于如何将这里的切面变成拦截器,封装到对应的代理对象,这里并没有详细说。我们在其他博客再深入讨论。
谢谢您的阅读。

猜你喜欢

转载自blog.csdn.net/ygy982883422/article/details/105345914