前言
代理模式:即通过代理对象访问目标对象,实现目标对象的方法。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,实现对目标功能的扩展。
这涉及到一个编程思想:不要随意去修改别人已经写好的代码或者方法(有坑)。如果需要修改,可以通过代理模式实现。
写法实现
代理模式通常有三种实现写法:静态代理、动态代理、Cglib代理。
我们依次说下这三种代理模式:
我们现有 AnimalsDao接口和其实现AnimalsDaoImpl实现类,有两个方法,run和eat。
1 2 3 4 5
| public interface AnimalsDao { void run(); void eat(); }
|
1 2 3 4 5 6 7 8 9 10
| public class AnimalsDaoImpl implements AnimalsDao{ @Override public void run() { System.out.println("run"); } @Override public void eat() { System.out.println("eat"); } }
|
现在我们想在run或者eat方法里之前做一些操作。
静态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class StaticProxy implements AnimalsDao{ @Override public void run() { System.out.println("StaticProxy--------->"); dao.run(); } @Override public void eat() { System.out.println("StaticProxy--------->"); dao.eat(); } private AnimalsDao dao; public StaticProxy(AnimalsDao dao){ this.dao=dao; } }
|
说明:静态代理通过实现目标对象接口,然后调用相同方法来实现代理。这种方式的缺点显而易见,当目标对象接口方法变动时,直接影响到代理类,需要对代理类进行修改,十分不方便。而且如果目标对象接口方法较多时,代理类也十分臃肿,不便维护。
动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class DynamicProxy { private Object obj; public DynamicProxy(Object obj){ this.obj=obj; } public Object getObjProxyIntance(){ return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("DynamicProxy--------->"); return method.invoke(obj,args); } }); } }
|
说明:动态代理模式主要借助JDK代理对象API java.lang.reflect.Proxy来实现的,所以也称作JDK代理。我们看一下JDK这个类,其中重要的一个方法如下:
这个方法的三个参数:
ClassLoader loader 目标对象类加载器
Class<?>[] interfaces 目标对象接口类型
InvocationHandler h 事物处理,在这里面可以实现自己想要的逻辑
根据以上,可以看出动态代理实现要求目标对象必须有实现接口。代理类不必实现接口。
Cglib代理
要实现Cglib代理,必须引入cglib.jar 包,由于Spring-core包中已经包含了cglib功能,且大部分Java项目均引入了spring 相关jar包,这边使用spring的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
| public class CglibProxy implements MethodInterceptor { private Object obj; public CglibProxy(Object obj){ this.obj=obj; } public Object getProxyInstance(){ Enhancer en = new Enhancer(); en.setSuperclass(obj.getClass()); en.setCallback(this); return en.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("CglibProxy--------->"); return method.invoke(obj,objects); } }
|
说明:可以看出,Cglib代理模式实现不需要目标对象一定实现接口,故目标对象如果没有实现接口,可以使用cglib代理模式。其实Spring的代理模式也是这么实现的。
应用实例
Spring的代理模式:如果容器目标对象有接口,使用JDK动态代理,如果没有接口,使用cglib动态代理。
参考资料
https://www.cnblogs.com/cenyu/p/6289209.html
Spring 4.0 源代码
GitHub代码地址
https://github.com/JavaZWT/designPatterns