代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。而代理模式又分为静态代理和动态代理,先说静态代理。
静态代理通俗点将就是自己手写一个代理类,而动态代理则不用我们手写,而是依赖于java反射机制,下面以一个demo举例。
demo结构如图:
Subject是一个普通接口,里面有个抽象的doSomething()的方法,而SubjectImpl.java是它的普通的实现类,如下所示。
而HandProxy.java就是SubjectImpl的静态代理类,代替了SubjectImpl完成doSomething的工作,如下所示
这样做的好处是对于doSomething方法来说,我用静态代理类来实现,可以任意的在其中插入我需要额外做的事情,比如说记录日志。
那么AutoProxy.java就是动态代理类了,具体如下所示。
这里面首先想要做到动态代理,必须先实现这个InvocationHandler接口,然后我们主要看bind方法,参数tar是一个Object类型的对象,也就是需要被代理的对象SubjectImpl,
方法里面有一个Proxy类,这个Proxy类提供了很多方法,这里我们用的是newProxyInstance方法,它有三个参数,第一个是被代理类的类构造器,第二个指的是被代理类的接口,也就是Subject接口,第三个是实现这个代理的类,这里就是本类。具体的来说,这个方法执行了下面三步:
1.生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码,然后用参数里的classLoader加载这个代理类。
2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler的子类传入。
3.返回这个代理类实例,因为我们构造的代理类实现了interfaces(也就是我们程序中传入的subject.getClass().getInterfaces())里的所有接口,因此返回的代理类可以强转成Subject类型来调用接口中定义的方法。
而在调用每个代理类每个方法的时候,都用反射去调h的invoke方法(也就是我们自定义的InvocationHandler的子类中重写的invoke方法),用参数传递了代理类实例、接口方法、调用参数列表,这样我们在重写的invoke方法中就可以实现对所有方法的统一包装了。
总结一下,静态代理的优点是清晰易懂,但是如果说业务代码很多,那么在代理类里面必须全部重新调用一遍,很麻烦。而动态代理,利用java反射机制,动态的生成了一个代理类,直接调用代理方法即可。
四、总结反射这一块是博主最近在看框架源码的时候总是遇到这类问题所以刻意去整理了一下,里面有些东西其实我也研究的不是很深刻,动态代理这边的源码还有待深入挖掘,若有大神发现写的不对的地方,还请多多指教,谢谢。