JAVA的JDK动态代理实现

JAVA代理模式的类型,有动态与静态之分,而其中动态代理分为两种:JDK动态代理和CGLIB动态代理。下面是JDK动态代理的介绍。
JDK动态代理
JDK动态代理需先声明一个代理类和目标类之间的中间类,此中间类需要实现jdk中的一个接口InvocationHandler。
源码如下:

package java.lang.reflect;
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
产生代理对象的中间类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy implements InvocationHandler {
private Object target; //持有目标对象的引用
public JDKProxy(Object target){
this.target = target;
//创建代理对象
public Object createProxy(){
//1.得到目标对象的classloader
ClassLoader classLoader = target.getClass().getClassLoader();
//2.得到目标对象的实现接口的class[]
Class<?>[] interfaces = target.getClass().getInterfaces();
//3.第三个参数需要一个实现InvocationHandler接口的对象
//3-1.第一种写法,让当前类实现InvocationHandler,第三个参数写this
return Proxy.newProxyInstance(classLoader, interfaces, this);
//3-2.第二种写法,第三个参数用匿名内部类的形式,先注释掉
/*return Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
long startTime = System.currentTimeMillis();
System.out.println(""开始记录时间"");
Object ret = method.invoke(target, args); //执行目标对象方法,此处写target如果写proxy会死循环直到内存溢出
long endTime = System.currentTimeMillis();
System.out.println(""保存用户信息方法耗时"" + (endTime-startTime) + ""毫秒"");
return ret;

在代理实例上执行目标对象的方法
参数1 就是代理对象,一般不使用
参数2 它调用的方法的Method对象
参数3 调用的方法的参数

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println(""开始记录时间"");
Object ret = method.invoke(target, args);//执行目标对象方法,此处写target如果写proxy会死循环直到内存溢出
long endTime = System.currentTimeMillis();
System.out.println(""保存用户信息方法耗时"" + (endTime-startTime) + ""毫秒"");
return ret;
客户端public class ProxyTest {
@Test
public void test1() {
UserService userService = new UserServiceImpl(); //1.创建目标对象
JDKProxy factory = new JDKProxy(userService); // 2.通过JKDProxy完成代理对象创建
UserService userServiceProxy = (UserService)factory.createProxy();
userServiceProxy.saveUser(new User(""1"",""张三""));

JDK动态代理中,需要关注的两点:
1、Proxy.newProxyInstance(classLoader, interfaces, this); 底层是怎么创建的代理对象
2、invoke方法是什么时候执行的,谁来调用的此方法解析1>>怎么产生代理对象:@CallerSensitive

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException
if (h == null) {
throw new NullPointerException();
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
* Look up or generate the designated proxy class.
Class<?> cl = getProxyClass0(loader, intfs);
* Invoke its constructor with the designated invocation handler.
*/
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return newInstance(cons, ih);
} else {
return newInstance(cons, ih);
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
//继续看newInstance方法
private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
try {
return cons.newInstance(new Object[] {h} );
} catch (IllegalAccessException | InstantiationException e) {throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString());

由此可以看出创建代理对象,是利用反射,先获取目标对象的构造器,然后在通过构造反射生成代理对象解析2>>invoke方法什么时候被调用:我们通过一个工具类把生成的代理对象的字节码输出到磁盘,然后通过反编译来查看代理对象有哪些内容工具类如下:

public class ProxyGeneratorUtils {
* 把代理类的字节码写到硬盘上
* @param fileName 文件名
* @param path 路径信息
* @param clazz 目标类的接口数组
*/
public static void writeProxyClassToHardDisk(String fileName, String path, Class<?>[] clazz) {
byte[] classFile = ProxyGenerator.generateProxyClass(fileName, clazz);
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
//主方法
public static void main(String[] args) {  ProxyGeneratorUtils.writeProxyClassToHardDisk(""$JDKProxy1"",""F:/$JDKProxy1.class"",UserServiceImpl.class.getInterfaces());
}运行main方法生成代理对象字节码文件,用JD.exe反编译打开如下public final class $JDKProxy1 extends Proxy implements UserService {
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;
public $JDKProxy1(InvocationHandler arg0) throws {
super(arg0);
public final void saveUser(User arg0) throws {
try {
super.h.invoke(this, m3, new Object[]{arg0});
} catch (RuntimeException | Error arg2) {
throw arg2;
} catch (Throwable arg3) {
throw new UndeclaredThrowableException(arg3);}

代理实现的部分到这里就告一段落了,希望这个系列的解说能够让大家对JAVA掌握更多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值