由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了
动态代理类 :
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
话不多说看代码。。 。
package proxyBase;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class MyProxy {
static Class<?>[] parameterTypes = { InvocationHandler.class };
protected InvocationHandler h;
protected MyProxy(InvocationHandler h) {
this.h = h;
}
public static Object newInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {
// :产生一个代理类的字节码对象
Class<?> c1 = null;
try {
// :通过getClass0方法可以得到一个代理类的字节码对象
c1 = getClass0(loader, interfaces);
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
Constructor<?> constructor = null;
try {
/**
* 调用子类$Proxy0(InvocationHandler h)构造函数,由于继承了MyProxy类,
* 所以又会继续调用父类的MyProxy(InvocationHandler h)构造函数给 h初始化一个值;
*/
constructor = c1.getDeclaredConstructor(InvocationHandler.class);
/**
* 返回一个生成的代理类对象,并将InvocationHandler 的实现类对象传入进去。从而达到给h赋值的目的
*
*/
return constructor.newInstance(h);
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
// :用来生成一个代理类对象
private static Class<?> getClass0(ClassLoader loader, Class<?>[] interfaces) throws MalformedURLException {
Class<?> forName = null;
try {
GennerateClass.generate(interfaces[0]);
// :动态编译
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(System.getProperty("user.dir") + "/src/"
+ interfaces[0].getPackage().getName() + "/" + interfaces[0].getSimpleName() + "$proxy0.java");
// :"-d", System.getProperty("user.dir")+"/bin/" 用来指定java文件编译后存放的地方
Iterable<String> options = Arrays.asList("-d", System.getProperty("user.dir") + "/bin/");
CompilationTask t = compiler.getTask(null, fileMgr, null, options, null, units);
t.call();
try {
fileMgr.close();
} catch (IOException e) {
e.printStackTrace();
}
// :得到代码自动生成代理类的实例对象
forName = Class.forName(interfaces[0].getName() + "$proxy0");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return forName;
}
}
这个GennerateClass类是用来生成代理类的Java文件的,是通过字符串拼接而成,仅供参考.
1 package proxyBase;
2
3 import java.io.BufferedWriter;
4 import java.io.File;
5 import java.io.FileWriter;
6 import java.io.IOException;
7 import java.lang.reflect.Method;
8
9 public class GennerateClass {
10 public static void generate(Class<?> clazz) {
11 String methodStr = ""; //:方法字符串的拼接
12 String classStr = ""; //:类名的拼接
13 String packageStr = ""; //:导入包名的拼接
14 String classParamStr = ""; //:
15 String staticCodeStr = "static {/ntry {";//:静态代码块的拼接
16 String member_var = ""; //:成员变量的拼接
17 String package1 = clazz.getPackage().getName();
18 String simpleName = clazz.getSimpleName(); //:获得简单类名
19 String className = clazz.getName(); //:获得权限定类名
20 //:构造函数的拼接
21 String counstructStr = "public " + simpleName + "$proxy0(InvocationHandler h) {/r/n" + " super(h);/r"
22 + " }/n";
23 // :导包
24 packageStr = "package " + package1 + ";/n"
25 + "import proxyBase.MyProxy;/r import java.lang.reflect.InvocationHandler;/n"
26 + "import java.lang.reflect.Method;/n";
27 // :构建类名
28 classStr += "public class " + simpleName + "$proxy0 extends MyProxy implements " + simpleName + "{/n" + "";
29 // :构建代理类的方法
30 Method[] methods = clazz.getMethods();
31 int i = 0;
32 for (Method method : methods) {
33 String paramStr = "";//:参数变量拼接
34 int paramCount = 0; //:参数个数计数用来生成参数变量
35 i += 1;
36 member_var += "private static Method m" + i + ";/n";//成员变量的拼接
37 String tempStr = ""; //:参数列表
38 String methodName = method.getName();// 方法名
39 Class<?>[] parameterTypes = method.getParameterTypes();// 参数列表的class类型
40 Class<?> returnType = method.getReturnType();// 返回值类型
41 methodStr += "public final " + returnType.getName() + " " + methodName + "(";
42 // :参数列表名字符串
43 for (Class<?> type : parameterTypes) {
44 paramCount += 1;
45 tempStr += "," + type.getName() + " param" + paramCount;
46 paramStr += ",param" + paramCount;
47 classParamStr += "," + type.getName() + ".class";
48 }
49 //:
50 if (!paramStr.isEmpty()) {
51 paramStr = paramStr.substring(1);
52 }
53 if (!tempStr.isEmpty()) {
54 tempStr = tempStr.substring(1);
55 }
56 if (classParamStr.isEmpty()) {
57 classParamStr = "null";
58 } else {
59 classParamStr = classParamStr.substring(1);
60 }
61 //:判断返回值是否时void,是则不需要return
62 //方法的拼接
63 if (returnType.getName().equals("void")) {
64 methodStr = methodStr + tempStr + ")/n{/n" + "/ttry{/n/tthis.h.invoke(this,m" + i + ",new Object[]{"
65 + paramStr + "});" + "} catch (Throwable e) {/r/n" + " e.printStackTrace();/r/n"
66 + " }/n}/n";
67 } else {
68 methodStr = methodStr + tempStr + ")/n{/nObject result=null;/n/ttry{/n/tresult=this.h.invoke(this,m" + i
69 + ",new Object[]{" + paramStr + "});" + "} catch (Throwable e) {/r/n"
70 + " e.printStackTrace();/r/n" + "}/nreturn (" + returnType.getName() + ")result;}/n";
71 }
72 // :构建静态代码块
73 if (!classParamStr.equals("null")) {
74 staticCodeStr += "m" + i + " = Class.forName(/"" + className + "/").getMethod(/"" + methodName
75 + "/",new Class<?>[]{" + classParamStr + "});";
76 } else {
77 staticCodeStr += "m" + i + " = Class.forName(/"" + className + "/").getMethod(/"" + methodName + "/");";
78 }
79 classParamStr = "";
80 }
81 //静态代码块的拼接
82 staticCodeStr += "} catch (NoSuchMethodException e) {/r/n" + " e.printStackTrace();/r/n"
83 + " } catch (SecurityException e) {/r/n" + " e.printStackTrace();/r/n"
84 + " } catch (ClassNotFoundException e) {/r/n" + " e.printStackTrace();/r/n" + " }}";
85 //总和成Java文件的内容
86 packageStr = packageStr + classStr + member_var + counstructStr + methodStr + staticCodeStr + "/n}";
87 //通过流写入成文件
88 FileWriter fout = null;
89 try {
90 fout = new FileWriter(new File("src/" + package1 + "/" + simpleName + "$proxy0.java"));
91 } catch (IOException e) {
92
93 e.printStackTrace();
94 }
95 BufferedWriter out = new BufferedWriter(fout);
96 try {
97 out.write(packageStr);
98 } catch (IOException e) {
99 e.printStackTrace();
100 }
101 try {
102 out.close();
103 fout.close();
104 } catch (IOException e) {
105 e.printStackTrace();
106 }
107 }
108 }
View Code
/***
*这个类是用来制定你的代理对象,在调用方法时需要进行哪些前置处理和后置处理
*
*/
1 package proxyBase;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5
6 public class Hadler<T> implements InvocationHandler {
7 private T target;
8 //通过new Hadler将被代理的那个对象传入,
9 public Hadler(T target) {
10 super();
11 this.target = target;
12 }
13 private void before() {
14 System.out.println("先吃饭");
15 }
16 private void after() {
17 System.out.println("再睡觉");
18 }
19 //这里根据自己的逻辑来制定相应的invoke方法,视情况而定,此处的写法只是来简单测试代理对象。
20 @Override
21 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
22 before();
23 Object invoke = method.invoke(target,args);
24 after();
25 return invoke;
26 }
27 }
这里时生成后的代理类文件Person$proxy0.java
package proxyBase;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class Hadler<T> implements InvocationHandler {
private T target;
//通过new Hadler将被代理的那个对象传入,
public Hadler(T target) {
super();
this.target = target;
}
private void before() {
System.out.println("先吃饭");
}
private void after() {
System.out.println("再睡觉");
}
//这里根据自己的逻辑来制定相应的invoke方法,视情况而定,此处的写法只是来简单测试代理对象。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object invoke = method.invoke(target,args);
after();
return invoke;
}
}
接下来是写一个接口,jdk中的动态代理是针对接口代理的,而cglib是针对类进行代理的,这个接口将会被代理,分别写了四个方法来测试,无参,一参,两参,和一个有返回值
的方法,都是用来测试GennerateClass类生成的是否正确,(目前只测试了这几种,如果大神发现有误,还望联系斧正)
1 package proxy;
2
3
4 public interface Person {
5 void study2();
6 void study2(int a);
7 void study3(int b ,String a);
8 int returnInt(int a);
9 }
接下来写一个Person的实现类,然后通过代理类来代理这个实现类对象,进行一些前置处理和后置处理。
1 package proxy;
2
3 public class Student implements Person {
4 public void study2() {
5 System.out.println("正在考试中");
6 }
7
8 @Override
9 public void study2(int a) {
10 System.out.println(a);
11 }
12
13 @Override
14 public void study3(int b, String a) {
15 System.out.println(a+b);
16 }
17
18 @Override
19 public int returnInt(int a) {
20
21 return a;
22 }
23 }
最后就是测试和使用所写的代理类了
第一步,创建一个Person类型的对象student,
第二步,创建一个InvocationHandler的实现类对象,并将student传入进去,这个student会将生成实现类中的成员变量target进行赋值初始化。
第三步,调用MyProxy中的newInstance方法来获得代理类对象(注意:newInstance 中的参数要是实现类的类类型来获得他的实现Interface接口的类类型,即Person,生成代理类的Java文件就是依据该接口生成的)
第四步, 测试生成的代理类对象,结果如下,通过原生student和代理类对象stu调用相同方法进行对比
1 public static void main(String[] args) {
2 Person student = new Student();
3
4 InvocationHandler h = new Hadler<Person>(student);
5 Person stu = (Person) MyProxy.newInstance(Person.class.getClassLoader(), Student.class.getInterfaces(), h);
6 stu.study2();
7 System.out.println("-------");
8 student.study2();
9 stu.study2(4);
10 stu.study3(4, "A");
11 int a = stu.returnInt(2015);
12 System.out.println(a);
13 }
运行结果:
先吃饭 正在考试中 再睡觉 ------- 正在考试中 先吃饭 4 再睡觉 先吃饭 A4 再睡觉 先吃饭 再睡觉 2015