自己动手实现JDK动态代理

 

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

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

引言

项目结构如下图所示,maven项目

image

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)处不同
image-w500

针对(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动态代理类

 

引言

项目结构如下图所示,maven项目

image

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)处不同
image-w500

针对(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动态代理类

猜你喜欢

转载自www.cnblogs.com/shoshana-kong/p/9110612.html
今日推荐