【原创】自己动手实现JDK动态代理
引言
项目结构如下图所示,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动态代理类
【原创】自己动手实现JDK动态代理的更多相关文章
- 【原创】分布式之缓存击穿 【原创】自己动手实现静态资源服务器 【原创】自己动手实现JDK动态代理
[原创]分布式之缓存击穿 什么是缓存击穿 在谈论缓存击穿之前,我们先来回忆下从缓存中加载数据的逻辑,如下图所示 因此,如果黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查 ...
- 动态代理学习(一)自己动手模拟JDK动态代理
最近一直在学习Spring的源码,Spring底层大量使用了动态代理.所以花一些时间对动态代理的知识做一下总结. 我们自己动手模拟一个动态代理 对JDK动态代理的源码进行分析 文章目录 场景: 思路: ...
- 自己动手实现JDK动态代理
出自:作者:孤独烟 http://rjzheng.cnblogs.com/ ------------------------------------------------------------- ...
- Java JDK 动态代理使用及实现原理分析
转载:http://blog.csdn.net/jiankunking 一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理 ...
- 【原创】JDK动态代理,此次之后,永生难忘。
动态代理,这个词在Java的世界里面经常被提起,尤其是对于部分(这里强调“部分”二字,因为有做了一两年就成大神的,实力强的令人发指,这类人无疑是非常懂动态代理这点小伎俩的)做了一两年新人来说,总是摸不 ...
- JDK动态代理
一.基本概念 1.什么是代理? 在阐述JDK动态代理之前,我们很有必要先来弄明白代理的概念.代理这个词本身并不是计算机专用术语,它是生活中一个常用的概念.这里引用维基百科上的一句话对代理进行定义: A ...
- jdk动态代理与cglib代理、spring aop代理实现原理
原创声明:本博客来源与本人另一博客[http://blog.csdn.net/liaohaojian/article/details/63683317]原创作品,绝非他处摘取 代理(proxy)的定义 ...
- jdk动态代理与cglib代理、spring aop代理实现原理解析
原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...
- 何为代理?jdk动态代理与cglib代理、spring Aop代理原理浅析
原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...
随机推荐
- DBI-1.634之selectrow_array与fetchrow_array的区别
在DBI-1.634使用手册里有一个selectrow_array函数,该函数具体说明如下: This utility method combines "prepare", &qu ...
- FFmpeg视频处理
FFmpeg是一个用于音视频处理的自由软件,被广泛用于音视频开发.FFmpeg功能强大,本文主要介绍如何使用FFmpeg命令行工具进行简单的视频处理. 安装FFmpeg可以在官网下载各平台软件包或者静 ...
- 【Docker】Docker概述
[Docker] Docker可以说是近几年非常热门的技术之一了.不管是别人敦促我还是从自己的想法来说,都觉得Docker这玩意儿肯定是要好好学习一下的,无奈没啥时间专门播出来给Docker,一直以来 ...
- spring boot — InputStream
@Componentpublic class TextFileDownloadView extends AbstractFileDownloadView { @Override protected I ...
- iOS scrollView中嵌套多个tabeleView处理方案
项目中经常会有这样的需求,scrollView有个头部,当scrollView滚动的时候头部也跟着滚动,同时头部还有一个tab会锁定在某个位置,scrollView中可以放很多不同的view,这些vi ...
- [bzoj1026][SCOI2009]windy数_数位dp
windy数 bzoj-1026 题目大意:求一段区间中的windy数个数. 注释:如果一个数任意相邻两位的差的绝对值都不小于2,这个数就是windy数,没有前导0.$区间边界<=2\cdot ...
- jmeter连接Mysql数据库测试性能初探
Jmeter mysql性能测试演示 1. Jmeter是java开发的,jmeter连接mysql数据库当然需要jdbc驱动,这个可以在网上下载mysql-connector-java包,然后解压 ...
- Linux安装java环境教程
前言: 本教程基于jdk 1.8,但是此教程适用于jdk1.7等版本. 教程正文: 1.1. 登录Oracle官网下载jdk1.8安装包(gz结尾) 这里可以用"wget + 下载地址&qu ...
- Alpha第三天
Alpha第三天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...
- sql with as 用法-Z
以下内容转自:http:.com/ 一.WITH AS的含义 WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个 ...