出自:作者:孤独烟  http://rjzheng.cnblogs.com/

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

引言

项目结构如下图所示,maven项目

1、JDK动态代理

先来一段jdk动态代理的demo,
首先创建一个接口,Person

package bean;

public interface Person {

    public void eat();

}

然后写一个实现类PersonImpl

package bean;

public class PersonImpl implements Person{

    @Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("time to eat ");
} }

然后写个使用类PersonInvocationHandler

package jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class PersonInvocationHandler implements InvocationHandler { private Object obj; public PersonInvocationHandler(Object obj) {
this.obj = obj;
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("before time to eat");
method.invoke(obj, args);
System.out.println("after time to eat");
return null;
} }

最后 再写个测试类

package jdk;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.lang.reflect.Proxy; import sun.misc.ProxyGenerator;
import bean.Person;
import bean.PersonImpl; public class jdkTest { public static void main(String[] args) throws Exception {
PersonInvocationHandler personInvocationHandler = new PersonInvocationHandler(
new PersonImpl());
Person personProxy = (Person) Proxy.newProxyInstance(
PersonImpl.class.getClassLoader(),
PersonImpl.class.getInterfaces(), personInvocationHandler);
personProxy.eat();
}
}

输出如下

before time to eat
time to eat
after time to eat

接下里我们不使用JDK的API,自己实现一套代理类

2、自定义动态代理

先上测试类的代码,如下图所示,共有(1)(2)(3)处不同

针对(1),我们有如下代码,先抄袭JDK的InvocationHandler,改个名字成为MyInvocationHandler

package custom;

import java.lang.reflect.Method;

public interface MyInvocationHandler {

     public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable; }

编写一个JAVA类MyPersonInvocationHandler继承MyInvocationHandler,这段代码与PersonInvocationHandler的代码无异,如下所示

package custom;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class MyPersonInvocationHandler implements MyInvocationHandler { private Object obj; public MyPersonInvocationHandler(Object obj) {
this.obj = obj;
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("before time to eat");
method.invoke(obj, args);
System.out.println("after time to eat");
return null;
} }

针对(2),我们实现一个自己的代理生成类MyProxy,其生成java代理类的步骤分为以下5步

  1. 生成java源碼
  2. 將源码输出到java文件中
  3. 将java文件编译成class文件
  4. 将class加载进jvm
  5. 返回代理类对象

具体代码如下

package custom;

import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method; import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider; public class MyProxy { public static final String ln = "\r\n"; public static Object newProxyInstance(MyClassLoader myClassLoder,
Class<?>[] interfaces, MyInvocationHandler h) {
try{
// 1 java源碼
String src = generateSrc(interfaces); // 2 將源码输出到java文件中
String filePath = MyProxy.class.getResource("").getPath();
System.out.println(filePath);
File f = new File(filePath + "$Proxy0.java");
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close(); //3、将java文件编译成class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
Iterable iterable = manage.getJavaFileObjects(f); JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
task.call();
manage.close(); //4、将class加载进jvm
Class proxyClass=myClassLoder.findClass("$Proxy0");
f.delete(); //5、返回代理类对象
Constructor constructor = proxyClass.getConstructor(MyInvocationHandler.class);
return constructor.newInstance(h);
}catch(Exception e){
e.printStackTrace();
}
return null;
} private static String generateSrc(Class<?>[] interfaces) {
// TODO Auto-generated method stub
StringBuffer sb = new StringBuffer();
sb.append("package custom;" + ln);
sb.append("import java.lang.reflect.Method;" + ln);
sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
sb.append("private MyInvocationHandler h;"+ln);
sb.append("public $Proxy0(MyInvocationHandler h) { " + ln);
sb.append("this.h = h;"+ln);
sb.append("}" + ln);
for (Method m : interfaces[0].getMethods()) {
sb.append("public " + m.getReturnType().getName() + " "
+ m.getName() + "() {" + ln);
sb.append("try{" + ln);
sb.append("Method m = " + interfaces[0].getName()
+ ".class.getMethod(\"" + m.getName()
+ "\",new Class[]{});" + ln);
sb.append("this.h.invoke(this,m,null);" + ln);
sb.append("}catch(Throwable e){" + ln);
sb.append("e.printStackTrace();" + ln);
sb.append("}"+ln);
sb.append("}"+ln);
}
sb.append("}" + ln);
return sb.toString();
}
}

针对(3),我们继承ClassLoader,实现一套自己的类加载机制MyClassLoader,如下所示,

package custom;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; public class MyClassLoader extends ClassLoader { private File classPathfile; public MyClassLoader() {
String classpth = MyClassLoader.class.getResource("").getPath();
classPathfile = new File(classpth);
} @Override
public Class<?> findClass(String name) throws ClassNotFoundException {
String className = MyClassLoader.class.getPackage().getName() + "." +name;
if (classPathfile != null) {
File file = new File(classPathfile, name + ".class");
FileInputStream fileInputStream = null;
ByteArrayOutputStream outputStream = null;
try{
fileInputStream = new FileInputStream(file);
outputStream = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len;
while((len=fileInputStream.read(buff))!=-1){
outputStream.write(buff, 0, len);
}
return defineClass(className, outputStream.toByteArray(), 0, outputStream.size());
}catch(Exception e){
e.printStackTrace();
}finally{
if(null!=fileInputStream){
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(null!=outputStream){
try {
outputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
return null;
} }

最后测试类代码如下所示

package custom;

import java.lang.reflect.Proxy;

import custom.MyPersonInvocationHandler;
import bean.Person;
import bean.PersonImpl; public class CustomTest { public static void main(String[] args) {
MyPersonInvocationHandler personInvocationHandler = new MyPersonInvocationHandler(
new PersonImpl());
Person personProxy = (Person) MyProxy.newProxyInstance(
new MyClassLoader(), PersonImpl.class.getInterfaces(),
personInvocationHandler);
personProxy.eat();
}
}

输出如何所示

before time to eat
time to eat
after time to eat

至此,我们已完全实现了一套自定义的jdk动态代理类

-------------------------------------------------------------------------------------------------

示例总结:

动态代理实际上: 它私下新建了一个java类$proxy0,这个$proxy0类是实现需要动态代理的接口Person。然后它的属性是动态代理类InvocationHander 的引用,

然后重写Person接口的方法eat,而eat的方法体调用动态代理类InvocationHandler实现类PersonInvocationHandler的方法eat这样在通过代理类工具Proxy获取代理时,

其实获取的是私下的这个$proxy0,这个java类是实现需要动态代理的接口Person的实现类。然后它的属性是动态代理类的引用,然后重写Person类的方法eat,

而每一个方法的方法体调用动态代理类InvocationHandler实现类PersonInvocationHandler的方法eat.

这样在通过代理类工具Proxy获取代理newProxyInstance时,其实获取的是私下的这个$proxy0的对象。 


描述完 豁然开朗。使用的都是JDK最基本的一些东西,反射,类加载,编译等等 信息。

 

自己动手实现JDK动态代理的更多相关文章

  1. 【原创】分布式之缓存击穿 【原创】自己动手实现静态资源服务器 【原创】自己动手实现JDK动态代理

    [原创]分布式之缓存击穿   什么是缓存击穿 在谈论缓存击穿之前,我们先来回忆下从缓存中加载数据的逻辑,如下图所示 因此,如果黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查 ...

  2. 动态代理学习(一)自己动手模拟JDK动态代理

    最近一直在学习Spring的源码,Spring底层大量使用了动态代理.所以花一些时间对动态代理的知识做一下总结. 我们自己动手模拟一个动态代理 对JDK动态代理的源码进行分析 文章目录 场景: 思路: ...

  3. 【原创】自己动手实现JDK动态代理

    项目结构如下图所示,maven项目 1.JDK动态代理 先来一段jdk动态代理的demo, 首先创建一个接口,Person package bean; public interface Person ...

  4. Java JDK 动态代理使用及实现原理分析

    转载:http://blog.csdn.net/jiankunking   一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理 ...

  5. JDK动态代理

    一.基本概念 1.什么是代理? 在阐述JDK动态代理之前,我们很有必要先来弄明白代理的概念.代理这个词本身并不是计算机专用术语,它是生活中一个常用的概念.这里引用维基百科上的一句话对代理进行定义: A ...

  6. JDK动态代理实例

    最近看<深入浅出MyBatis技术原理与实战>这本书时,里面讲到Mapper接口的内部实现是通过JDK动态代理生成实现类,联想到之前看<SPRING技术内幕>这本书里也常常提到 ...

  7. 静态代理和利用反射形成的动态代理(JDK动态代理)

    代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...

  8. Spring中的JDK动态代理

    Spring中的JDK动态代理 在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层 ...

  9. AOP学习心得&jdk动态代理与cglib比较

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...

随机推荐

  1. STL的内存管理

    SGI STL 的内存管理 http://www.cnblogs.com/sld666666/archive/2010/07/01/1769448.html 1. 好多废话 在分析完nginx的内存池 ...

  2. php源代码安装

    1.在官网下载php安装源文件.版本选择5的最新稳定版. [root@trial download]# wget http://cn.php.net/distributions/php-5.5.38. ...

  3. Selenium2+python自动化-查看selenium API

    前面都是点点滴滴的介绍selenium的一些api使用方法,那么selenium的api到底有多少呢?本篇就叫大家如何去查看selenium api,不求人,无需伸手找人要,在自己电脑就有. pydo ...

  4. Spring源码学习(2)——默认标签的解析

    上一篇随笔说到Spring对于默认标签和自定义标签的解析方法是不同的,这里详细看一下Spring对于默认标签的解析. private void parseDefaultElement(Element ...

  5. linux重启查看日志及历史记录 查询原因

    linux重启查看日志及历史记录 查询原因 linux系统文件通常在/var/log中下面是对下面常出现的文件进行解释 /var/log/message ----------------------- ...

  6. Springmvc 简单入门1

    导入jar包 下载路径: 在web.xml里面配置 <servlet> <servlet-name>Springmvc</servlet-name> <!-- ...

  7. ASP.NET之使用Ajax实现页面异步刷新(无需刷新整个页面)

    目前在使用ASP.NET技术做毕业设计,但是关于网页中的各种配置我到现在还不是很清楚,正在努力进化... 一般情况下,新建网页页面的话,应该为.aspx后缀的文件,建好之后对应一个同名的.cs文件,属 ...

  8. Python全栈之路----常用模块----datetime模块详解

    相比于time模块,datetime模块的接口则更直观,更容易调用. datetime模块定义了下面这几个类: datetime.date:表示日期的类,常用的属性有year,month,day: d ...

  9. Java第一次作业——Java语言基础

    <Java技术>第一次作业 学习总结 1.Scanner类实现基本数据输入方法 Scanner input=new Scanner(System.in); int num = input. ...

  10. nginx 文档链接

    https://www.cnblogs.com/wcwnina/p/8728391.html    NGINX简介 http://www.nginx.cn/doc/                  ...