模拟实现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) :C. Annoying Present(等差求和)
题目链接:http://codeforces.com/contest/1009/problem/C 解题心得: 题意就是一个初始全为0长度为n的数列,m此操作,每次给你两个数x.d,你需要在数列中选一 ...
- Hbase数据IO
场景及方案分析 场景1:logs --> HBase logs -> flume -> hfile -> import -> HBase (实时) csv导入HBase ...
- Mysql自学笔记
SQL(strucut query language) DDL (数据库定义语言)DML (数据库操作语言)DCL (数据库的控制语言)DTL (数据库的高级语言)查看版本的函数select vers ...
- mysql ON DUPLICATE KEY UPDATE、REPLACE INTO
INSERT INTO ON DUPLICATE KEY UPDATE 与 REPLACE INTO,两个命令可以处理重复键值问题,在实际上它之间有什么区别呢?前提条件是这个表必须有一个唯一索引或主键 ...
- Android PopupWindow 疑难杂症之宽度WRAP_CONTENT
一直以来都觉得 Android 中的 PopupWindow 不好用.主要有以下两点:1.宽度不好控制2.位置不好控制 今天单说第1点. 由于应用有好几种国家的语言,加上各设备宣染效果不完全一样,对p ...
- 最火的.NET开源项目[转]
综合类 微软企业库 微软官方出品,是为了协助开发商解决企业级应用开发过程中所面临的一系列共性的问题, 如安全(Security).日志(Logging).数据访问(Data Access).配置管理( ...
- 「暑期训练」「Brute Force」 Money Transfers (CFR353D2C)
题目 分析 这个Rnd353真是神仙题层出不穷啊,大力脑筋急转弯- - 不过问题也在我思维江化上.思考任何一种算法都得有一个“锚点”,就是说最笨的方法怎么办.为什么要这么思考,因为这样思考最符合我们的 ...
- DP入门(2)——DAG上的动态规划
有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 一.DAG模型 [嵌套矩形问题] 问题 ...
- websocket协议详解;
websocket是基于http协议,借用http协议来完成连接阶段的握手: 当连接建立后,浏览器和服务器之间的通信就和http协议没有关系了,b.s之间只用websocket协议来完成基本通信. = ...
- [org.hibernate.engine.jdbc.spi.SqlExceptionHelper]SQL Error: 1064, SQLState: 42000问题的解决办法
[org.hibernate.engine.jdbc.spi.SqlExceptionHelper]SQL Error: 1064, SQLState: 42000问题的解决办法. 出现这种情况的原因 ...