至于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. c# winform 隐藏tabcontrol标签

    Apperarance 属性:Faltbuttons SizeMode属性:Fixed 各个TabPage的Text :空 ItemSize : Width=0;Height=1;

  2. POJ 1459 Power Network 最大流(Edmonds_Karp算法)

    题目链接: http://poj.org/problem?id=1459 因为发电站有多个,所以需要一个超级源点,消费者有多个,需要一个超级汇点,这样超级源点到发电站的权值就是发电站的容量,也就是题目 ...

  3. 双数组Trie树 (Double-array Trie) 及其应用

    双数组Trie树(Double-array Trie, DAT)是由三个日本人提出的一种Trie树的高效实现 [1],兼顾了查询效率与空间存储.Ansj便是用DAT(虽然作者宣称是三数组Trie树,但 ...

  4. ssh登录docker容器

    ssh登录docker容器1.启动一个docker容器# docker run -t -i ubuntu/ruby:v1 /bin/bash2.然后在容器里,安装openssh-server open ...

  5. TCP/IP入门学习(1)---分层概述

    本文旨在记述一些学习中的笔记 OSI分层:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层 详细点: 1.应用层:为应用程序提供服务并规定程序中通信相关细节. 2.表示层:将应用处理的信息转 ...

  6. bzoj 2244: [SDOI2011]拦截导弹 cdq分治

    2244: [SDOI2011]拦截导弹 Time Limit: 30 Sec  Memory Limit: 512 MBSec  Special JudgeSubmit: 237  Solved: ...

  7. IEEE会议排名(转载)

    不知道谁整理的,我就下了个word.所以就标注不了,引用的哪的了. Rank 1: SIGCOMM: ACM Conf on Comm Architectures, Protocols & A ...

  8. [python]用profile协助程序性能优化

    转自:http://blog.csdn.net/gzlaiyonghao/article/details/1483728 本文最初发表于恋花蝶的博客http://blog.csdn.net/lanph ...

  9. [wikioi]传纸条

    http://wikioi.com/problem/1169/ 棋盘型的动态规划,这道题可以看成是从左上角向右下角走两条不重合的路(除了开始和结尾).动态规划要想的是状态和阶段,状态是(x1,y1,x ...

  10. Android开源项目发现---Menu 篇(持续更新)

    1. MenuDrawer 滑出式菜单,通过拖动屏幕边缘滑出菜单,支持屏幕上下左右划出,支持当前View处于上下层,支持Windows边缘.ListView边缘.ViewPager变化划出菜单等. 项 ...