至于jdk的动态代理怎么用此处并不多说,现在是更深一步的理解,jdk的Proxy类到底做了什么。

Proxy.newProxyInstance可以生成代理类,此方法有三个参数(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)分别是类加载器,接口数组,InvocationHandler的实现类。

简而言之,Proxy通过newProxyInstance方法生成了一个实现了第二个参数所有接口的实现类,并且内部组合了一个InvocationHandler h,当调用代理类实现的接口(第二个参数)中的方法时,该方法调用InvocationHandler 接口中的invoke方法,把自身作为第一个参数,该方法的Method对象作为第二个参数,该方法的所有参数以Object数组的形式作为第三个参数传递过去,用户可以回调invoke方法,因此自己实现类里的invoke方法的到了调用。

下面是一个自己写的MyProxy.

package com.shalf.myproxy;

public interface Animal {
public void breathe();
}

package com.shalf.myproxy;

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

public class Client {
public static void main(String[] args) {
Animal dog = new Dog();
// 使用JDK的java.lang.reflect.Proxy生成代理实例
Animal dogProxy = (Animal) Proxy.newProxyInstance(dog.getClass().getClassLoader(), dog.getClass().getInterfaces(), new ProxyInvoke(dog));
dogProxy.breathe();

System.out.println("---------------优美的分割线在此卖萌---------------");

// 使用自己的代理类生成代理实例
// 需要注意的是这里的MyProxy类和JDK中java.lang.reflect.Proxy并不相同。只是他们的原理大致相同,实现的细节并不同。JDK中生成$Proxy1并不是拼字符串,而是直接生成二进制码。
Animal myDogProxy = (Animal) MyProxy.newProxyInstance(dog.getClass().getClassLoader(), Animal.class, new ProxyInvoke(dog));
myDogProxy.breathe();

// System.out.println(System.getProperty("user.dir"));
// System.out.println(Class.class.getClass().getResource("/").getPath());
}
}

/**
* 此类并不是代理类,只是根据这个类生成代理类,生成的代理类引用InvocationHandler实例的invoke方法,属于回调函数。
*
* @author shalf
*
*/
class ProxyInvoke implements InvocationHandler {

private final Object obj;

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("DogProxy.invoke()");
return method.invoke(obj, args);
}

public ProxyInvoke(Object obj) {
super();
this.obj = obj;
}
}

package com.shalf.myproxy;

public class Dog implements Animal {

@Override
public void breathe() {
System.out.println("Dog.breathe()");
}

}

package com.shalf.myproxy;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class MyProxy {

private static String filePath = System.getProperty("user.dir") + "/src/";
// private static String packageName = MyProxy.class.getPackage().getName();
private static String name = "$Proxy1";
private static String fileName = filePath+ name + ".java";

public static Object newProxyInstance(ClassLoader loader, Class<?> infce, InvocationHandler h) {
Object obj = null;
try {
// 创建源文件
String src = createClass(infce);
// 写到文件
toFile(src);
// 编译文件
compileFile();
// 获得实例
obj = getInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}

/**
* 创建类的代码 方法最核心的代码,h是构造$Proxy1时传入的handler,本例中就是DogProxy对象
* 从而达到我们最初要在move方法前加日志逻辑的的目的
* 下面要做的就是把我们拼好的字符串生成类并load到内存就可以了这样就实现了动态生成代理类并加自己想加的逻辑
*
* @param infce
* @return
*/
private static String createClass(Class<?> infce) {
String methodStr = "";
String rt = "\r\n";
// 利用反射,获得infce接口中方法,本例中就是获得Animal接口的方法breathe
Method[] methods = infce.getMethods();

// 拼接infce中所有方法字符串,用来重写infce中的方法,本例中拼出来就是重写的breathe方法
for (Method m : methods) {
methodStr += " @Override" + rt + " public void " + m.getName() + "() {" + rt + " try {" + rt + " Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");"
+ rt + " h.invoke(this, md, md.getParameterTypes());" + rt + " }catch(Throwable e) {e.printStackTrace();}" + rt + " }" + rt;
}

String src ="import java.lang.reflect.Method;" + rt + "import java.lang.reflect.InvocationHandler;" + rt + "public class $Proxy1 implements "
+ infce.getName() + "{" + rt + " public $Proxy1(InvocationHandler h) {" + rt + " this.h = h;" + rt + " }" + rt + " InvocationHandler h;" + rt + methodStr + rt + "}";

return src;
}

/**
* load into memory and create an instance加载进内存并创建对象
*
* @param h
* @return
* @throws MalformedURLException
* @throws ClassNotFoundException
* @throws NoSuchMethodException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/

private static Object getInstance(InvocationHandler h) throws Exception {
String url = "file:/" + filePath+ "/";
URL[] urls = new URL[] { new URL(url) };
URLClassLoader ul = new URLClassLoader(urls);
Class<?> c = ul.loadClass(name);
//拿到那个(本例也只有这一个)带InvocationHandler参数的构造器
Constructor<?> ctr = c.getConstructor(InvocationHandler.class);
return ctr.newInstance(h);
}

/**
* 编译文件
*
* @throws IOException
*/
private static void compileFile() throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
compiler.getTask(null, fileMgr, null, null, null, fileMgr.getJavaFileObjects(fileName)).call();
fileMgr.close();
}

/**
* 写到文件
*
* @param src
* @throws IOException
*/
private static void toFile(String src) throws IOException {
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
}

下面是生成的代理类的源代码,当然了jdk不是生成源代码,而是在内存直接生成字节码。

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

public class $Proxy1 implements com.shalf.myproxy.Animal {
public $Proxy1(InvocationHandler h) {
this.h = h;
}

InvocationHandler h;

@Override
public void breathe() {
try {
Method md = com.shalf.myproxy.Animal.class.getMethod("breathe");
h.invoke(this, md, md.getParameterTypes());
} catch (Throwable e) {
e.printStackTrace();
}
}

}

}

jdk的动态代理的更多相关文章

  1. JAVA JDK的动态代理反射实现

    动态代理类使用到了一个接口InvocationHandler和一个代理类Proxy ,这两个类配合使用实现了动态代理的功能. 什么是动态代理呢?  普通代理类是指: 给每个具体类写一个代理类,以后要使 ...

  2. JDK的动态代理-----为接口进行代理

    JDK的动态代理是必须掌握的,动态代理的好处就不用我多说了吧 :) 小弟最近在研究mybatis的源码实现,就开始了解mybatis的Mapper代理机制,为什么接口不用实现类也能代理? 好了,废话不 ...

  3. 基于 JDK 的动态代理机制

    『动态代理』其实源于设计模式中的代理模式,而代理模式就是使用代理对象完成用户请求,屏蔽用户对真实对象的访问. 举个最简单的例子,比如我们想要「FQ」访问国外网站,因为我们并没有墙掉所有国外的 IP,所 ...

  4. JDK的动态代理机制

    JDK Proxy OverView jdk的动态代理是基于接口的,必须实现了某一个或多个随意接口才干够被代理,并且仅仅有这些接口中的方法会被代理.看了一下jdk带的动态代理api.发现没有样例实在是 ...

  5. 动态代理:JDK原生动态代理(Java Proxy)和CGLIB动态代理原理+附静态态代理

    本文只是对原文的梳理总结,以及自行理解.自己总结的比较简单,而且不深入,不如直接看原文.不过自己梳理一遍更有助于理解. 详细可参考原文:http://www.cnblogs.com/Carpenter ...

  6. CGLib与JDK的动态代理

    一.CGLib 简单介绍 CGLib (Code Generation Library) 是一个强大的,高性能,高质量的Code生成类库. 它能够在执行期扩展Java类与实现Java接口. Hiber ...

  7. JDK的动态代理深入解析(Proxy,InvocationHandler)(转)

    JDK的动态代理深入解析(Proxy,InvocationHandler)(转) 一.什么是动态代理 动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实.代理一般会实现它所表示的实际对象的 ...

  8. JDK 原生动态代理是怎么实现的 + 面试题

    JDK 原生动态代理是怎么实现的 + 面试题 反射 反射机制是 Java 语言提供的一种基础功能,赋予程序在运行时自省(introspect)的能力.简单来说就是通过反射,可以在运行期间获取.检测和调 ...

  9. 代理模式详解:静态代理+JDK/CGLIB 动态代理实战

    1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ...

随机推荐

  1. 在ubuntu12.0.4上搭建samba服务器以实现文件共享

    在安装之前samba服务器之前,先进行以下配置和测试. <壹> 准备工作 一.NAT联网方式 (1)硬件连接 无需网线,无需路由器 (2)虚拟机选择NAT连接方式 (3)测试网络通不通 在 ...

  2. 自定义modal一个控制器的效果, presentViewController

    presentViewController 一.主要用途 弹出模态ViewController是IOS变成中很有用的一个技术,UIKit提供的一些专门用于模态显示的ViewController,如UI ...

  3. 从零到一:caffe-windows(CPU)配置与利用mnist数据集训练第一个caffemodel

    一.前言 本文会详细地阐述caffe-windows的配置教程.由于博主自己也只是个在校学生,目前也写不了太深入的东西,所以准备从最基础的开始一步步来.个人的计划是分成配置和运行官方教程,利用自己的数 ...

  4. JavaScript高级之闭包的概念及其应用

    主要内容: 什么是闭包 闭包使用的一般模式 闭包都能做些什么 本文是我的JavaScript高级这个系列中的第二篇文章. 在这个系列中,我计划分析说明 一下JavaScript中的一些常用的而又神秘的 ...

  5. 工作总结:文件对话框的分类(C++)

    原文地址:http://www.jizhuomi.com/software/173.html 文件对话框分为打开文件对话框和保存文件对话框,相信大家在Windows系统中经常见到这两种文件对话框.例如 ...

  6. python基础知识(引用)

    文章连接:http://xianglong.me/article/how-to-code-like-a-pythonista-idiomatic-python/

  7. 安装python环境(win7 64bit)

    原地址:http://blog.csdn.net/bryanliu1982/article/details/7184814 虽然简单,但是过段时间又忘了,还是记下来比较好. 总体来说只有两步: 下载安 ...

  8. 【BZOJ 2693】jzptab(莫比乌斯+分块)

    2693: jzptab Description Input 一个正整数T表示数据组数 接下来T行 每行两个正整数 表示N.M Output T行 每行一个整数 表示第i组数据的结果 Sample I ...

  9. 【poj3734】矩阵乘法求解

    [题意] 给N个方块排成一列.现在要用红.蓝.绿.黄四种颜色的油漆给这些方块染色.求染成红色方块和染成绿色方块的个数同时为偶数的染色方案的个数,输出对10007取余后的答案.(1<=n<= ...

  10. QEvent整理归纳:140种类型,29个继承类,7个函数,3种事件来源

    140种事件类型: QEvent::None QEvent::AccessibilityDescription QEvent::AccessibilityHelp QEvent::Accessibil ...