实现步骤

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. js数组长度

    js数组长度,一般使用length 属性即可获取,但这个数组是个对象则只能使用以下方式 var t=typeof o; var length=0; if(t=='string'){ length=o. ...

  2. 初步学习pg_control文件之十三

    接前文,初步学习pg_control文件之十二 看这个: * backupStartPoint is the redo pointer of the backup start checkpoint, ...

  3. 4368: [IOI2015]boxes纪念品盒

    4368: [IOI2015]boxes纪念品盒 链接 分析 链接 代码 #include<bits/stdc++.h> using namespace std; typedef long ...

  4. RAID(冗余硬盘阵列)

    一. RAID定义 RAID( Redundant Array of Independent Disk 独立冗余磁盘阵列 )技术是加州大学伯克利分校1987年提出,最初是为了组合小的廉价磁盘来代替大的 ...

  5. linux 操作之一 如何在linux将本地数据*.sql文件导入到linux 云服务器上的mysql数据库

    liunx 版本ubuntu 16.4 mysql 版本  5.6 1)准备*.sql文件 (* 是准备导入的sql文件的名字) 2)liunx 远程客户端  SecureCRT 7.0 alt+p ...

  6. Hibernate-ORM:06.Hibernate中三种状态

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客主要叙述Hibernate中的三种状态:临时状态(瞬时状态),持久状态,游离状态 commit和flu ...

  7. 自动化测试--封装JDBCUnit

    在进行测试的时候,经常需要对数据库进行操作.我们知道,通过代码与数据库交互,需要以下几步: 1.加载驱动 之前有盆友问我,为什么Selenium操作浏览器的时候,非要下载浏览器驱动?为啥对数据库进行操 ...

  8. (Python爬虫01)-本想给随笔加个序号才发现这么不方便

    本想给随机加个序号,才发现还得去返回看看文章的序号.好在cnblog能断点自动保存. 作为一个小程序员,点赞的同时还在想,谁知道咋实现这种实时保存呢?有知道的给个参考文档呗.太感激了! 重点在这里 有 ...

  9. c# 把List<T>转成DataTable对象,批量导入Sqlserver库

    /// <summary> /// Sqlbulkcopies the specified SMS.批量插入到数据库 /// </summary> /// <param ...

  10. 最短路径——Bellman-Ford算法以及SPFA算法

    说完dijkstra算法,有提到过朴素dij算法无法处理负权边的情况,这里就需要用到Bellman-Ford算法,抛弃贪心的想法,牺牲时间的基础上,换取负权有向图的处理正确. 单源最短路径 Bellm ...