jdk动态代理-实现原理和源码分析

128 阅读2分钟

前言

动态代理的作用和本质是拦截器,和servlet的拦截器、spring的mvc 控制器拦截器和aop拦截器是一样的作用。

只不过不同拦截器的底层实现不一样,aop拦截器就是基于jdk动态代理。

jdk动态代理有2种实现方法
1.jdk自带的动态代理
必须是接口
2.第三方库cglib
支持非接口,即实现类

demo

总共有3个类

接口

目标类的接口

package proxy;

/**
 * 目标类的接口,jdk动态代理的类一定要实现某一个接口
 */
public interface User {
	void sayHello();
}


实现类

目标类的实现类

package proxy;

/**
 * 目标对象的具体类
 */
public class UserImpl implements User {
	@Override
	public void sayHello() {
		System.out.println("hello");
	}
}


拦截器

1.如何使用?
拦截器类需要继承InvocationHandler。

2.实现代码

package proxy;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 每个代理对象 内部都有一个实现了InvocationHandler接口的 类的实例
 *
 * InvocationHandler 顾名思义就是 代理对象的方法调用的处理类(调用它的invoke方法)
 *
 */
public class InvocationHandlerImpl implements InvocationHandler {
	// 目标对象
	private Object target; //接口实现类

	public InvocationHandlerImpl(Object target) {
		this.target = target;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 代理方法简单地打下日志,这其实就是spring aop的简单实现
		System.out.println("start");

		// 调用目标对象的实际方法
		Object result = method.invoke(target, args);

		System.out.println("end");

		return  result;
	}

	/**
	 * 通过Proxy.newProxyInstance 生成代理对象(重要的方法)
	 */
	public Object getProxy() {
		return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
				target.getClass().getInterfaces(), this); //创建代理类的核心代码
	}

	public static void main(String[] args) {
		// 实例化目标对象
		User user = new UserImpl();

		// 用目标对象实例化InvocationHandler
		InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(user);

		// 生成代理对象
		User proxyUser = (User) invocationHandler.getProxy();

		// 调用代理对象的方法,实际上就是调用了invocationHandler的invoke方法
		proxyUser.sayHello();
	}
}


3.底层原理
作用是拦截目标类的方法。

具体的实现是,通过生成接口实现类的代理类来拦截的。

那代理类又是怎么生成的呢?基于jdk的动态代理技术,其实就是反射包里的Proxy类。

4.拦截器的作用
拦截业务类的业务方法,然后
1.前置业务
2.业务类的业务方法
3.后置业务

运行结果

start //拦截器的前置业务
hello //业务类的业务方法
end //拦截器的后置业务

源码分析

生成代理类的核心代码,这是应用层。


源码层

jdk源码注释更详细见参考里的链接。

为什么jdk自带的动态代理必须是接口?

jdk自带的动态代理只支持接口,为什么?

代理类

代理类的类文件是动态生成的(动态生成的意思是运行时生成的),生成的结果就是一个类文件,名字是$Proxy0.class。

类文件里面的核心代码是,调用InvocationHandler实现类(即拦截器)的方法。

参考

jdk8和低版本jdk的实现有点不一样

juejin.cn/post/693008… //jdk8

www.iteye.com/blog/rejoy-… //低版本jdk