动态代理实现思路:
Moveable m = (Moveable) Proxy.newProxyInstance(ClassLoader, Interfaces, InvocationHandler);实现功能:通过Proxy的newProxyInstance返回代理对象
* 1.声明一段源码(动态产生代理)
* 2.编译源码(JDK Compiler API),产生新的类(代理类)
* 3.将这个类load到内存当中,产生一个新的对象(代理对象)
* 4.return 代理对象
由于对实现接口的任意对象的任意方法进行代理
1.Proxy.java:
package com.zy.proxyPrinciple;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import org.apache.commons.io.FileUtils;
public class Proxy {
public static Object newProxyInstance(Class infce) throws Exception {
// windows下的换行符
String rt = "\r\n";
//获取类中的所有方法
String methodStr = "";
for (Method m : infce.getMethods()) {
methodStr +=
"@Override"+ rt+
"public void "+m.getName()+"() {"+ rt+
"long starttime = System.currentTimeMillis();"+ rt+
"System.out.println(\"汽车开始行驶...\");"+ rt+
"m."+m.getName()+"();"+ rt+
"long endtime = System.currentTimeMillis();"+ rt+
"System.out.println(\"汽车结束行使..\" + (endtime - starttime) + \"毫秒\");"+ rt +
"}" ;
}
// 源码
// 返回的动态代理类(CarTimeProxy.java),注意"要用转义字符\,每行末尾加rt换行,jdk生成代理类、构造函数名字为$Proxy0
String str =
"package com.zy.proxyPrinciple;"+ rt+
"public class $Proxy0 implements "+infce.getName()+" {"+ rt+
"public $Proxy0("+infce.getName()+" m) {"+ rt+
"super();"+ rt+
"this.m = m;"+ rt+
"}"+ rt+
"private "+infce.getName()+" m;"+ rt+
methodStr + rt +
"}";
// 先创建java文件放置到对应的文件目录,再编译此java文件
// 获得当前的路径
// 放在bin目录下方便编译
String filename = System.getProperty("user.dir")
+ "/bin/com/zy/proxyPrinciple/$Proxy.java";
File file = new File(filename);
// 引入jar包,commons-io.jar,提供FileUtils快速写入内容到文件中
FileUtils.writeStringToFile(file, str);
return null;
}
}
2.Test.java:
package com.zy.proxyPrinciple;
public class Test {
public static void main(String[] args) throws Exception {
Proxy.newProxyInstance(Moveable.class);
}
}
3.将代理业务抽取出来对任意对象的任意方法起作用,动态的实现业务逻辑
创建事务处理器:
1> InvocationHandler.java接口:
package com.zy.proxyPrinciple;
import java.lang.reflect.Method;
public interface InvocationHandler {
public void invoke(Object o, Method m);
}
2>TimeHandler.java接口实现类:(把Proxy.java中写死的业务代码提取到相应的业务处理类)
package com.zy.proxyPrinciple;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TimeHandler implements InvocationHandler {
// 获取被代理类
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
@Override
public void invoke(Object o, Method m) {
try {
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶...");
// 调用代理类的方法
m.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行使.." + (endtime - starttime) + "毫秒");
} catch (Exception e) {
e.printStackTrace();
}
}
}
3>修改Proxy.java,将代理业务处理类作为参数传入代理对象
源码中创建InvocationHandler,并且import进来,import Method进来
package com.zy.proxyPrinciple;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import org.apache.commons.io.FileUtils;
public class Proxy {
public static Object newProxyInstance(Class infce,<span style="color:#ff6666;">InvocationHandler h</span>) throws Exception {
// windows下的换行符
String rt = "\r\n";
//获取类中的所有方法
String methodStr = "";
for (Method m : infce.getMethods()) {
methodStr += "@Override"+ rt+
"public void "+m.getName()+"() {"+ rt+
"try{"+ rt+
<span style="color:#ff6666;">"Method md = "+infce.getName() +".class.getMethod(\""
+m.getName()+"\");"+ rt+
"h.invoke(this,md);"+ rt+</span>
"}catch(Exception e){e.printStackTrace();}"+ rt+
"}" ;
}
// 源码
// 返回的动态代理类(CarTimeProxy.java),注意"要用转义字符\,每行末尾加rt换行,jdk生成代理类、构造函数名字为$Proxy0
String str =
"package com.zy.proxyPrinciple;"+ rt+
<span style="color:#ff6666;"> "import com.zy.proxyPrinciple.InvocationHandler;"+ rt+
"import java.lang.reflect.Method;"+ rt+</span>
"public class $Proxy0 implements "+infce.getName()+" {"+ rt+
"public $Proxy0(InvocationHandler h) {"+ rt+
"super();"+ rt+
"this.h = h;"+ rt+
"}"+ rt+
<span style="color:#ff6666;"> "private InvocationHandler h;"+ rt+</span>
methodStr + rt +
"}";
// 1、产生代理类的java文件
// 获得当前的路径
// 放在bin目录下方便编译
String filename = System.getProperty("user.dir")
+ "/bin/com/zy/proxyPrinciple/$Proxy0.java";
File file = new File(filename);
// 引入jar包,commons-io.jar,提供FileUtils快速写入内容到文件中
FileUtils.writeStringToFile(file, str);
//2、编译代理类的java文件
//拿到编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
//文件管理者
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,null,null);
//获取文件
Iterable utils = fileMgr.getJavaFileObjects(filename);
//编译任务
//参数:输出位置,fileMgr,监听器,国际化参数,国际化参数,要编译的文件
CompilationTask t = compiler.getTask(null,fileMgr,null,null,null,utils);
//进行编译
t.call();
fileMgr.close();
//3、编译好的文件load到内存中
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class c = cl.loadClass("com.zy.proxyPrinciple.$Proxy0");
//4、根据代理类的构造方法创建代理类并返回
Constructor ctr = c.getConstructor(<span style="color:#ff6666;">InvocationHandler.class</span>);
<span style="color:#ff6666;"> return ctr.newInstance(h);</span>
}
}
4>测试类:Test.java
package com.zy.proxyPrinciple;
public class Test {
public static void main(String[] args) throws Exception {
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class, h);
m.move();
}
}
Proxy.java:声明动态源码,产生动态代理 --> 源码生成java文件 --> 对java文件进行编译 --> 将编译好的java文件load到内存中 --> 产生代理类的对象
Test.java: 定义一个InvocationHandler专门进行代理业务处理(计时功能、日志功能等) --> 产生代理对象时把InvocationHandler传进去
面向切面编程(InvocationHandler): 在方法的前后增加逻辑处理