代理模式
前言
代理类主要目的在于隔离目标类,可以在代理类写公用的代码比如日志,也可以加入一些缓存。也能起到降低耦合度的效果。
有时候我们在不想修改目标的类的情况下修改逻辑。也在增加代理类。
代理类的使用主要分为2种方式:静态代理、动态代理
静态代理
我们以买电脑为例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public interface IComputerStore { String buyComputer(); }
public class ComputerStore implements IComputerStore{ @Override public String buyComputer() { return "mac book"; } }
public class ComputerStoreStaticProxy implements IComputerStore{ private IComputerStore computerStore; public ComputerStoreStaticProxy(IComputerStore computerStore) { this.computerStore = computerStore; } @Override public String buyComputer() { System.out.println("收钱"); String computer = computerStore.buyComputer(); System.out.println("发货"); return computer; } }
public class Main { public static void main(String[] args) { IComputerStore computerStore = new ComputerStore(); IComputerStore computerStoreStaticProxy = new ComputerStoreStaticProxy(computerStore); computerStoreStaticProxy.buyComputer(); } }
|
以上就是一个非常简单的静态代理模式,代码比较简单自己看吧。
这个写法缺点也比较明显,代理都是手工编写。不利于管理,而且如果类比较多,工作量大也比较大
动态代理
JDK动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class JdkProxyHandler implements InvocationHandler { private Object object; public JdkProxyHandler(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("收钱"); Object result = method.invoke(object, args); System.out.println("拿到电脑"); System.out.println("发货"); return result; } }
public static void main(String[] args) throws Exception { IComputerStore computerStore = new ComputerStore(); IComputerStore proxy = (IComputerStore)Proxy.newProxyInstance(ComputerStore.class.getClassLoader(), ComputerStore.class.getInterfaces(), new JdkProxyHandler(computerStore)); proxy.buyComputer();
}
|
JDK生成的代理类都是继承Proxy且生成的代理类和委托类实现同一个接口,而且实现了InvocationHandler。
通过调用invoke方法。来实现目标类的访问。
jdk动态代理只能代理接口
cglib代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class CglibProxyHandle implements MethodInterceptor {
private Object obj;
public Object getInstance(Object obj) { this.obj = obj; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.obj.getClass()); enhancer.setCallback(this); return enhancer.create(); }
@Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("收钱"); Object res = methodProxy.invokeSuper(o, objects); System.out.println("拿到电脑"); System.out.println("发货"); return res; } }
public static void main(String[] args) throws Exception { CglibProxyHandle cglibProxyHandle = new CglibProxyHandle(); IComputerStore instance = (IComputerStore)cglibProxyHandle.getInstance(new ComputerStore()); instance.buyComputer(); }
|
注意cdlib生成的代理类是继承目标类的,实现接口Factory。所以可以代理普通类,但是方法不能是final,因为final 不能重写。
fastClass机制所以执行效率要比jdk快,jdk通过反射机制来调用目标类
比较
对三种代理进行一个简单的比较过程
代理 |
实现方式 |
优点 |
缺点 |
特点 |
静态代理 |
代理类和委托类实现一个接口,硬编码 |
简单,容易懂 |
硬编码不好管理,代码量大 |
- |
JDK动态代理 |
代理和委托类实现同一个接口,通过实现InvocationHandler重写invoke来实现访问委托类 |
复用度高,JDK自带 |
只能代理委托类实现的接口 |
底层通过反射机制来调用目标方法 |
cglib动态代理 |
代理通过将委托类作为父类。同时为其委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor接口的对象,若存在则将调用intercept方法对委托方法进行代理 |
可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口 |
不能对final类和final方法进行代理 |
底层将方法全部存入一个数组中,通过数组索引直接进行方法调用,调用效率比JDK高 |
本篇文章主要是结论性的东西,便于自己学习