代理模式
一、模式的提出
为其他对象提供一种代理以控制对这个对象的访问。其实,observer也是一种代理模式
二、业务背景
要测试一个方法运行了多长时间怎么测试?要给一个方法记录日志文件怎么记录?怎样动态的设置该方法(是先记录日志文件、还是先测试运行该方法多长时间)的先后顺序,本文以测试坦克方法为例
三、UML图
四、代码详解
测试方法的接口
package com.hewen.proxy;
public interface Moveable {
public void move();//测试运行方法
}
Tank类
package com.hewen.proxy;
import java.util.Random;
public class Tank implements Moveable{
public void move() {
System.out.println("Tank moving....");
try {
Thread.sleep(new Random().nextInt(10000));//休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
时间记录类
package com.hewen.proxy;
public class TankTimeProxy implements Moveable {
private Moveable t;//只要类实现了该接口,就可以动态代理这个方法
public TankTimeProxy(Moveable t) {
this.t=t;
}
public void move() {
long start=System.currentTimeMillis();
t.move();
long end=System.currentTimeMillis();
System.out.println("time:"+(end-start));
}
}
日志记录类
package com.hewen.proxy;
public class TankLogProxy implements Moveable {
private Moveable t;//代理对象
public TankLogProxy(Moveable t) {
this.t=t;
}
//可以为这个方法设置日志
public void move() {
System.out.println("tank start......");
t.move();
System.out.println("tank stop......");
}
}
主方法测试类
package com.hewen.proxy;
public class Test {
public static void main(String[] args){
//测试坦克运行的方法的时间,以及该方法的日志管理
//Moveable t=new TankLogProxy(new TankTimeProxy(new Tank()));
//t.move();
Moveable t=new TankTimeProxy(new TankLogProxy(new Tank()));
t.move();
}
}
运行的结果
tank start...... Tank moving.... tank stop...... time:7328
时序图:
还有一个是java虚拟机代理动态调用
业务背景:有一个疑问希望网友解释的越详细越好,
自己查看源码proxy类是怎样动态的调用invoke方法?
这是一个代理类
package com.cn.dynamic.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理类实现了InvocationHandler接口,
* 通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,
* 并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的
* Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,
* 并且它返回的结果将作为代理实例上方法调用的结果返回。
* @author Administrator
*
*/
public class DynamicProxySay implements InvocationHandler {
private Object proxyOperation; // 操作者对象
private Object proxyLogic; // 业务逻辑对象
/**
* 获得代理对象(业务逻辑)
*
* @param proxyOperation
* @param proxyLogic
* @return
*/
public Object getProxyObj(Object proxyOperation, Object proxyLogic) {
this.proxyOperation = proxyOperation;
this.proxyLogic = proxyLogic;
/**两种方式调用
* 第一种方式:这个是比较复杂的返回代理的实例对象,
* 返回代理类的 java.lang.Class 对象,注意一定是要
*/
Class proxyClass = Proxy.getProxyClass(
this.proxyLogic.getClass().getClassLoader(),
this.proxyLogic.getClass().getInterfaces() );
try {//得到构造方法新建一个代理对象
return proxyClass.getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { this });
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return proxyClass;
//第二种方式: 比较简易的返回一个代理实例对象,
/* return Proxy.newProxyInstance(this.proxyLogic.getClass()
.getClassLoader(), this.proxyLogic.getClass().getInterfaces(),
this); */
}
/**
* JVM动态调用
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/**
* 判断是否是代理类
*/
// if(Proxy.isProxyClass(Proxy.getProxyClass(this.proxyLogic.getClass()
// .getClassLoader(), this.proxyLogic.getClass().getInterfaces()))){
// System.out.println("this dynamic proxy class!");
// }
Object resultObj = null;
try {
Class operCls = this.proxyOperation.getClass();
//得到操作类的方法,参数是start名字和该方法的参数
Method start = operCls.getMethod("start",
new Class[] { Method.class });
// 反射执行start方法,参数是该方法的对象和该方法的参数
start.invoke(proxyOperation, new Object[] { method });
// 执行业务逻辑对象
resultObj = method.invoke(proxyLogic, args);
Method end = operCls.getMethod("end", new Class[] { Method.class });
// 反射执行end方法
end.invoke(proxyOperation, new Object[] { method });
} catch (Exception e) {
e.printStackTrace();
}
return resultObj;
}
}
客户端的调用
package com.cn.dynamic.proxy;
import com.cn.dynamic.operator.ISay;
import com.cn.dynamic.operator.Say;
/**
* 测试方法
* @author Administrator
*
*/
public class Client {
public static void main(String[] args) {
//对业务逻辑做日志的操作方法
IOperatorExecutor operExe = new LoggerOperation();
//业务逻辑方法
ISay say = new Say();
//返回代理对象
ISay proxySay = (ISay) new DynamicProxySay().getProxyObj(operExe, say);
proxySay.sayHello("Alice"); //代理对象动态的调用invoke方法
System.out.println();
proxySay.sayGoodBye("Bob"); //代理对象动态的调用invoke方法
}
}
业务逻辑的接口
package com.cn.dynamic.operator;
public interface ISay {
void sayHello(String name);
void sayGoodBye(String name);
}
实现业务逻辑的类
package com.cn.dynamic.operator;
public class Say implements ISay{
public void sayGoodBye(String name) {
System.out.println("goodBye: "+name);
}
public void sayHello(String name) {
System.out.println("hello: "+name);
}
}
记录日志的接口
package com.cn.dynamic.proxy;
import java.lang.reflect.Method;
public interface IOperatorExecutor {
void start(Method method);
/**
* 方法执行之前的操作
*
* @param method
*/
void end(Method method);
}
实现记录日志的类
package com.cn.dynamic.proxy;
import java.lang.reflect.Method;
import com.cn.dynamic.Level;
import com.cn.dynamic.Logger;
public class LoggerOperation implements IOperatorExecutor {
public void end(Method method) {
Logger.log(Level.INFO, method.getName() + " method end...");
}
public void start(Method method) {
Logger.log(Level.INFO, method.getName() + " method start...");
}
}
记录日志类依赖的类
package com.cn.dynamic;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class Logger {
/*
* 重做方法日志
*/
public static void log(Level level, String logInfo) {
if (level.equals(Level.INFO)) {
System.out.println("Logger INFO : "
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new Date()) + " " + logInfo);
} else if (level.equals(Level.WARN)) {
System.out.println("Logger WARN : "
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new Date()) + " " + logInfo);
} else if (level.equals(Level.DEBUG)) {
System.out.println("Logger DEBUG : "
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new Date()) + " " + logInfo);
}
}
}
package com.cn.dynamic;
public enum Level {
INFO,WARN,DEBUG;
}
运行的结果
Logger INFO : 2010-09-04 18:23:41 sayHello method start...
hello: Alice
Logger INFO : 2010-09-04 18:23:41 sayHello method end...
Logger INFO : 2010-09-04 18:23:41 sayGoodBye method start...
goodBye: Bob
Logger INFO : 2010-09-04 18:23:41 sayGoodBye method end...