该文学习资源来自https://www.imooc.com/video/5063
引言:当有无数个代理类的话,传统做法要写100个代理类,显然这样子类会过于膨胀,那么有没有一种方法,可以动态产生代理,实现对不同类,不同方法的代理。
动态代理:JDK的动态代理,ca
在代理类和被代理类之间加入了InvocationHander的一个类,也叫事务处理器。
被代理类:
package com.imooc.jdkproxy;
import com.imooc.jdkproxy.Moveable;
import java.util.Random;
public class Car implements Moveable {
@Override
public void move() {
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
被代理类的方法:
package com.imooc.jdkproxy;
/**
* Created by Administrator on 2018/9/4.
*/
public interface Moveable {
void move();
}
事物处理器:
public class TimeHandler implements InvocationHandler{
private Object target;
public TimeHandler(Object target) {
this.target = target;
}
//proxy,被代理对象;
//method 被代理对象的方法;
//方法的参数
//
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime=System.currentTimeMillis();
System.out.println("汽车开始行驶....");
method.invoke(target);// target为被代理对象
long endTime=System.currentTimeMillis();
System.out.println("汽车结束行驶.... 汽车行驶时间:"+(endTime-startTime)+"毫秒!");
return null;//该示例中car的move()没有返回值
}
}
测试类:
package com.imooc.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* Created by Administrator on 2018/9/4.
*/
public class Test {
public static void main(String [] args){
Car car=new Car();
InvocationHandler h=new TimeHandler(car);
Class<?> cls =car.getClass();
/**
* loader 类加载器
* interfaces 实现接口
* h InvocationHandler
*/
Moveable m=(Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h);//生成动态代理类,返回的值都代理类,都实现了movable接口
m.move();//调用返回动态代理的move方法
}
}
run: 在move方法的基础上,增加了时间的代理方法。
JDK动态的代理的原理和内部实现:
procy:
package com.imooc.proxy;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
import org.apache.commons.io.FileUtils;
//定义一个静态方法,返回一个代理对象
//第一步声明一段源码
public class Proxy {
//(Class infce)把我们需要实现的接口传递过来
public static Object newProxyInstance(Class infce) throws Exception{
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(\"汽车结束行驶.... 汽车行驶时间:\" " + rt +
" + (endtime - starttime) + \"毫秒!\");" + rt +
" }" ;
}
String str =
"package com.imooc.proxy;" + 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文件进行编译
String filename = System.getProperty("user.dir") +"/bin/com/imooc/proxy/$Proxy0.java";//文件的路径取当前应用所在的路径,然后放在bin目录下
File file = new File(filename);
FileUtils.writeStringToFile(file, str);//将这段源码生成到我们的java文件当中;
//编译
//得到当前系统的编译器
JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
//文件管理者
StandardJavaFileManager fileMgr =
complier.getStandardFileManager(null, null, null);
//获取文件
Iterable units = fileMgr.getJavaFileObjects(filename);
//编译任务
CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
//进行编译
t.call();
fileMgr.close();
//编译好的文件()代理类load 到内存
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class c = cl.loadClass("com.imooc.proxy.$Proxy0");//loader文件名
//产生代理对象
Constructor ctr = c.getConstructor(infce);
return ctr.newInstance(new Car());
}
}
测试类:
package com.imooc.proxy;
public class Client {
/**
* 测试类
* @throws Exception
*/
public static void main(String[] args) throws Exception {
Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class);//产生一个代理对象,并实现Moveable接口
m.move();
}
}
这样子就好了,但是我们会发现以上代码中,业务逻辑是写死的,也就是我们要怎么做才能适用于任意类和任意方法呢?
--------即,我们需要在动态代理中添加 InvocationHandler;
package com.imooc.proxy;
import java.lang.reflect.Method;
/**
* Created by Administrator on 2018/9/14.
*/
public interface InvocationHandler{
public void invoke(Object o,Method m);//invoke 对某个对象的方法进行处理。
}
修改我们的proxy类:
package com.imooc.proxy;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
import org.apache.commons.io.FileUtils;
public class Proxy {
@SuppressWarnings("unchecked")
public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{
String rt = "\r\n";
String methodStr = "";
for(Method m : infce.getMethods()){
methodStr += " @Override" + rt +
" public void " + m.getName() + "() {" + rt +
" try{" + rt +
" Method md = " + infce.getName() + ".class.getMethod(\""
+ m.getName() + "\");" + rt +
" h.invoke(this,md);" +rt+
" }catch(Exception e){ e.printStackTrace();}" + rt +
" }" ;
}
String str =
"package com.imooc.proxy;" + rt +
"import java.lang.reflect.Method;" + rt +
"import com.imooc.proxy.InvocationHandler;" + rt+
"public class $Proxy0 implements " + infce.getName() + " {" + rt +
" public $Proxy0(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
" private InvocationHandler h;" + rt+
methodStr + rt +
"}" ;
//产生代理类的java文件
String filename = System.getProperty("user.dir") +"/bin/com/imooc/proxy/$Proxy0.java";
File file = new File(filename);
FileUtils.writeStringToFile(file, str);
//编译
//拿到编译器
JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
//文件管理者
StandardJavaFileManager fileMgr =
complier.getStandardFileManager(null, null, null);
//获取文件
Iterable units = fileMgr.getJavaFileObjects(filename);
//编译任务
CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
//进行编译
t.call();
fileMgr.close();
//load 到内存
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class c = cl.loadClass("com.imooc.proxy.$Proxy0");
Constructor ctr = c.getConstructor(InvocationHandler.class);
return ctr.newInstance(h);
}
}
测试类:
package com.imooc.proxy;
public class Client {
/**
* 测试类
* @throws Exception
*/
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();
}
}