实现步骤

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动态代理的更多相关文章

  1. 对JDK动态代理的模拟实现

    对JDK动态代理的模拟 动态代理在JDK中的实现: IProducer proxyProduec = (IProducer)Proxy.newProxyInstance(producer.getCla ...

  2. 动态代理学习(一)自己动手模拟JDK动态代理

    最近一直在学习Spring的源码,Spring底层大量使用了动态代理.所以花一些时间对动态代理的知识做一下总结. 我们自己动手模拟一个动态代理 对JDK动态代理的源码进行分析 文章目录 场景: 思路: ...

  3. Spring中的JDK动态代理

    Spring中的JDK动态代理 在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层 ...

  4. AOP学习心得&jdk动态代理与cglib比较

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...

  5. Spring AOP详解 、 JDK动态代理、CGLib动态代理

    AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码 ...

  6. JDK动态代理与Cglib库

    JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...

  7. 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理

    Spring AOP详解 . JDK动态代理.CGLib动态代理  原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...

  8. 设计模式之jdk动态代理模式、责任链模式-java实现

    设计模式之JDK动态代理模式.责任链模式 需求场景 当我们的代码中的类随着业务量的增大而不断增大仿佛没有尽头时,我们可以考虑使用动态代理设计模式,代理类的代码量被固定下来,不会随着业务量的增大而增大. ...

  9. JDK动态代理给Spring事务埋下的坑!

    一.场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下: 1.场景A ...

随机推荐

  1. 最短路径问题 3.Bellman-Ford算法

    简要:Bellman-Ford算法计算的仍然是从一个点到其他所有点的最短路径算法,其时间复杂度是O(NE),N表示点数,E表示边数,不难看出,当一个图稍微稠密一点,边的数量会超过点数那么实际上效率是低 ...

  2. AVL重平衡细节——插入

    话说这个系列鸽了好久,之前在准备语言考试,就没管博客了,现在暑假咱们继续上路! 每当我们进行一次插入之后,整棵AVL树的平衡性就有可能发生改变,为了控制整棵树的高度,我们需要通过一系列变换(重平衡)来 ...

  3. CSS3实现加载数据动画2

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. android .9图制作

    andorid .9 图,可用于适配各种屏幕.制作的时候,很简单. 在stadio 里面,把鼠标放到图片的边界,点一下.这时候,图片的边缘会有黑块. 然后把鼠标放到黑块上,发现可以拉伸区域了. 这个区 ...

  5. Python简要标准库(3)

    shelve 若只需要一个简单的存储方案,那么shelve模块可以满足你大部分的需要,你所需要的只是为它提供文件名.shelve中唯一有趣的函数是open,在调用的时候他会返回一个Shelf对象 注意 ...

  6. 文本向量化及词袋模型 - NLP学习(3-1)

    分词(Tokenization) - NLP学习(1) N-grams模型.停顿词(stopwords)和标准化处理 - NLP学习(2)   之前我们都了解了如何对文本进行处理:(1)如用NLTK文 ...

  7. JavaSE复习(六)函数式接口

    函数式接口 有且仅有一个抽象方法的接口 @FunctionalInterface注解 一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错.需要注 意的是,即使 ...

  8. Python不同进制之间的转换

    不同的进制 二进制    0b101 以数字0和字母b打头的表示二进制数 如果出现大于等于2的数 会抛出SyntaxError异常 八进制    0711 以数字0打头的数字表示八进制数 如果出现大于 ...

  9. 如何创建LocalDB数据库和数据库实例

    LocalDB是SQL Server 2012带来的新特性,它是一个专门为开发人员量身定制的轻量级数据库,下面介绍如何使用它. 创建LocalDB数据库的方法: 打开服务器资源管理器,右键点击“数据连 ...

  10. 结对作业 -GUI四则运算

    目录: 一.前言(及项目地址) 二.PSP(planning) 三.结对编程中对接口的设计 四.计算模块接口的设计与实现过程 五.计算模块接口部分的性能改进 六.计算模块部分单元测试展示 七.计算模块 ...