代理模式
给A对象,找个替身B,所有请求和响应都经过B完成。
代理模式优缺点
代理模式的优点:
1、职责清晰
2、高扩展性
3、智能化
代理模式缺点:
1、因为加了代理对象,可能造成请求的处理速度变慢
2、代理模式需要额外的工作,稍复杂
代理模式适应场景
1、
2、
代理模式的分类
1、静态代理 静态代理虽然存在一定的缺点,死板,不能动态调整,但是它很重要,源码中很多写法也是使用了静态代理。并且先研究静态代理,知道其缺陷,再去研究动态代理是很有帮助的。所以不要小瞧静态代理。
2、动态代理 在运行期间,可以方便地调整被代理的对象,如可以代理A,也可以代理B。 java 单继承,is-a的体系 。会对动态代理有一定影响,但可以通过操作字节码方式解决问题。 动态代理又有2种方式,JDK 动态代理,CGlib动态代理。
静态代理
被代理对象,target 可以是接口、抽象类,并且有具体的实现
代理类,proxy ,暴露给使用端使用,和被代理对象实现同一个接口或者继承同一个抽象类(因为java是单继承,is-a,如果代理类已经继承了某个类,则不能再继承被代理对象【抽象类】,这是一个限制)
客户端, client , 不直接使用被代理的对象,而是使用代理类完成作业
静态代理的写法,完成对一个接口的代理。
interface Subject{
void work();
// 可以有多个行为
}
// 被代理对象的具体实现
class SubjectImpl implements Subject{
void work(){
sout("work");
}
}
// 代理类 , 实现 被代理对象 ,并持有一个被代理对象的实例
class Proxy implements Subject{
Subject target; // 非常重要,持有被代理对象,在构造函数时候指定,这也意味着,静态代理在编码环境已经确定代理的对象,写法比较死板,达不到在运行期间动态的调整
public Proxy(Proxy target){
this.target= target;
}
// 满足开闭
void work(){
sout("before"); //代理前增强
target.work();
sout("after"); //代理后增强
}
}
// 使用
class Client {
void main(){
Subject target = new SubjectImpl();
Proxy proxy = new Proxy(target);// 把被代理对象传入到代理类中
proxy.work(); // 使用代理类操作,效果是达到了 target的实现,并且还能做扩展
}
}
从开闭原则视角,再重新考虑,代理模式,就是在不改变原有的情况下,做一些拓展,也可以通过继承的方式来实现。
基于上面的 Subject 和它的一个具体实现 SubjectImpl,为此,我们模拟一种场景,对SubjectImpl进行拓展。用一个代理类,完成 SubjectImpl 的作业,并拓展一些设计模式要活用,这才是设计模式的精髓。马走日,象飞田,可以把这些规则理解成设计模式,但是到整个棋盘上,变化万千了!
采用继承的方式,实现对 代理subjectImpl的作业,并做拓展,如下是伪代码
// 继承方式实现静态代理 , 不要拘泥于代码的形式,要明白设计模式的本质,会活用
class SubjectProxy extends SubjectImpl{
public void work(){
sout("静态代理-继承方式 : before work");
super.work();
sout("静态代理-继承方式 : after work");
}
}
// 客户端使用
class client {
void main(){
Subject proxy = new SubjectProxy();
proy.work();
}
}
JDK动态代理
实现 IncocationHandler 接口,走invoke()拦截,底层使用 java 反射技术。
代理对象,是个接口 代理类 客户端
// 简单的订单对象,提交订单入参
public class Order {
private String orderNo;
private String status;
private BigDecimal amount;
private String type="普通订单";
private String description;
public Order() {
}
}
被代理对象,是一个接口
// 被代理对象
public interface OrderServer {
/**
* 下单,被代理的目标方法
*/
Order buildOrder(Order order);
}
被代理对象的2个具体实现,
// 普通订单
public class DefaultOrderHandler implements OrderServer{
@Override
public Order buildOrder(Order order) {
Order od = order;
od.setAmount(new BigDecimal("1000"));
od.setStatus("待付款");
return od;
}
}
// 用券订单
public class CouponOrderHandler implements OrderServer{
@Override
public Order buildOrder(Order order) {
Order od = order;
od.setAmount(new BigDecimal("600")); // 模拟用券,比普通订单金额少了400
od.setStatus("待付款");
System.out.println(" have built an order with coupon ... ... ... ... ");
return od;
}
}
代理类, 实现 JDK的 InvocationHandler 接口,实现invoke() 使用Proxy.newProxyInstance() 构建代理类
//
public class InvocationHandlerOrder implements InvocationHandler {
private Object os;
public InvocationHandlerOrder(Object os){
this.os = os; // 构造函数指定具体干事的 即代理对象的具体实现
}
public void setOs(Object os) {
this.os = os;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理-invoke before"); // 代理前置增强
Object result =null;
// jvm 加 -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true 查看字节码
//result = method.invoke(proxy, args); // 死循环
result = method.invoke(this.os, args);
System.out.println("JDK代理-invoke after ... "); // 代理后置增强
return result;
}
}
// 构建订单 使用一个工厂方式,
public class OrderFactory {
public static Object getProxy(Object targetObject){
ClassLoader loader = targetObject.getClass().getClassLoader();
Class<?>[] interfaces = targetObject.getClass().getInterfaces();
InvocationHandler h = new InvocationHandlerOrder(targetObject);// 实例化代理类对象
// Proxy.newProxyInstance() 构建代理类
return Proxy.newProxyInstance(
loader,//目标对象的类加载器
interfaces,//获取目标对象实现的接口
h//将目标对象传递到JDK动态代理类的构造方法中,进行创建一个动态代理类的实例对象
);
}
}
客户端使用(业务聚合层使用领域层)
// client 调用
public static void jdkProxy(){
Order od = new Order();
od.setOrderNo("2022-04-08-15-100");
od.setStatus("草稿");
OrderServer target =new CouponOrderHandler(); // 正在干事的,被代理对象的具体实现
OrderServer proxy = (OrderServer)OrderFactory.getProxy(target);
Order or=proxy.buildOrder(od);
System.out.println(or);
}
// main 方式运行结果如下:
JDK代理-invoke before 【代理的前置增强】
have built an order with coupon ... ... ... ... 【真正干事的】
JDK代理-invoke after ... 【代理的后置增强】
Order{orderNo='2022-04-08-15-100', status='待付款', amount=600, type='普通订单', description='null'}
the end
CgLib动态代理
1、 底层使用字节码技术 ASM框架。
JDK动态代理和Cglib 动态代理比较
源码中动态代理的使用
spring aop
dubbo