互联网架构-精讲设计模式-005:代理模式

1 精讲代理模式介绍

课题内容:
1.什么是代理模式?代理模式应用场景?
2.代理模式两种创建方式
3.静态代理与动态代理区别
4.JDK动态代理与CGLIB代理区别
5.JDK动态代理实现原理
5.JDK动态代理被代理类必须要实现接口
6.CGLIB代理实现原理
7.纯手写动态代理模式

什么是代理模式
为其他对象提供一种代理以控制对这个对象的访问。
通过代理控制对象的访问,调用对象中的方法,在方法调用之前或调用后可以做别的操作。

2 为什么要使用代理模式

为什么使用代理模式
中介隔离:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口
开闭原则,增加功能:通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。
代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。

3 使用实现接口实现代理模式

1.代理模式实现方式?
静态代理和动态代理
2.静态代理
静态代理是由程序员创建或工具生成代理类的源码,再编译代理类。
所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。一句话,自己手写代理类就是静态代理。
静态代理实现方式(两种):
1.实现接口
2.继承
在这里插入图片描述
基于接口实现方式

public interface OrderService {

    /**
     * 共同抽象的方法
     */
    void order();
}
public class OrderServiceImpl implements OrderService {

    @Override
    public void order(){
        System.out.println("执行订单业务逻辑代码");
    }
}
public class OrderServiceProxy implements OrderService {

    /**
     * 被代理对象
     */
    private OrderService orderService;

    public OrderServiceProxy(OrderService orderService) {
        this.orderService = orderService;
    }

    @Override
    public void order() {
        System.out.println(">>打印订单日志开始");
        orderService.order();// 执行order业务逻辑代码
        System.out.println(">>打印订单日志结束");
    }
}
public class Client {
    public static void main(String[] args) {
        OrderService orderService = new OrderServiceProxy(new OrderServiceImpl());
        orderService.order();
    }
}

4 使用继承被代理类实现代理模式

public class OrderServiceProxy extends OrderServiceImpl {
    
    @Override
    public void order() {
        System.out.println(">>打印订单日志开始");
        super.order();// 执行父类OrderServiceImpl的order
        System.out.println(">>打印订单日志结束");
    }
}
public class Client {
    public static void main(String[] args) {
        OrderService orderService = new OrderServiceProxy();
        orderService.order();
    }
}

5 使用JDK动态代理实现代理模式

动态代理
通过Java反射或者字节码技术自动在运行时创建代理类对象。
JDK动态代理
CGLIB动态代理

JDK动态代理
JDK动态代理的一般步骤如下:
1.创建被代理的接口和类;
2.实现InvocationHandler接口,对目标接口中声明的所有方法进行统一处理;
3.调用Proxy的静态方法,创建代理类并生成相应的代理对象;

public class JdkInvocationHandler implements InvocationHandler {

    /**
     * 被代理类对象 目标代理对象
     */
    public Object target;

    public JdkInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(">>jdk打印订单日志开始,proxy:" + proxy.getClass().toString());
        Object result = method.invoke(target, args); // java的反射机制执行方法  执行目标对象的方法
        System.out.println(">>jdk打印订单日志结束");
        return result;
    }

    /**
     * 使用jdk动态代理创建代理类
     *
     * @param <T>
     * @return
     */
    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}
public class Client {
    public static void main(String[] args) {
        // 1.使用jdk动态代理
        OrderService proxy = new JdkInvocationHandler(new OrderServiceImpl()).getProxy();
        proxy.order();
    }
}

在这里插入图片描述

6 JDK动态代理底层实现分析

原理分析
1.获取代理的生成的class文件
System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
在这里插入图片描述
2.使用反编译工具打开$Proxy0.class
在这里插入图片描述
在这里插入图片描述
JDK动态代理为什么需要通过父类接收
JDK动态生成的代理都是实现接口形式,所以代理类必须实现接口。
在这里插入图片描述
JDK动态代理自动生成的代理类继承了Proxy类,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类;实现了代理的接口,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。

7 使用CGLIB动态代理实现代理模式

CGLIB动态代理
Cglib是一个强大的,高性能,高质量的代码生成类库。它可以在运行期扩展JAVA类与实现JAVA接口。其底层实现是通过ASM字节码处理框架来转换字节码并生成新的类。大部分功能实际上是ASM所提供的,Cglib只是封装了ASM,简化了ASM操作,实现了运行期生成新的class。

CGLIB原理
运行时动态的生成一个被代理类的子类(通过ASM字节码处理框架实现),子类重写了被代理类中所有非final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势植入横切逻辑。

Cglib优缺点
优点:JDK动态代理要求被代理的类必须实现接口,当需要代理的类没有实现接口时Cglib代理是一个很好的选择。另一个优点是Cglib动态代理比使用java反射的JDK动态代理要快
缺点:对于被代理类中的final方法,无法进行代理,因为子类中无法重写final函数

CGLIB代理实现
实现MethodInterceptor接口的intercept方法后,所有生成的代理方法都调用这个方法。
intercept方法的具体参数有:
1.obj 目标类的实例
2.method 目标方法实例(通过反射获取的目标方法实例)
3.args 目标方法的参数
4.proxy 代理类的实例
该方法的返回值就是目标方法的返回值。

public class CglibMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println(">>cglib日志收集开始<<");
        Object result = methodProxy.invokeSuper(obj, args);
        System.out.println(">>cglib日志收集结束<<");
        return result;
    }
}
public class Client {
    public static void main(String[] args) {
        // 2.使用cglib动态代理
        CglibMethodInterceptor cglibMethodInterceptor = new CglibMethodInterceptor();
        Enhancer enhancer = new Enhancer();
        // 设置代理类的父类
        enhancer.setSuperclass(OrderServiceImpl.class);
        // 设置回调对象
        enhancer.setCallback(cglibMethodInterceptor);
        // 创建代理对象
        OrderServiceImpl orderServiceImpl = (OrderServiceImpl) enhancer.create();
        orderServiceImpl.order();
    }
}

在这里插入图片描述
CGLIB与JDK动态代理区别是什么?
jdk动态代理:被代理类必须实现接口,实现方式,java反射执行
cligb动态代理:使用继承被代理类,继承方式,ASM生成子类

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值