设计模式之代理
使用场景:不改变源代码,加入日志、权限管理、时间纪录等功能
一、静态代理
??? 1.1 使用继承的方式
?public interface Moveable {?//
??void move();
?
//?void stop();
}
?????????????
?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();
??}
?}
?
//?public void stop() {
//??System.out.println("Tank stopping...");
//?}
?}
?public class InheritedStaticProxy extends Tank {?? // 代理类继承自目标类
?public void move() {
??System.out.println("计时开始...");
??long start = System.currentTimeMillis();
??
??super.move();
??
??long end = System.currentTimeMillis();
??System.out.println("计时结束,共耗时 : " + (end-start) + "毫秒.");
?}
?}
?public class Client {? // 测试
?public static void main(String[] args) {
??Moveable m = new InheritedStaticProxy();
??m.move();
??// 输出
??
?}
}
??? 1.2 使用聚合的方式 (更加灵活,可以任意组合)
?public interface Moveable {?//
??void move();
?
//?void stop();
}
?????????????
?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();
??}
?}
?
//?public void stop() {
//??System.out.println("Tank stopping...");
//?}
?}
?public class TankTimeProxy implements Moveable {?? // 时间代理类
?private Moveable t;
?
?public TankTimeProxy (Moveable t) {
??this.t= t;
?}
?public void move() {
??System.out.println("计时开始...");
??long start = System.currentTimeMillis();
??
??t.move();
??
??long end = System.currentTimeMillis();
??System.out.println("计时结束,共耗时: " + (end-start) + "毫秒.");
?}
?
//?public void stop() {
//??System.out.println("计时开始...");
//??long start = System.currentTimeMillis();
//?
//??t.stop();
//?
//??long end = System.currentTimeMillis();
//??System.out.println("计时结束,共耗时: " + (end-start) + "毫秒.");
//?}
}
public class TankLogProxy implements Moveable {
?private Moveable t;
?
?public TankLogProxy (Moveable t) {
??this.t= t;
?}
?public void move() {
??System.out.println("日志纪录开始? ...");
??t.move();
??System.out.println("日志纪录结束? ...");
?}
?
//?public void stop() {
//??System.out.println("日志纪录开始 ...");
//??t.stop();
//??System.out.println("日志纪录结束? ...");
//?}
}
public class Client {?? // 测试
?public static void main(String[] args) {
??System.out.println("=====================");
??Moveable m = new TankTimeProxy(new Tank());
??m.move();
??
??System.out.println("=====================");
??m = new TankLogProxy(new Tank());
??m.move();
??
??System.out.println("=====================");
??m = new TankTimeProxy(new TankLogProxy(new Tank()));
??m.move();
??
??System.out.println("=====================");
??m = new TankLogProxy(new TankTimeProxy(new Tank()));
??m.move();
?}
}
// 输出
?
二、动态代理
public interface Eatingable {
?int eating(String food);
}
?????????????
public class Goat implements Eatingable {
?@Override
?public int eating(String food) {
??
??System.out.println("Eating: " + food);
??
??return food.length();
?}
}
?public class TimeHandler implements InvocationHandler {? // 把日志、时间记录等功能抽象了出来
?private Object target;
?
?public TimeHandler(Object target) {
??this.target = target;
?}
?
?@Override
?public Object invoke(Object proxy, Method method, Object[] args)?
???throws Throwable {
??
??System.out.println("时间记录开始...");
??long start = System.currentTimeMillis();
??
??Object retObj = method.invoke(target, args);
??
??long end = System.currentTimeMillis();
??System.out.println("计时结束,共耗时: " + (end-start) + "毫秒.");
??
??return retObj;
?}
}
?public class Client {? // 测试
?public static void main(String[] args) throws Exception {
??
??Eatingable e = (Eatingable)Proxy.newProxyInstance(Client.class.getClassLoader(),
????????new Class[]{Eatingable.class}, new TimeHandler(new Goat()));
??System.out.println(e.eating("apple"));
??// 输出
??
?}
?}
??
三、使用CGLIB实现动态代理
?3.1 对没有实现接口的类进行代理
??public class MyClass {
?public String fun (String str) {
??System.out.println("Parameter: " + str);
??
??return "函数返回值: Hello " + str;
?}
}
?
??public class TimeInterceptor implements MethodInterceptor {? // 拦截器
?/**
? * @param obj 代理对象
? * @param method 被代理对象的方法
? * @param args 被代理对象的方法参数
? * @param proxy 代理方法。使用起来比原生的method要快
? */
?@Override
?public Object intercept(Object obj, Method method, Object[] args,
???MethodProxy proxy) throws Throwable {
??
????System.out.println("时间记录开始...");
????long start = System.currentTimeMillis();
??
????//Object retObj = proxy.invoke(this, args); // error
????Object retObj = proxy.invokeSuper(obj, args);? // 不要使用proxy.invoke方法
??
????long end = System.currentTimeMillis();
????System.out.println("计时结束,共耗时: " + (end-start) + "毫秒.");
??
????return retObj;
???}
??}
??final public class ProxyFactory {
?
?/**
? * @param interceptor? 拦截器(如添加日志、事务的代码)
? * @param superClz? 被代理类
? * @return 代理类(增加了interceptor拦截代码后的代理类)
? */
?public static synchronized Object getProxyInstance(MethodInterceptor interceptor, Class superClz) {
??Enhancer enhancer = new Enhancer();
??enhancer.setSuperclass(superClz);
??enhancer.setCallback(interceptor);
??//enhancer.setClassLoader(superClz.getClassLoader());
??return enhancer.create();
?}
}
??public class Client {
?public static void main(String[] args) throws Exception {
??MyClass proxy = (MyClass)ProxyFactory.getProxyInstance(new TimeInterceptor(), MyClass.class);
??System.out.println(proxy.fun("Allei"));
??// 输出
??
?}
??}
??? 3.2 对继承了接口的类进行代理
public interface Eatingable {
?int eating(String food);
}
?????????????
public class Goat implements Eatingable {
?@Override
?public int eating(String food) {
??
??System.out.println("Eating: " + food);
??
??return food.length();
?}
?}
?TimeInterceptor 和ProxyFactory 与上面一样。
?
?public class Client {
?public static void main(String[] args) throws Exception {??
??TimeInterceptor h = new TimeInterceptor();
??Eatingable proxy = (Eatingable)ProxyFactory.getProxyInstance(new TimeInterceptor(), Goat.class);
??System.out.println(proxy.eating("apple"));
??// 输出
??
?}
}
?