代理模式(相关文件在最下方)
静态代理
- 接口:例如:租房子
- 真实角色:向代理角色发出信息,例如,房东:要出租房子
- 代理角色:收到真实角色信息,并做一些附属操作,例如:中介:带顾客看房,收取中介费等
- 客户:从代理角色处实现目标,例如:面向中介租房,不再是面向房东
- 一般原业务代码不进行修改,要增添新功能只需要在增加一个代理角色,用来增加新功能,而不需要更改原业务代码
- 代理模式降低了耦合性,实现了分工,但是增加了代码量,因为不仅要加入新代码还有调用老代码
###动态代理 - 动态代理和静态代理角色相同
- 动态代理的代理类是动态生成的,不需要我们直接写好
- 动态代理分为两大类:1.基于接口的动态代理;2.基于类的动态代理
a.基于接口:JDK的动态代理
b.基于类:cglib
c.java字节码实现:javasist(使用较多,快速简单的改变类的结构,生成动态类) - invoke(proxy:代理对象,method:代理对象调用的被代理对象的方法的方法名,args:方法的参数,如果没有参数就是null)
invoke返回一个实例类。
###个人理解(静态代理和动态代理的比较看 spring-08-proxy项目中的demo2和demo4)
首先,采用代理模式是为了降低耦合性,进行业务分工,当公共业务发生扩展时方便集中管理。
代理模式又分为两类:静态代理 、 动态代理(利用反射) - 动态代理角色和静态代理抽象出来的角色 所做的工作相同,但一个是动态生成代理对象(一对多:一个代理角色类对应多个真实角色类),一个是静态生成(一对一)
- **********静态代理********** 虽然降低了耦合性,并进行了业务分工,但是因为是采用的重写被代理对象的所有方法的方式,一个真实角色就要对应一个代理角色,是一对一的关系,
导致代码量成倍增加(动态代理是多个真实角色对应一个代理角色,是多对一的关系,所以降低了代码量) - 例如,有一个UserService接口,定义了10个方法:
不采用代理模式时:应该定义一个UserServiceImpl用来实现接口UserService里的方法 -
采用静态代理时:同样定义了一个实现类UserServiceProxy用来实现接口UserService里的方法,!!!但是,该实现类是!重写!!UserServiceImpl中
的方法,并不是直接重头实现接口里的方法,
可查看spring-08-demo2里写的代理角色的方法。 -
采用动态代理时:定义一个实现类ProxyInvocationHandler,!!!!实现接口InvocationHandler!!!这个与静态代理不同,接口InvocationHandler
只有一个Invoke方法,只需重写invoke方法,当通过生成的动态代理对象调用被代理的对象时,动态代理是进行自动调用invoke方法实现,而不是需要在该类中重写所有方法,只需invoke里获得 method.invoke方法的值即可 - **********动态代理**********不仅降低了耦合性,进行了程序分工,并且不增加代码量,是动态生成的
- 动态代理-代理角色类的工作:
1.该类 实现InvocationHandler接口:public class 代理角色名字 implements InvocationHandler{具体内容}
2.定义被代理的接口(被代理的对象),并为接口(对象)设置set方法:private Object target;
public void setTarget(Object target) {this.target = target;}
3.生成代理对象:public Object getProxy(){return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);}
4.编写invoke方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {新增方法;Object result = method.invoke(target, args); return result;新增方法;}
- 动态代理-客户端的工作(使用动态代理的方法):
1.生成真实角色(不可以是接口),例如:UserServiceImpl 真实角色名 = new UserServiceImpl();
定义的代理角色类名 pih = new 定义的代理角色类名(); 例如spring-08的demo4的ProxyInvocationHandler类
3.为代理角色设置要代理的对象(使用代理角色类中写入的set方法):pih.setTarget(真实角色名); 则真实角色被代理角色pih代理
UserService proxy = (UserService) pih.getProxy();
真实对象类的类型 代理对象名 = (真实对象类的类型) 代理角色.getProxy(),getProxy()为代理角色类中生成代理对象的方法。 5.使用 代理对象 调用 被代理对象(真实角色) 的方法:proxy.update();
,proxy为代理对象名,update为被代理对象的原方法,这里会传入Invoke的三个参数为:proxy,update,null 当使用代理对象调用被代理对象的方法时,代理对象为自动调用代理角色类中写好的Invoke()方法,分别传入invoke方法三个参数:代理对象、方法名、方法的参 数。 在invoke方法里,会自动调用被代理对象的原方法和新写入Invoke里的方法。
相关文件下载
spring-study:
链接:https://pan.baidu.com/s/1YWbZJ_EGWyJInxBtR9c1UQ
提取码:bjfu