基于前一篇设计模式之代理模式,我们来深入分析下JDK动态代理是如何实现的,并自己实现JDK动态代理。
github代码:github动态代理代码,老铁,如果喜欢可以给看小星星,谢谢。
1、JDK动态代理原理分析
(1)通过被代理对象的引用,利用反射获取所有接口;
(2)通过Proxy类动态生成一个新类,并实现所有接口;
(3)反射调用时将增强的代码添加在被代理类目标方法前后;
(4)编译新生成的java类,并加载到JVM中。
核心类:InvocationHandler、Proxy、ClassLoader。
2、自己实现JDK动态代理
(1)首先我们将动态代理生成的对象写入磁盘文件,通过反编译查看生成的类。
package com.william.javacore.pattern.structure.proxy.jdk;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
/**
* @Author: WilliamDream
* @Description:
* @Date: 2017/6/22 16:01
*/
public class JdkDynamicProxyTest {
public static void main(String[] args) {
try{
Person obj = (Person)new HouseProxy().getInstance(new Renter());
System.out.println(obj.getClass());
obj.findHouse();
//把动态代理生成的对象写入磁盘文件
byte [] bytes = ProxyGenerator.generateProxyClass("$proxy0",new Class[]{Person.class});
FileOutputStream os = new FileOutputStream("D://$proxy0.class");
os.write(bytes);
os.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
(3)反编译后代码
import com.william.javacore.pattern.structure.proxy.jdk.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $proxy0 extends Proxy
implements Person
{
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final void findHouse()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.william.javacore.pattern.structure.proxy.jdk.Person").getMethod("findHouse", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
}
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
3、查看JDK生成的代理类
(1)创建接口类MyInvocationHandler
/**
* @Author: WilliamDream
* @Description:
* @Date: 2017/6/22 21:58
*/
public interface MyInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
(2)创建代理对象
package com.william.javacore.pattern.structure.proxy.myproxy;
import com.william.javacore.pattern.structure.proxy.jdk.Person;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Author: WilliamDream
* @Description:
* @Date: 2017/6/22 22:08
*/
public class MyHouseProxy implements MyInvocationHandler{
//保存被代理对象的引用
private Object target;
public Object getInstance(Person object) throws Exception {
this.target = object;
Class<?> clazz = target.getClass();
return MyProxy.newProxyInstance(new MyClassLoader(),clazz.getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.doBefore();
method.invoke(this.target,args);
this.doAfter();
return null;
}
private void doBefore(){
System.out.println("我是房产中介,我们有很多房源。");
}
private void doAfter(){
System.out.println("我带你去看房吧!");
}
}
(3)创建MyProxy类
package com.william.javacore.pattern.structure.proxy.myproxy;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @Author: WilliamDream
* @Description: 用于生成代码
* @Date: 2017/6/22 22:09
*/
public class MyProxy {
private static final String ln = "\r\n";
public static Object newProxyInstance(MyClassLoader loader,
Class<?>[] interfaces,
MyInvocationHandler h) {
try {
// 1、生成代理类$Proxy0.java
String codeStr = generateCode(interfaces);
System.out.println(codeStr);
//2、Java文件输出到磁盘
String filepath = MyProxy.class.getResource("").getPath();
File file = new File(filepath + "$Proxy0.java");
FileWriter fileWriter = new FileWriter(file);
fileWriter.write(codeStr);
fileWriter.close();
//3、动态的编译生成的类$Proxy0
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = compiler.getStandardFileManager(null,null,null);
Iterable iterable = manager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = compiler.getTask(null,null,null,null,null,null);
task.call();
manager.close();
Class proxyClass = loader.findClass("$Proxy0");
Constructor constructor = proxyClass.getConstructor(MyInvocationHandler.class);
return constructor.newInstance(h);
} catch (Exception e){
e.printStackTrace();
}
return null;
}
private static String generateCode(Class<?>[] interfaces){
//生成动态代理产生的类$proxy0的代码
StringBuffer sb = new StringBuffer();
sb.append("package com.william.javacore.pattern.structure.proxy.myproxy;" + ln);
sb.append("import com.william.javacore.pattern.structure.proxy.jdk.Person;" + ln);
sb.append("import java.lang.reflect.*;" + ln);
sb.append("public class $Proxy0 implements " + interfaces[0].getSimpleName() + "{" + 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 method : interfaces[0].getMethods()){
sb.append("public " + method.getReturnType().getName() + " " + method.getName() + "(){" + ln);
sb.append("try{" + ln);
sb.append("Method m = " + interfaces[0].getSimpleName() +".class.getMethod(\"" + method.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();
}
}
(4)创建MyClassLoader对象
package com.william.javacore.pattern.structure.proxy.myproxy;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
/**
* @Author: WilliamDream
* @Description:
* @Date: 2017/6/22 22:08
*/
public class MyClassLoader extends ClassLoader{
private File classPathFile;
public MyClassLoader(){
String classPath = MyClassLoader.class.getResource("").getPath();
this.classPathFile = new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = MyClassLoader.class.getPackage().getName() + "." + name;
if(classPathFile != null){
File classFile = new File(classPathFile,name.replace("\\.","/")+".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();
}
}
}
return super.findClass(name);
}
}
(5)测试
package com.william.javacore.pattern.structure.proxy.myproxy;
import com.william.javacore.pattern.structure.proxy.jdk.HouseProxy;
import com.william.javacore.pattern.structure.proxy.jdk.Person;
import com.william.javacore.pattern.structure.proxy.jdk.Renter;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
/**
* @Author: WilliamDream
* @Description:
* @Date: 2017/6/22 22:17
*/
public class MyProxyTest {
public static void main(String[] args){
try {
Person person = new Renter();
MyHouseProxy houseProxy = new MyHouseProxy();
Person p = (Person)houseProxy.getInstance(person);
p.findHouse();
//把动态代理生成的对象写入磁盘文件
/* byte [] bytes = ProxyGenerator.generateProxyClass("$proxy0",new Class[]{Person.class});
FileOutputStream os = new FileOutputStream("D://$proxy0.class");
os.write(bytes);
os.close();*/
} catch (Exception e){
e.printStackTrace();
}
}
}
总结:
1、Proxy生成的类以$开头,数字结尾,如果生成代理类有多个,数字自增。