代理模式通过代理对象为原对象增加某种功能,是Spring AOP的实现方式。代理模式主要分为静态代理和动态代理. 静态代理模式与装饰器模式类似,在此就不展示代码了。静态代理的主要缺点是一个代理类只能用于一个被代理类,是一种『类专用』的代理,被代理类和代理类的组合数是乘积关系。下面通过代码演示Java中的动态代理模式。
Java动态代理模式通过InvocationHandler接口和Proxy类实现。Invocation
接口的invoke
方法通过反射的方式调用被代理类的方法并增加代理逻辑,Proxy类用于生成代理对象。动态代理模式中,代理逻辑和被代理逻辑是分离的,被代理类和代理类的组合数是加和关系。动态代理模式,使用反射动态地在运行时生成代理类,解除了被代理类和代理类的逻辑耦合,减少了类的个数,提高了代理模式的可维护性,但是由于使用了反射,效率相对静态代理模式要低一些。下面以一个例子说明Java动态代理模式。
被代理接口:Operator.java,抽象的操作符
public interface Operator {
public int operate(int a, int b);
}
被代理类:AddOperator.java,完成多次加法
public class AddOperator implements Operator {
@Override
public int operate(int a, int b) {
int ans = 0;
for (long i=0; i<100000000000L; ++i) {
ans = a + b;
}
return ans;
}
}
被代理类:MulOperator.java,完成多次乘法
public class MulOperator implements Operator {
@Override
public int operate(int a, int b) {
int ans = 0;
for (long i=0; i<100000000000L; ++i) {
ans = a * b;
}
return ans;
}
}
代理类:TimeCostProxy.java,增加计时功能
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimeCostProxy implements InvocationHandler {
private Operator oper;
public TimeCostProxy(Operator oper) {
this.oper = oper;
}
public void setOperator(Operator oper) {
this.oper = oper;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long since = System.currentTimeMillis();
Object res = method.invoke(oper, args);
long cost = (System.currentTimeMillis() - since) / 1000L;
System.out.println("Method cost: " + cost + " s");
return res;
}
}
驱动类:Main.java
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
Operator add = new AddOperator(), mul = new MulOperator();
TimeCostProxy timeit = new TimeCostProxy(add);
add = (Operator) Proxy.newProxyInstance(Operator.class.getClassLoader(), new Class<?>[] { Operator.class }, timeit);
add.operate(1, 2); // Method cost: 37 s
timeit.setOperator(mul);
mul = (Operator) Proxy.newProxyInstance(Operator.class.getClassLoader(), new Class<?>[] { Operator.class }, timeit);
mul.operate(1, 2); // Method cost: 37 s
}
}