今天刚好讲了JDK动态代理,于是想自己写个JDK动态
首先看下JDK动态代理源码中的Proxy类中的newProxyInstance方法中所需要的参数
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
- 第一个是目标类的类加载器
- 第二个是目标了所继承的所有接口
- 第三个是传入一个InvocationHandler接口
先说下自己的思路
- 先通过传入的interfaces参数获取接口和方法去创建代理对象的java类
- 通过JavaCompiler去把.java类编译成字节码文件
- 通过类加载器加载字节码文件到jvm中并获得Class对象
- 通过Class类对象获取构造器,并通过构造器得到代理实例
- 返回代理实例
自己创建类Proxy一个和它一样的newProxyInstances方法
public static Object newProxyInstances(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler h){
}
CreateProxy类的create方法去创建代理对象的java类
public static String create(Class<?>[] interfaces) {
StringBuilder stringBuilder = new StringBuilder();
String rt = "\r\n";
//这个是获取代理类类名
className = ProxyUtils.getProxyClassName();
//这个for循环是导入接口类
for (Class<?> inter : interfaces) {
String name = inter.getName();
stringBuilder.append("import " + name).append(";").append(rt);
}
stringBuilder.append("import java.lang.reflect.InvocationHandler;").append(rt);
stringBuilder.append("import java.lang.reflect.Method;").append(rt);
//拼接目标对象的接口
stringBuilder.append("public class " + className + " implements ");
for (Class<?> inter : interfaces) {
String simpleName = inter.getSimpleName();
stringBuilder.append(simpleName).append(",");
}
stringBuilder.deleteCharAt(stringBuilder.length()-1);
stringBuilder.append("{").append(rt);
//定义一个类型为InvocationHandler类的h变量
stringBuilder.append("private InvocationHandler h;").append(rt);
//定义一个钩子方法
stringBuilder.append("public ")
.append(className)
.append("(InvocationHandler h){")
.append("this.h = h;")
.append("}").append(rt);
//下面是实现接口中的方法
for (Class<?> inter : interfaces){
Method[] methods = inter.getDeclaredMethods();
for (Method method : methods){
stringBuilder.append("@Override").append(rt);
stringBuilder.append("public ").append(method.getReturnType().getName())
.append(" "+method.getName()).append("(").append(ProxyUtils.getParameter(method.getParameterTypes()))
.append(") {").append(rt)
.append("\t")
.append("Object o = null;")
.append(rt)
.append("try {").append(rt)
.append("o = h.invoke(this,")
.append(inter.getName())
.append(".class.getDeclaredMethod(")
.append("\""+method.getName()+"\"");
if(!"".equals(ProxyUtils.getParameterClass(method.getParameterTypes()))){
stringBuilder.append(",")
.append(ProxyUtils.getParameterClass(method.getParameterTypes()));
}
stringBuilder.append(")")
.append(",")
.append("new Object[]{")
.append(ProxyUtils.getParameterName(method.getParameterTypes()))
.append("}")
.append(");")
.append(rt)
.append("}")
.append("catch (Throwable throwable) {")
.append(rt)
.append("throwable.printStackTrace();")
.append(rt)
.append("}").append(rt);
//判断返回值类型是否为void
if(!"void".equals(method.getReturnType().getName())){
stringBuilder.append("return ")
.append("(")
.append(method.getReturnType().getName())
.append(")o;")
.append(rt);
}
stringBuilder.append("}").append(rt);
}
}
stringBuilder.append("}");
return stringBuilder.toString();
}
炒鸡长花了我好长的时间
接着通过CreateProxy类的save方法把StringBuiler中的内容通过io流保存到类路径下
public static void save(String src){
//获取类路径
path = CreateProxy.class.getClassLoader().getResource("").getPath();
Writer writer = null;
try {
writer = new FileWriter(path+className+".java");
writer.write(src);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
然后就保存到这里啦!
接着把java文件编译成字节码文件,看一下Proxy$1.class
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import com.atguigu.target.Person;
import java.lang.reflect.InvocationHandler;
public class Proxy$1 implements Person {
private InvocationHandler h;
public Proxy$1(InvocationHandler var1) {
this.h = var1;
}
public void myInfo(String var1, int var2) {
Object var3 = null;
try {
this.h.invoke(this, Person.class.getDeclaredMethod("myInfo", String.class, Integer.TYPE), new Object[]{var1, var2});
} catch (Throwable var5) {
var5.printStackTrace();
}
}
public void say(String var1) {
Object var2 = null;
try {
this.h.invoke(this, Person.class.getDeclaredMethod("say", String.class), new Object[]{var1});
} catch (Throwable var4) {
var4.printStackTrace();
}
}
public String hello(String var1, String var2) {
Object var3 = null;
try {
var3 = this.h.invoke(this, Person.class.getDeclaredMethod("hello", String.class, String.class), new Object[]{var1, var2});
} catch (Throwable var5) {
var5.printStackTrace();
}
return (String)var3;
}
}
代码是CreateProxy的compile方法把java文件编译成字节码文件
public static void compile() {
//获取类路径下的java文件
File file = new File(path+className+".java");
//下面就是把java文件编译成字节码文件
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = javaCompiler.getStandardFileManager(null,null,null);
Iterable<? extends JavaFileObject> iterable = manager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = javaCompiler.getTask(null, manager, null, null, null, iterable);
task.call();
try {
manager.close();
} catch (IOException e) {
e.printStackTrace();
}
}
最后去填充自己创建的Proxy类中newProxyInstances方法
public static Object newProxyInstances(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler h){
//1.创建代理类的java文件
String s = CreateProxy.create(interfaces);
CreateProxy.save(s);
//2.把创建好的java文件编译成class文件
CreateProxy.compile();
//3.把class文件加载到内存中获取Class对象
try {
Class<?> aClass = classLoader.loadClass(CreateProxy.className);
//4.通过Class对象获取构造方法把InvocationHandler传入,创建代理对象
Constructor<?> constructor = aClass.getConstructor(InvocationHandler.class);
Object o = constructor.newInstance(h);
//5.返回代理对象
return o;
} catch (ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
接下来就是测试啦
- 先创建一个Person接口
- 在创建一个Student类去实现Person接口
Person接口
package com.atguigu.target;
public interface Person {
void say(String name);
void myInfo(String name,int age);
String hello(String name,String OtherName);
}
Student类
public class Student implements Person{
@Override
public void say(String name) {
System.out.println(name);
}
@Override
public void myInfo(String name, int age) {
System.out.println(name + age);
}
@Override
public String hello(String name, String OtherName) {
return name+"对"+OtherName+"打招呼";
}
}
接下来就是和java自带的JDK代理一样去获取代理类
package com.atguigu.test;
import com.atguigu.proxy.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyProxy {
private Object target;
public MyProxy(Object target){
this.target = target;
}
public Object createProxy(){
return Proxy.newProxyInstances(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("hello");
Object invoke = method.invoke(target, args);
System.out.println("good");
return invoke;
}
});
}
}
测试
public class MyTest {
public static void main(String[] args) {
Student student = new Student();
MyProxy myProxy = new MyProxy(student);
Person proxy = (Person) myProxy.createProxy();
proxy.say("zwb");
}
}
结果
hello
zwb
good
如果再次加入其它的接口也是可以动态的创建代理类的
只有一个Person接口时,的字节码反编译后的样子
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import com.atguigu.target.Person;
import java.lang.reflect.InvocationHandler;
public class Proxy$1 implements Person {
只实现了一个Person接口
让Studnet类加入Serializable接口和一个Man接口
package com.atguigu.target;
import java.io.Serializable;
public class Student implements Person,Serializable,Man{
@Override
public void say(String name) {
System.out.println(name);
}
@Override
public void myInfo(String name, int age) {
System.out.println(name + age);
}
@Override
public String hello(String name, String OtherName) {
return name+"对"+OtherName+"打招呼";
}
@Override
public void gander() {
System.out.println("我是一个男的");
}
}
再次测试
public class MyTest {
public static void main(String[] args) {
Student student = new Student();
MyProxy myProxy = new MyProxy(student);
//注意:JDk是通过接口代理的,所以必须用接口接收类
Man proxy = (Man) myProxy.createProxy();
proxy.gander();
}
}
看下反字节码反编译后的文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import com.atguigu.target.Man;
import com.atguigu.target.Person;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
public class Proxy$1 implements Person, Serializable, Man {
private InvocationHandler h;
public Proxy$1(InvocationHandler var1) {
this.h = var1;
}
public void say(String var1) {
Object var2 = null;
try {
this.h.invoke(this, Person.class.getDeclaredMethod("say", String.class), new Object[]{var1});
} catch (Throwable var4) {
var4.printStackTrace();
}
}
public String hello(String var1, String var2) {
Object var3 = null;
try {
var3 = this.h.invoke(this, Person.class.getDeclaredMethod("hello", String.class, String.class), new Object[]{var1, var2});
} catch (Throwable var5) {
var5.printStackTrace();
}
return (String)var3;
}
public void myInfo(String var1, int var2) {
Object var3 = null;
try {
this.h.invoke(this, Person.class.getDeclaredMethod("myInfo", String.class, Integer.TYPE), new Object[]{var1, var2});
} catch (Throwable var5) {
var5.printStackTrace();
}
}
public void gander() {
Object var1 = null;
try {
var1 = this.h.invoke(this, Man.class.getDeclaredMethod("gander"), new Object[0]);
} catch (Throwable var3) {
var3.printStackTrace();
}
}
}
成功!!!!!!!
如果有什么地方不足请多多指出,有什么更好的方法可以私信我,谢谢啦!!!