【原创】自己动手实现JDK动态代理
引言
项目结构如下图所示,maven项目
1、JDK动态代理
先来一段jdk动态代理的demo,
首先创建一个接口,Person
package bean;
public interface Person {
public void eat();
}
然后写一个实现类PersonImpl
package bean;
public class PersonImpl implements Person{
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("time to eat ");
}
}
然后写个使用类PersonInvocationHandler
package jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PersonInvocationHandler implements InvocationHandler {
private Object obj;
public PersonInvocationHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("before time to eat");
method.invoke(obj, args);
System.out.println("after time to eat");
return null;
}
}
最后 再写个测试类
package jdk;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.lang.reflect.Proxy;
import sun.misc.ProxyGenerator;
import bean.Person;
import bean.PersonImpl;
public class jdkTest {
public static void main(String[] args) throws Exception {
PersonInvocationHandler personInvocationHandler = new PersonInvocationHandler(
new PersonImpl());
Person personProxy = (Person) Proxy.newProxyInstance(
PersonImpl.class.getClassLoader(),
PersonImpl.class.getInterfaces(), personInvocationHandler);
personProxy.eat();
}
}
输出如下
before time to eat
time to eat
after time to eat
接下里我们不使用JDK的API,自己实现一套代理类
2、自定义动态代理
先上测试类的代码,如下图所示,共有(1)(2)(3)处不同
针对(1),我们有如下代码,先抄袭JDK的InvocationHandler,改个名字成为MyInvocationHandler
package custom;
import java.lang.reflect.Method;
public interface MyInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
编写一个JAVA类MyPersonInvocationHandler继承MyInvocationHandler,这段代码与PersonInvocationHandler的代码无异,如下所示
package custom;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyPersonInvocationHandler implements MyInvocationHandler {
private Object obj;
public MyPersonInvocationHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("before time to eat");
method.invoke(obj, args);
System.out.println("after time to eat");
return null;
}
}
针对(2),我们实现一个自己的代理生成类MyProxy,其生成java代理类的步骤分为以下5步
- 生成java源碼
- 將源码输出到java文件中
- 将java文件编译成class文件
- 将class加载进jvm
- 返回代理类对象
具体代码如下
package custom;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class MyProxy {
public static final String ln = "\r\n";
public static Object newProxyInstance(MyClassLoader myClassLoder,
Class<?>[] interfaces, MyInvocationHandler h) {
try{
// 1 java源碼
String src = generateSrc(interfaces);
// 2 將源码输出到java文件中
String filePath = MyProxy.class.getResource("").getPath();
System.out.println(filePath);
File f = new File(filePath + "$Proxy0.java");
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//3、将java文件编译成class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
Iterable iterable = manage.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
task.call();
manage.close();
//4、将class加载进jvm
Class proxyClass=myClassLoder.findClass("$Proxy0");
f.delete();
//5、返回代理类对象
Constructor constructor = proxyClass.getConstructor(MyInvocationHandler.class);
return constructor.newInstance(h);
}catch(Exception e){
e.printStackTrace();
}
return null;
}
private static String generateSrc(Class<?>[] interfaces) {
// TODO Auto-generated method stub
StringBuffer sb = new StringBuffer();
sb.append("package custom;" + ln);
sb.append("import java.lang.reflect.Method;" + ln);
sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
sb.append("private MyInvocationHandler h;"+ln);
sb.append("public $Proxy0(MyInvocationHandler h) { " + ln);
sb.append("this.h = h;"+ln);
sb.append("}" + ln);
for (Method m : interfaces[0].getMethods()) {
sb.append("public " + m.getReturnType().getName() + " "
+ m.getName() + "() {" + ln);
sb.append("try{" + ln);
sb.append("Method m = " + interfaces[0].getName()
+ ".class.getMethod(\"" + m.getName()
+ "\",new Class[]{});" + ln);
sb.append("this.h.invoke(this,m,null);" + ln);
sb.append("}catch(Throwable e){" + ln);
sb.append("e.printStackTrace();" + ln);
sb.append("}"+ln);
sb.append("}"+ln);
}
sb.append("}" + ln);
return sb.toString();
}
}
针对(3),我们继承ClassLoader,实现一套自己的类加载机制MyClassLoader,如下所示,
package custom;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class MyClassLoader extends ClassLoader {
private File classPathfile;
public MyClassLoader() {
String classpth = MyClassLoader.class.getResource("").getPath();
classPathfile = new File(classpth);
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
String className = MyClassLoader.class.getPackage().getName() + "." +name;
if (classPathfile != null) {
File file = new File(classPathfile, name + ".class");
FileInputStream fileInputStream = null;
ByteArrayOutputStream outputStream = null;
try{
fileInputStream = new FileInputStream(file);
outputStream = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len;
while((len=fileInputStream.read(buff))!=-1){
outputStream.write(buff, 0, len);
}
return defineClass(className, outputStream.toByteArray(), 0, outputStream.size());
}catch(Exception e){
e.printStackTrace();
}finally{
if(null!=fileInputStream){
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(null!=outputStream){
try {
outputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
return null;
}
}
最后测试类代码如下所示
package custom;
import java.lang.reflect.Proxy;
import custom.MyPersonInvocationHandler;
import bean.Person;
import bean.PersonImpl;
public class CustomTest {
public static void main(String[] args) {
MyPersonInvocationHandler personInvocationHandler = new MyPersonInvocationHandler(
new PersonImpl());
Person personProxy = (Person) MyProxy.newProxyInstance(
new MyClassLoader(), PersonImpl.class.getInterfaces(),
personInvocationHandler);
personProxy.eat();
}
}
输出如何所示
before time to eat
time to eat
after time to eat
至此,我们已完全实现了一套自定义的jdk动态代理类
【原创】自己动手实现JDK动态代理的更多相关文章
- 【原创】分布式之缓存击穿 【原创】自己动手实现静态资源服务器 【原创】自己动手实现JDK动态代理
[原创]分布式之缓存击穿 什么是缓存击穿 在谈论缓存击穿之前,我们先来回忆下从缓存中加载数据的逻辑,如下图所示 因此,如果黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查 ...
- 动态代理学习(一)自己动手模拟JDK动态代理
最近一直在学习Spring的源码,Spring底层大量使用了动态代理.所以花一些时间对动态代理的知识做一下总结. 我们自己动手模拟一个动态代理 对JDK动态代理的源码进行分析 文章目录 场景: 思路: ...
- 自己动手实现JDK动态代理
出自:作者:孤独烟 http://rjzheng.cnblogs.com/ ------------------------------------------------------------- ...
- Java JDK 动态代理使用及实现原理分析
转载:http://blog.csdn.net/jiankunking 一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理 ...
- 【原创】JDK动态代理,此次之后,永生难忘。
动态代理,这个词在Java的世界里面经常被提起,尤其是对于部分(这里强调“部分”二字,因为有做了一两年就成大神的,实力强的令人发指,这类人无疑是非常懂动态代理这点小伎俩的)做了一两年新人来说,总是摸不 ...
- JDK动态代理
一.基本概念 1.什么是代理? 在阐述JDK动态代理之前,我们很有必要先来弄明白代理的概念.代理这个词本身并不是计算机专用术语,它是生活中一个常用的概念.这里引用维基百科上的一句话对代理进行定义: A ...
- jdk动态代理与cglib代理、spring aop代理实现原理
原创声明:本博客来源与本人另一博客[http://blog.csdn.net/liaohaojian/article/details/63683317]原创作品,绝非他处摘取 代理(proxy)的定义 ...
- jdk动态代理与cglib代理、spring aop代理实现原理解析
原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...
- 何为代理?jdk动态代理与cglib代理、spring Aop代理原理浅析
原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...
随机推荐
- delphi XE Datasnap SERVER 在windows 7 下为服务添加描述信息
网上对服务添加描述信息的,多数是用注册表的方式,而注册表的方式,我在win7 下测试,不知为什么,总是不行,把执行的CMD以管理员模式开启,还是没加进去. 于是在网上查到下面的代码,保存供叁考,原文博 ...
- PHP之取得当前时间函数方法
PHP之取得当前时间函数方法 PHP之取得当前时间函数方法文章提供了php的几种获取当前时间的函数,date,time等,同时告诉我如何解决时区问题.php教程取得当前时间函数文章提供了php的几种获 ...
- 警示:AL32UTF8字符集不是ZHS16GBK字符集的超集
今天有一个客户向我咨询:数据库由ZHS16GBK字符集修改为AL32UTF8字符集,发现中文的数据中小部分出现乱码,客户认为AL32UTF8明明可以支持更多的文字,不应该出现这样的情况才对. 从现象看 ...
- Spring Framework 简介
Spring Framework 依赖注入.事务管理.Web应用程序.数据访问.消息传递.测试和更多的核心支持. Tips: Spring 官网:https://spring.io/ spring f ...
- [jdoj1817]Drainage Ditches_网络流
Drainage Ditches jdoj-1817 题目大意:网络流裸求最大流 注释:n(点数),m(边数)<=200. 想法:裸的网络流求最大流,用bfs+dfs,美其名曰dinic. 没有 ...
- Dynamics 365 for CRM: Sitemap站点图的可视化编辑功能
Dynamics 365 for CRM 提供了Sitemap站点图的可视化编辑功能 在之前的所有版本中,我们只能通过从系统中导出站点图的XML进行编辑后再导入(容易出错),或使用第三方的Sitema ...
- beta冲刺 用户使用调查报告
测评结果 一.使用体验 数据加载响应很快,页面切换丝滑流畅. UI有点偏暗,有些字被覆盖了. 页面布局过于居中,两侧空白范围较大. 总体功能完善. 二.登录.注册.忘记密码界面 管理员登录按钮太靠下, ...
- 数据结构基础——结构体struct及类型别名typedef的使用
一.结构体的创建 在C语言中,实现数据结构的一种常用方法便是使用结构体(structure)其示例代码如下: struct stu { int num; char ch; }; struct表示创建结 ...
- day9
Alpha冲刺Day9 一:站立式会议 今日安排: 经过为期5天的冲刺,基本完成企业人员模块的开发.因第三方机构与企业存在委托的关系.第三方人员对于风险的自查.风险列表的展示以及自查风险的统计展示(包 ...
- C语言--第四周作业
一.题目7-1 计算分段函数[1] 1.代码 #include <stdio.h> int main () { float x,result; scanf("%f",& ...