引言

项目结构如下图所示,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步

  1. 生成java源碼
  2. 將源码输出到java文件中
  3. 将java文件编译成class文件
  4. 将class加载进jvm
  5. 返回代理类对象

具体代码如下

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

  1. 【原创】分布式之缓存击穿 【原创】自己动手实现静态资源服务器 【原创】自己动手实现JDK动态代理

    [原创]分布式之缓存击穿   什么是缓存击穿 在谈论缓存击穿之前,我们先来回忆下从缓存中加载数据的逻辑,如下图所示 因此,如果黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查 ...

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

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

  3. 自己动手实现JDK动态代理

    出自:作者:孤独烟  http://rjzheng.cnblogs.com/ ------------------------------------------------------------- ...

  4. Java JDK 动态代理使用及实现原理分析

    转载:http://blog.csdn.net/jiankunking   一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理 ...

  5. 【原创】JDK动态代理,此次之后,永生难忘。

    动态代理,这个词在Java的世界里面经常被提起,尤其是对于部分(这里强调“部分”二字,因为有做了一两年就成大神的,实力强的令人发指,这类人无疑是非常懂动态代理这点小伎俩的)做了一两年新人来说,总是摸不 ...

  6. JDK动态代理

    一.基本概念 1.什么是代理? 在阐述JDK动态代理之前,我们很有必要先来弄明白代理的概念.代理这个词本身并不是计算机专用术语,它是生活中一个常用的概念.这里引用维基百科上的一句话对代理进行定义: A ...

  7. jdk动态代理与cglib代理、spring aop代理实现原理

    原创声明:本博客来源与本人另一博客[http://blog.csdn.net/liaohaojian/article/details/63683317]原创作品,绝非他处摘取 代理(proxy)的定义 ...

  8. jdk动态代理与cglib代理、spring aop代理实现原理解析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

  9. 何为代理?jdk动态代理与cglib代理、spring Aop代理原理浅析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

随机推荐

  1. 【重要】使用Git命令行上传到GitHub上

    [本人GitHub账号:] 用户名:chenhongshuang 密码:shuangshuang6300 邮箱:2452420371@qq.com 进入GitHub账号后 1·新建项目文件名称例dem ...

  2. new Date的兼容性问题

    标准浏览器下正常,结果ie.老版本的IOS微信公众号不支持,搞不懂,原来有兼容性问题 //beginData格式为'yyyy-mm-dd' 1 var _date = new Date(Date.pa ...

  3. ng-if ng-show ng-hide区别(面试题)

    ng-if ng-show  ng-hide区别 实现原理方面: ng-show/ng-hide是通过修改css样式方式控制元素显示与隐藏,对应的DOM元素会一直存在于当前页面中: 而ng-if根据表 ...

  4. ReactiveCocoa--RACTuple

    基本信息 例子 [[self rac_signalForSelector:@selector(tableView:didSelectRowAtIndexPath:) fromProtocol:@pro ...

  5. Java基础学习笔记总结

    Java基础学习笔记一 Java介绍 Java基础学习笔记二 Java基础语法之变量.数据类型 Java基础学习笔记三 Java基础语法之流程控制语句.循环 Java基础学习笔记四 Java基础语法之 ...

  6. Java基础学习笔记十二 类、抽象类、接口作为方法参数和返回值以及常用API

    不同修饰符使用细节 常用来修饰类.方法.变量的修饰符 public 权限修饰符,公共访问, 类,方法,成员变量 protected 权限修饰符,受保护访问, 方法,成员变量 默认什么也不写 也是一种权 ...

  7. React Native 轻松集成统计功能(Android 篇)

    关于推送的集成请参考这篇文章,本篇文章将引导你集成统计功能,只需要简单的三个步骤就可以集成统计功能. 第一步 安装 在你的项目路径下执行命令: npm install janalytics-react ...

  8. 云计算之路-阿里云上-容器难容:优化自建 docker swarm 集群的部署

    在上周六遭遇阿里云容器服务 swarm 版的故障之后,我们决定还是走自建 docker swarm 之路,只要不是阿里云底层的问题,我们相信会找到办法解决或避开自建 docker swarm 不稳定的 ...

  9. web面试题

    1.你做的页面在哪些流览器测试过?这些浏览器的内核分别是什么? Ie(Ie内核) 火狐(Gecko) 谷歌(webkit) opear(Presto)

  10. 网络1712--c语言字符数组作业总结..

    ---恢复内容开始--- 作业亮点 1.总体情况 1.大部分同学利用了流程图后,对于思路的理解有了提升. 2.很多同学在总结方面写的很不错,能够罗列问题贴出解决问题,我们能够看到你们的进步 2.作业发 ...