模拟实现jdk动态代理
实现步骤
1、生成代理类的源代码
2、将源代码保存到磁盘
3、使用JavaCompiler编译源代码生成.class字节码文件
4、使用JavaCompiler编译源代码生成.class字节码文件
5、返回代理类的实例
实现代码
package com.lnjecit.proxy.custom; import java.lang.reflect.Method; /**
* 自定义InvocationHandler
*/
public interface MyInvocationHandler { /**
* 执行代理实例中目标方法,并返回结果
* @param proxy 代理实例
* @param method 目标方法
* @param args 目标方法中的参数
* @return
*/
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
package com.lnjecit.proxy.custom; import java.io.File;
import java.lang.reflect.Constructor; /**
* 自定义代理类
*
* @author
* @create 2018-04-08 21:55
**/
public class MyProxy { /**
* 生成代理类实例
*
* @param classLoader 类加载器
* @param interfaces 被代理类实现的接口数组
* @param h
* @return
*/
public static Object newProxyInstance(MyClassLoader classLoader, Class<?>[] interfaces, MyInvocationHandler h) throws ClassNotFoundException {
// 1、生成代理类的源代码
String sourceFileStr = MyProxyGenerator.generateSourceFile("$Proxy0", interfaces);
String filePath = MyProxy.class.getResource("/").getPath();
try {
// 2、将源代码保存到磁盘
File sourceFile = MyProxyGenerator.saveGeneratedSourceFile(filePath, sourceFileStr);
// 3、使用JavaCompiler编译源代码生成.class字节码文件
MyProxyGenerator.generateProxyClass(sourceFile);
// 4、使用ClassLoader将.class文件中的内容加载到JVM
Class proxyClass = classLoader.findClass("$Proxy0");
// 5、返回代理类的实例
Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
// 删除生成的源文件
// sourceFile.delete();
return c.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return null;
} }
package com.lnjecit.proxy.custom; import javax.tools.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method; /**
* 生成代理类
*
* @author
* @create 2018-04-08 22:01
**/
public class MyProxyGenerator { private static final String PROXY_PACKAGE = "com.lnjecit.proxy.custom"; private static final String LINE_FEED = "\r\n"; /**
* 生成代理类的源代码
* @param proxyName
* @param interfaces
* @return
*/
public static String generateSourceFile(String proxyName, Class<?>[] interfaces) {
StringBuffer buffer = new StringBuffer();
buffer.append("package " + PROXY_PACKAGE + ";" + LINE_FEED);
for (Class<?> intf : interfaces) {
buffer.append("import " + intf.getName() + ";" + LINE_FEED);
} buffer.append("import java.lang.reflect.Method;" + LINE_FEED);
buffer.append("import com.lnjecit.proxy.custom.MyProxy;" + LINE_FEED);
buffer.append("import com.lnjecit.proxy.custom.MyInvocationHandler;" + LINE_FEED);
buffer.append("public final class " + proxyName + " extends MyProxy implements ");
for (Class<?> intf : interfaces) {
buffer.append(intf.getSimpleName());
}
buffer.append("{" + LINE_FEED); buffer.append("private MyInvocationHandler h;" + LINE_FEED);
// 构造函数
buffer.append("public " + proxyName + "(MyInvocationHandler h" + ") {" + LINE_FEED);
buffer.append("this.h = h;" + LINE_FEED);
buffer.append("}" + LINE_FEED); for (Class<?> intf : interfaces) {
Method[] methods = intf.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
buffer.append("public " + method.getReturnType() + " " + method.getName() + "()" + "{" + LINE_FEED);
buffer.append("try {" + LINE_FEED);
buffer.append("Method m = " + intf.getName() + ".class.getMethod(\"" + method.getName() + "\",new Class[]{});" + LINE_FEED);
buffer.append("h.invoke(this, m, null);" + LINE_FEED);
buffer.append("} catch (Throwable e) {" + LINE_FEED);
buffer.append("e.printStackTrace();" + LINE_FEED);
buffer.append("}" + LINE_FEED);
buffer.append("}" + LINE_FEED);
} }
buffer.append("}" + LINE_FEED);
return buffer.toString();
} /**
* 将代理类源文件便以为.class文件
* @param sourceFile 源文件
* @throws IOException
*/
public static void generateProxyClass(File sourceFile) throws IOException {
// 获取JavaCompiler
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// DiagnosticListener用于获取Diagnostic信息,Diagnostic信息包括:错误,警告和说明性信息
DiagnosticListener<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
// StandardJavaFileManager:用于管理与工具有关的所有文件
StandardJavaFileManager manager = compiler.getStandardFileManager(diagnostics, null, null);
// avaFileObjects: 是java源码文件(.java)和class文件(.class)的抽象
Iterable iterable = manager.getJavaFileObjects(sourceFile);
// 编译任务
JavaCompiler.CompilationTask task = compiler.getTask(null, manager, diagnostics, null, null, iterable);
task.call();
manager.close();
} /**
* 将代理类的源代码保存到本地磁盘
* @param filePath 文件保存路径
* @param sourceFileStr 源代码
* @throws IOException
*/
public static File saveGeneratedSourceFile(String filePath, String sourceFileStr) throws IOException {
File sourceFile = new File(filePath + PROXY_PACKAGE.replaceAll("\\.", "/") + "/" + "$Proxy0.java");
FileWriter fw = new FileWriter(sourceFile);
fw.write(sourceFileStr);
fw.flush();
fw.close();
return sourceFile;
}
}
package com.lnjecit.proxy.custom; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; /**
* 自定义ClassLoader
* @author
* @create 2018-04-08 21:57
**/
public class MyClassLoader extends ClassLoader { private File baseDir; public MyClassLoader(){
String basePath = MyClassLoader.class.getResource("").getPath();
this.baseDir = new java.io.File(basePath);
} @Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = MyClassLoader.class.getPackage().getName() + "." + name;
if(baseDir != null){
File classFile = new File(baseDir,name.replaceAll("\\.", "/") + ".class");
if(classFile.exists()){
FileInputStream in = null;
ByteArrayOutputStream out = null;
try{
in = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte [] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
return defineClass(className, out.toByteArray(), 0,out.size()); }catch (Exception e) {
e.printStackTrace();
}finally{
if(null != in){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null != out){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
classFile.delete();
} }
} return null;
}
}
package com.lnjecit.proxy.custom; import java.lang.reflect.Method; /**
* @author
* @create 2018-04-08 21:59
**/
public class JDKDynamicProxy implements MyInvocationHandler { Object target; public <T> T getInstance(Object target) throws Exception {
this.target = target;
return (T) MyProxy.newProxyInstance(new MyClassLoader(), target.getClass().getInterfaces(), this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before invoke");
Object result = method.invoke(target, args);
System.out.println("After invoke");
return result;
}
}
测试代码
package com.lnjecit.proxy; /**
* Subject
* 抽象主题接口
* @author
* @create 2018-03-29 14:16
**/
public interface Subject { void doSomething();
}
package com.lnjecit.proxy; /**
* RealSubject
* 真实主题类
* @author
* @create 2018-03-29 14:21
**/
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject do something");
}
}
import com.lnjecit.proxy.RealSubject;
import com.lnjecit.proxy.Subject; /**
* 测试类
* @author
* @create 2018-04-08 23:07
**/
public class Client {
public static void main(String[] args) {
try {
Subject subject = new JDKDynamicProxy().getInstance(new RealSubject());
subject.doSomething();
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试结果:
Before invoke
RealSubject do something
After invoke
在调试过程中可看到:在classpath路径下生成了$Proxy0.java和$Proxy0.class两个文件

以上仅仅实现了代理一个接口并且方法无参数的简单代理,只是为了更好理解jdk动态代理。
模拟实现jdk动态代理的更多相关文章
- 对JDK动态代理的模拟实现
对JDK动态代理的模拟 动态代理在JDK中的实现: IProducer proxyProduec = (IProducer)Proxy.newProxyInstance(producer.getCla ...
- 动态代理学习(一)自己动手模拟JDK动态代理
最近一直在学习Spring的源码,Spring底层大量使用了动态代理.所以花一些时间对动态代理的知识做一下总结. 我们自己动手模拟一个动态代理 对JDK动态代理的源码进行分析 文章目录 场景: 思路: ...
- Spring中的JDK动态代理
Spring中的JDK动态代理 在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层 ...
- AOP学习心得&jdk动态代理与cglib比较
什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...
- Spring AOP详解 、 JDK动态代理、CGLib动态代理
AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码 ...
- JDK动态代理与Cglib库
JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...
- 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理
Spring AOP详解 . JDK动态代理.CGLib动态代理 原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...
- 设计模式之jdk动态代理模式、责任链模式-java实现
设计模式之JDK动态代理模式.责任链模式 需求场景 当我们的代码中的类随着业务量的增大而不断增大仿佛没有尽头时,我们可以考虑使用动态代理设计模式,代理类的代码量被固定下来,不会随着业务量的增大而增大. ...
- JDK动态代理给Spring事务埋下的坑!
一.场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下: 1.场景A ...
随机推荐
- Educational Codeforces Round 47 (Rated for Div. 2) :D. Relatively Prime Graph
题目链接:http://codeforces.com/contest/1009/problem/D 解题心得: 题意就是给你n个点编号1-n,要你建立m条无向边在两个互质的点之间,最后所有点形成一个连 ...
- fiddler手机抓包配置方法
一.下载工具包 百度搜索”fiddler 下载“ ,安装最新版本 下载的软件安装包为“fiddler_4.6.20171.26113_setup.exe”格式,双击安装.安装成功,在“开始”-“所有程 ...
- 3,SQL语句及数据库优化
1,统一SQL语句的写法 对于以下两句SQL语句,程序员认为是相同的,数据库查询优化器认为是不同的. 所以封装成复用方法,用标准模板来控制. select*from dual select*Fr ...
- 26、js阶段性复习
1.一元运算符 Operator + 可用于将变量转换为数字: <!DOCTYPE html> <html> <body> <p> typeof 操作符 ...
- PostgreSQL基本配置
记一下Postgresql的基本操作,在Ubuntu下使用apt-get安装是不会像MySQL那样都配置好了,而是要安装后再配置: 1. 基本安装 # 安装postgresql和pgadmin(一个管 ...
- Queue模块初识
Queue模块实现了多生产者.多消费者队列.它特别适用于信息必须在多个线程间安全地交换的多线程程序中.这个模块中的Queue类实现了所有必须的锁语义.它依赖于Python中线程支持的可用性:参见thr ...
- 前端开发神器Sublime Text2/3之安装使用(windows7/Mac)
一,到官方网站下载神器 地址:http://www.sublimetext.com/3 Sublime Text 3 配置解释(默认){// 设置主题文件“color_scheme”: “Packag ...
- 第十四次ScrumMeeting会议
第十三次Scrum Meeting 时间:2017/12/2 地点:咖啡馆 人员:策划组美工组 目前工作情况 名字 完成的工作 计划工作 蔡帜 科技树策划设计,科技图鉴蓝图设计 员工方面细节设定 游心 ...
- await和async再学习
await太不容易理解了,自己常常迷惑,不知道该怎么用. 文章:探索c#之Async.Await剖析 这篇文章,有一个很清晰的描述: 使用Async标记方法Async1为异步方法,用Await标记Ge ...
- Mac上基于hexo+GitHub搭建个人博客(一)
原文地址: http://fanjiajia.cn/2018/11/23/Mac%E4%B8%8A%E5%9F%BA%E4%BA%8Ehexo+GitHub%E6%90%AD%E5%BB%BA%E4% ...