自己动手实现JDK动态代理
出自:作者:孤独烟 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步
- 生成java源碼
- 將源码输出到java文件中
- 将java文件编译成class文件
- 将class加载进jvm
- 返回代理类对象
具体代码如下
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动态代理的更多相关文章
- 【原创】分布式之缓存击穿 【原创】自己动手实现静态资源服务器 【原创】自己动手实现JDK动态代理
[原创]分布式之缓存击穿 什么是缓存击穿 在谈论缓存击穿之前,我们先来回忆下从缓存中加载数据的逻辑,如下图所示 因此,如果黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查 ...
- 动态代理学习(一)自己动手模拟JDK动态代理
最近一直在学习Spring的源码,Spring底层大量使用了动态代理.所以花一些时间对动态代理的知识做一下总结. 我们自己动手模拟一个动态代理 对JDK动态代理的源码进行分析 文章目录 场景: 思路: ...
- 【原创】自己动手实现JDK动态代理
项目结构如下图所示,maven项目 1.JDK动态代理 先来一段jdk动态代理的demo, 首先创建一个接口,Person package bean; public interface Person ...
- Java JDK 动态代理使用及实现原理分析
转载:http://blog.csdn.net/jiankunking 一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理 ...
- JDK动态代理
一.基本概念 1.什么是代理? 在阐述JDK动态代理之前,我们很有必要先来弄明白代理的概念.代理这个词本身并不是计算机专用术语,它是生活中一个常用的概念.这里引用维基百科上的一句话对代理进行定义: A ...
- JDK动态代理实例
最近看<深入浅出MyBatis技术原理与实战>这本书时,里面讲到Mapper接口的内部实现是通过JDK动态代理生成实现类,联想到之前看<SPRING技术内幕>这本书里也常常提到 ...
- 静态代理和利用反射形成的动态代理(JDK动态代理)
代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...
- Spring中的JDK动态代理
Spring中的JDK动态代理 在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层 ...
- AOP学习心得&jdk动态代理与cglib比较
什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...
随机推荐
- wordpress搭建自己的博客~
去官方网站下载wordpress,并解压缩.下载链接:https://cn.wordpress.org/ wordpress是一款开源的PHP框架,搭建个人博客网站最实用的选择之一,甚至你都不需要懂P ...
- PHP涉及的所有英文单词
PHP涉及的所有英文单词拦路虎 PHP再火,也会让一部同学心生畏惧,因为看到编辑器中那一串串英文单词,担心自己英文不好,从而对能学会PHP的决心产生动摇.其实大可不必,英文在学习PHP过程中真的连级别 ...
- jwt 接口加密
什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点 ...
- day04列表
列表 内容详细 1.列表 公共 独有方法 删除 remove pop clear del区别 强制转换 #表示多个事物 users=["lili","Joe", ...
- linux下设置mysql5.7数据库远程访问
1.在网上看了很多关于设置远程访问的方式,根本就不起作用,后来在网上看到有一篇文章终于解决了我的问题,在配置文件中 /etc/mysql/my.cnf : 2.编辑 vi /etc/mysql/mys ...
- PTA——洗牌
PTA 7-43 Shuffling Machine #include<stdio.h> int main() { int i,n,*result; scanf("%d" ...
- https原理及其中所包含的对称加密、非对称加密、数字证书、数字签名
声明:本文章已授权公众号Hollis转载,如需转载请标明转载自https://www.cnblogs.com/wutianqi/p/10654245.html(安静的boy) 一.为什么要使用http ...
- python: 递归函数(科赫雪花)
import turtle as t def kehe(size,n): #递归函数 if n==0: t.fd(size) #阶数为0时,为一直线 else: for i in [0,60,-120 ...
- python:递归函数(汉诺塔)
#hanoi.py def hanoi(n,x,y,z): if n==1: print(x,"-->",z) else: hanoi(n-1,x,z,y) print(x, ...
- git 错误汇总
★一.git提交时报错:Updates were rejected because the tip of your current branch is behind 出现这样的问题是由于:自己当前版本 ...