模拟实现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 ...
随机推荐
- 博科brocade光纤交换机alias-zone的划分-->实操案例
一,图形化操作 光纤交换机作为SAN网络的重要组成部分,在日常应用中非常普遍,本次将以常用的博科交换机介绍基本的配置方法. 博科300实物图: 环境描述: 如上图,四台服务器通过各自的双HBA卡连接至 ...
- idea 常用设置
1.修改为Eclipse快捷键 File -> Settings -> Keymap => Keymaps改为 Eclipse copy 2.显示行号: File -> S ...
- BLE(Bluetooth Low Energy)---first part
原文地址:https://developer.android.com/guide/topics/connectivity/bluetooth-le.html#terms (本人是技术宅,翻译时候,只要 ...
- Java:Random函数及其种子的作用
伪随机(preundorandom):通过算法产生的随机数都是伪随机!! 只有通过真实的随机事件产生的随机数才是真随机!!比如,通过机器的硬件噪声产生随机数.通过大气噪声产生随机数 Random生成的 ...
- Hbase读写流程和寻址机制
写操作流程 (1) Client通过Zookeeper的调度,向RegionServer发出写数据请求,在Region中写数据. (2) 数据被写入Region的MemStore,直到MemStore ...
- 网页设计简史看设计&代码“隔膜”
本文来自网易云社区 作者:马宝 设计与代码之间隔膜所在?既然你诚心诚意地问了,我就大发慈悲地告诉你.为了防止地球被破坏,为了维护世界的和平,为了贯彻爱与真实的邪恶~,我是穿梭在前端与设计之间爱与美丽的 ...
- Qt C++ 并发,并行,多线程编程系列1 什么是并发
什么是并发,并发往简单来说就是两个或多个独立的任务同时发生,在我们的生活中也是随处可见.如果把每个人都当作一个独立的任务,那每个人可以相互独立的生活,这就是并发. 在计算机的系统里面,并发一般有两种, ...
- 怎么在windows10中关闭Windows Defender?
通过修改注册表,永久禁用Windows Defender 打开注册表编辑器. 按 Win +R键入regedit,点击确定. 定位需要修改的注册表 其路径如下 HKEY_LOCAL_MACHIN ...
- browsersync的安装与基本使用
browser-sync启动命令 Browsersync能让浏览器实时.快速响应您的文件更改(html.js.css.sass.less等)并自动刷新页面. 官网文档:http://www.brows ...
- packstack安装ironic
KVM Centos7.3虚机 安装openstack Pike版本, 其它版本安装方法类似. packstack目前对NetworkManager 还不支持,我们修改下配置: systemctl d ...