1.静态代理
代理的实现方式有两种,一是继承,二是聚合。示例如下:计算Tank中move方法的运行时间,不包括JDK为其准备运行环境的时间。
package com.zj.proxy;
public interface Moveable {
void move();
void stop();
}
package com.zj.proxy;
import java.util.Random;
public class Tank implements Moveable{
@Override
public void move() {
System.out.println("Tank moving.....");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void stop() {
System.out.println("Tank stop....");
}
}
package com.zj.proxy;
public class TankExtendProxy extends Tank{
/*
* 方法1:继承Tank,复写move方法,前后加上时间计时,然后相减。
* TankExtendProxy相当于Tank的代理:调用TankExtendProxy的move时,
* 总会调用TankExtendProxy父类的move,即相当于调用Tank的move。
*/
@Override
public void move() {
long start=System.currentTimeMillis();
super.move();
long end=System.currentTimeMillis();
//计算方法的运行时间
System.out.println("time="+(end-start));
}
}
package com.zj.proxy;
public class TankTimeProxy implements Moveable{
Moveable t;
public TankTimeProxy(Moveable t) {
super();
this.t = t;
}
/*
* 方法2:聚合(一个类中有另外一个类的对象)。Tank类型的成员变量,实现Moveable接口,复写move方法,调用Tank对象的move方法,前后加上时间计时,然后相减。
* TankTimeProxy相当于Tank的代理:调用TankTimeProxy的move即相当于调用Tank的move。
*/
@Override
public void move() {
long start=System.currentTimeMillis();
System.out.println("Time proxy: Start time....");
t.move();
long end=System.currentTimeMillis();
//计算方法的运行时间
System.out.println("Time proxy: run time= "+(end-start));
}
@Override
public void stop() {
}
}
package com.zj.proxy;
public class TankLogProxy implements Moveable{
Moveable t;
public TankLogProxy(Moveable t) {
super();
this.t = t;
}
@Override
public void move() {
System.out.println("Log Proxy: Tank start move....");
t.move();
System.out.println("Log Proxy: Tank stop....");
}
@Override
public void stop() {
}
}
package com.zj.proxy;
import org.junit.Test;
/*
* 1.代理的实现:计算move的运行时间,不包括JDK为其准备运行环境的时间
* 方法1:继承Tank,复写move方法,前后加上时间计时,然后相减。
* 方法2:聚合(一个类中有另外一个类的对象)。Tank类型的成员变量,实现Moveable接口,复写move方法,调用Tank对象的move方法,前后加上时间计时,然后相减。
*
* 2.上述两种方法都是对Tank的代理,问哪种方法好?
* 答:聚合比继承好。
*/
public class Client {
public static void main(String[] args) {
Moveable m=new Tank();
m.move();
}
//测试继承方式实现的代理
@Test
public void testTankExtendProxy() {
TankExtendProxy tep=new TankExtendProxy();
tep.move();
}
//测试聚合方式实现代理:先记录时间,后记录日志
@Test
public void testTimeLog(){
Tank t=new Tank();
TankTimeProxy ttp=new TankTimeProxy(t);
TankLogProxy tlp=new TankLogProxy(ttp);
Moveable m=tlp;
m.move();
}
//测试聚合方式实现代理:先记录日志,后记录时间
@Test
public void testLogTime(){
Tank t=new Tank();
TankLogProxy tlp=new TankLogProxy(t);
TankTimeProxy ttp=new TankTimeProxy(tlp);
Moveable m=ttp;
m.move();
}
}
2.动态代理
如果有很多对象,要想对任意对象、任意的接口方法,实现任意代理,又改怎么办呢?答案是动态代理,下面我们简单模拟JDK的动态代理。
package com.zj.proxy2;
public interface Moveable {
void move();
}
package com.zj.proxy2;
import java.util.Random;
public class Tank implements Moveable{
@Override
public void move() {
System.out.println("Tank moving.....");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.zj.proxy2;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
public class Proxy {
public static Object newProxyInstance(Class interf, InvocationHandler h) throws Exception{
/**********************source code*******************************/
String rt="\r\n";
String methodStr="";
Method[] methods= interf.getMethods();
for(Method m:methods){
methodStr += " @Override" + rt +
" public " + m.getReturnType()+" "+m.getName()+"(){" + rt +
" try {" + rt +
" Method md="+interf.getName()+".class.getMethod(\""+m.getName()+"\");"+ rt +
" h.invoke(this,md);" + rt +
" } catch(Exception e){e.printStackTrace();}" + rt +
" }";
}
String src=
"package com.zj.proxy2;" + rt +
"import java.lang.reflect.Method;" + rt +
"public class MyProxy implements "+interf.getName()+" {" + rt +
" InvocationHandler h;" + rt +
" public MyProxy(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
methodStr + rt +
"}";
//拿到系统的当前目录
String fileName=System.getProperty("user.dir")+"\\src\\com\\zj\\proxy2\\MyProxy.java";
//System.out.println(fileName);//输出结果为F:\sys_zj\Proxy\src\com\zj\proxy2\MyProxy.java
File f=new File(fileName);
FileWriter fw=new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
/**********************compile*******************************/
//Java的编译器,调用ToolProvider.getSystemJavaCompiler()可以拿到系统当前默认的Java编译器,即Javac
JavaCompiler compiler =ToolProvider.getSystemJavaCompiler();
//System.out.println(compiler.getClass().getName());//输出结果为com.sun.tools.javac.api.JavacTool
StandardJavaFileManager fileMgr=compiler.getStandardFileManager(null, null, null);
Iterable units=fileMgr.getJavaFileObjects(fileName);
CompilationTask t=compiler.getTask(null, fileMgr, null, null, null, units);
t.call();//调用任务,编译
fileMgr.close();
/**********************load into memory*******************************/
//把硬盘上的java文件放到内存中
URL[] urls=new URL[]{new URL("file:\\"+ System.getProperty("user.dir")+"\\src")};
URLClassLoader ul=new URLClassLoader(urls);
Class c=ul.loadClass("com.zj.proxy2.MyProxy");
//System.out.println(c);//输出结果为class com.zj.proxy2.MyProxy
/**********************create an instance*******************************/
//拿到构造方法
Constructor ctr=c.getConstructor(InvocationHandler.class);
//获得代理对象
Object obj=ctr.newInstance(h);
return obj;
}
}
package com.zj.proxy2;
import java.lang.reflect.Method;
public interface InvocationHandler {
public void invoke(Object obj,Method m);
}
package com.zj.proxy2;
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 obj,Method m) {
long start=System.currentTimeMillis();
System.out.println("Time proxy: Start time....");
try {
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
long end=System.currentTimeMillis();
System.out.println("Time proxy: run time= "+(end-start));
}
}
package com.zj.proxy2;
import java.lang.reflect.Method;
public class LogHandler implements InvocationHandler{
//被代理对象
private Object target;
public LogHandler(Object target) {
super();
this.target = target;
}
@Override
public void invoke(Object obj,Method m) {
System.out.println("Log Proxy: Tank start move....");
try {
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
long end=System.currentTimeMillis();
System.out.println("Log Proxy: Tank stop....");
}
}
package com.zj.proxy2;
/*
* 动态代理的好处:可以对任意的对象、任意的接口方法,实现任意的代理;还可以实现代理的叠加
*
* 1.什么是动态代理?
* 2.动态代理是怎么产生的?
* 3.动态代理的作用?
*/
public class Client {
public static void main(String[] args) throws Exception {
Tank t=new Tank();
InvocationHandler h1=new TimeHandler(t);
Moveable m1=(Moveable)Proxy.newProxyInstance(Moveable.class, h1);
InvocationHandler h2=new LogHandler(m1);
Moveable m2=(Moveable)Proxy.newProxyInstance(Moveable.class, h2);
m2.move();
}
}
运行结果如下:
其中Proxy类动态生成的代理类为MyProxy.java,如下:
package com.zj.proxy2;
import java.lang.reflect.Method;
public class MyProxy implements com.zj.proxy2.Moveable {
InvocationHandler h;
public MyProxy(InvocationHandler h) {
this.h = h;
}
@Override
public void move(){
try {
Method md=com.zj.proxy2.Moveable.class.getMethod("move");
h.invoke(this,md);
} catch(Exception e){e.printStackTrace();}
}
}