静态代理:
举个栗子:在生活中,中介的存在,帮助客户找到理想的房源,也帮助房东出租房源,这就是代理模式
房东——真实角色:被代理的角色
中介——代理角色:代理真实角色来操作
租客——客户:使用代理角色来进行操作
租房这件事——抽象角色:一般使用接口或抽象类来实现
在这个过程中,租客只需调用中介来完成租房这个方法即可,至于怎么租它不需要管
中介只需实现租房这个接口或抽象类,来重写它(其中包括实现租房外的一些方法,比如收取中介费),注意的是租房是通过调用房东这个真实对象来完成租房这件事
房东只需实现租房这个接口或抽象类即可,其他啥事不用做,等着中介那边调用它租房即可
对代理模式的理解:没有代理的前提下,一个真实角色想要多实现一个功能,那就只能在原业务代码上去进行修改,这是大忌,所以此时需创一个代理类,并写出这个添加的方法,来代理真实角色完成所有这些事即可(我们在不改变原来代码的情况下,实现了对原有功能的增强,这就是AOP核心思想)
这些固定下来就是静态代理模式了,可以看出有个很大的弊端,就是一个真实角色就要对应一个代理角色(真实角色可能需求不同),所以真实角色一多,那效率就不高了,为了解决这个弊端就出现了动态代理模式
动态代理:
与静态代理的一大不同点:静态代理模式的代理类是我们提取写好的,而动态代理模式是动态生成的
动态代理的底层:反射
动态代理分为:
- 基于接口动态代理——JDK动态代理
- 基于类的动态代理——cglib
- java字节码实现:javassist(用的比较多)
两种代理在实现道理上差不多,这里以JDK原生代码为例
JDK动态代理
核心有两大类:
- InvocationHandler 每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用(invoke里是我们真正执行的方法)
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
proxy:代理类代理的真实对象,也就是你要代理谁
method:我们所要调用某个对象真实的方法的Method对象,也就是你要代理这个类的哪个方法,也可以是接口
args:指代代理对象方法传递的参数,如果接口方法没有参数则为null,也就是那个方法所需要传递的参数
- Proxy 用来创建一个代理对象的类,它提供了很多静态方法,但是我们最常用的是newProxyInstance方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
interface:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法
h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用
//生成代理类,这里是死的,用时只需改变rent(租房)这个抽象角色即可
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
动态代理类大致过程:
分享一个万能动态代理类:
相比于静态代理的优点:
- 一个动态代理类代理的是一个接口,一般对应的就是一类业务
- 一个动态代理类可以代理多个类,只要实现了同一个接口即可