1. 代理模式
1.1 什么是代理
说白了就是通过不直接访问被代理对象而实现对代理对象的访问,不能直接访问但还成功访问了,那肯定是间接访问的啦,而间接就是通过代理实现的。好比租房,租客—>中介(代理)—>房东,即租客可以不通过直接和房东对话,而是通过中介(代理)与房东联系而实现租客租房的目的。
1.2 代理的优点
- 设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑(sometimes the code is really like shit),这时就很难去下手修改代码,那么这时我们就可以通过代理对类进行增强。
- 通过代理模式可以实现降耦合甚至是解耦。
- Spring的AOP机制就是采用动态代理的机制来实现切面编程。
1.3 代理原理
- Subject(共同接口)
- RealSubject():真实对象的类
- ProxySubject():代理类
特征
- 代理类和委托类具有相同的接口,代理类主要负责为委托类预处理消息,过滤消息,把消息转发给委托类,以及事后的消息处理等。
- 代理类的对象并不正真实现服务,而是通过调用委托类的对象的相关方法来提供服务。
2. 静态代理
- 有程序员编写相应的代理类,即程序编译时就已经将接口,被代理类,以及代理类确定下来。
3. 动态代理
3.1 JDK动态代理
- 代理类是在程序运行期间由JVM根据反射等机制动态生成,所以在程序编译时期不存在代理类的字节码文件,代理类和委托类的关系是在程序运行时确定的。
- 在Java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成动态代理类和动态代理对象,这是JDK所提供的。
- jdk动态代理模式里面有个拦截器的概念,在jdk中,只要实现了InvocationHandler这个接口的类就是一个拦截器类。InvocationHandler中有个invoke方法,所有执行代理对象的方法都会被转化成invoke方法,在invoke中执行被代理对象target的相应方法,在执行被代理对象的方法前后加入一些其他处理。
- proxy 调用方法的代理实例
- method 代理实例上调用的接口方法,包括若有父类,父类中声明的接口方法
- args 传入代理实例上调用的接口方法的参数
- 返回值 就是上述的method的返回值。如果是基本数据类型,则返回的是其包装类的类型
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args)throws Throwable; }
- Proxy类提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。,其中newProxyInstance()方法用来创建代理类对象。
- ClassLoader loader:被代理类的类加载器
- Class[] interfaces:被代理类所实现的接口
- InvocationHandler h:实现InvocationHandler的类
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)throws IllegalArgumentException
- 动态代理就是在代理类和被代理类之间加入了一个实现了InvocationHandler的类,也叫事务处理器。
- 动态代理类实现步骤
其具体实现步骤如下:
1.创建被代理的类和接口
2.创建一个接口实现InvocationHandler的类,且它必须实现invoke()方法
3.通过Proxy的静态方法newProxyInstance来创建代理类的对象
4.通过代理类的对象来调用方法
3.1.1 Q&A
1、代理对象是由谁产生的?
jvm产生的,不像上次的静态代理,我们自己得new个代理对象出来。
2、代理对象实现了什么接口?
实现的接口是目标对象实现的接口。同静态代理模式中代理对象实现的接口。那个继承关系图还是相同的。代理对象和目标对象都实现一个共同的接口。就是这个接口。所以Proxy.newProxyInstance()方法返回的类型就是这个接口类型。
3、代理对象的方法体是什么?
代理对象的方法体中的内容就是拦截器中invoke方法中的内容。所有代理对象的处理逻辑,控制是否执行目标对象的目标方法。都是在这个方法里面处理的。
4、拦截器中的invoke方法中的method参数是在什么时候赋值的?
在客户端,代理对象调用目标方法的时候,实际上进入的是拦截器中的invoke方法,这个时候,拦截器中的invoke方法中的method参数会被赋值。
Loading Comments...