代理模式浅谈

前言

代理模式有时也被称作委托模式,是一个比较常用/基本的设计模式。代理类不仅会解耦方法的具体实现和方法调用者,而且会对目标方法进行增强。代理模式主要有三类角色:抽象主题角色(ISubject)、委托类角色(被代理角色,RealSubject)和代理类角色(Proxy)。三者之间的关系如下图:
在这里插入图片描述

代理模式实践

代理模式实现方式有两类:一类是静态代理(普通代理),代理类在程序运行前就已经存在;另一类是动态代理,代理类在程序运行时创建。代理模式要求客户端只能访问代理角色,不能访问真实角色。

1. 前置代码准备

1.1 domain

/**
 * 车辆属性
 */
public class Car implements Serializable {
    //编号
    private Long id;
    //外观颜色
    private String shellColor;
    //轮子厂商
    private String wheelManufacturer;
    //车辆类型
    private String type;
    //价格
    private BigDecimal price;
    public Car() {}
    public Car(Long id, String shellColor, String wheelManufacturer, String type, BigDecimal price) {
        this.id = id;
        this.shellColor = shellColor;
        this.wheelManufacturer = wheelManufacturer;
        this.type = type;
        this.price = price;
    }
    
    //get、set方法

1.2 接口(interface)

public interface CarFactoryService {
    /**
     * 描述:制造车辆
     * @return
     */
    Car produceCar();
}

1.3 被代理类(real-class)

public class RealCarFactory implements CarFactoryService {

    //被代理逻辑
    @Override
    public Car produceCar() {
        return new Car(1L, "red", "上海轮胎橡胶", "suv", new BigDecimal(115239.28));
    }
}

2. 静态代理

静态代理需要定义父类或接口,并要求代理类和被代理类继承相同的父类或实现相同的接口。

2.1 代理类(proxy-static)

public class ProxyStaticCarFactory implements CarFactoryService {

    //被代理类
    private RealCarFactory realCarFactory;

    public ProxyStaticCarFactory(RealCarFactory realCarFactory){
        this.realCarFactory = realCarFactory;
    }

    @Override
    public Car produceCar() {
        //此处加入增强逻辑  start
        //....
        //此处加入增强逻辑  end
        Car car = this.realCarFactory.produceCar();
        //此处加入增强逻辑  start
        //....
        //此处加入增强逻辑  end
        return car;
    }
}

2.2 静态代理测试/调用

	//静态代理测试
    @Test
    public void testStaticProxy(){
        CarFactoryService proxy = new ProxyStaticCarFactory(new RealCarFactory());
        Car car = proxy.produceCar();
    }

3. 动态代理

静态代理只是一个基础的应用而已,动态代理才是重中之重,与静态代理相对。动态代理在开发阶段并不需要关心被代理对象是什么,在运行阶段才会生成代理类。我们经常提到的AOP(面向切面编程)背后的核心机制就依赖于动态代理,如果我们要开发属于自己的 AOP 框架,就需要使用动态代理。

3.1 JDK代理

3.1.1 匿名类方式

public class ProxyJdk {

    //被代理类
    private Object target;

    public ProxyJdk(Object RealTarget) {
        this.target = RealTarget;
    }

    public Object getProxyInstance(){
        return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), new InvocationHandler() {
            /**
             * @param proxy 生成的代理对象
             * @param method 需要执行的目标方法
             * @param args 需要执行的目标方法参数
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //此处加入增强逻辑  start
                //....
                //此处加入增强逻辑  end
                return method.invoke(target, args);
            }
        });
    }
}

3.1.2 显式的实现 InvocationHandler 接口方式

public class ProxyInvocation implements InvocationHandler {

    //被代理类
    private Object target;

    public ProxyInvocation(Object RealTarget) {
        this.target = RealTarget;
    }

    public Object getProxyInstance(){
        return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
    }

    /**
     * @param proxy 生成的代理对象
     * @param method 需要执行的目标方法
     * @param args 需要执行的目标方法参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //此处加入增强逻辑  start
        //....
        //此处加入增强逻辑  end
        return method.invoke(target, args);
    }
}

3.2 Cglib代理

3.1.1 实现 MethodInterceptor 接口

public class ProxyCglib implements MethodInterceptor {

    //被代理类
    private Object target;

    public ProxyCglib(Object RealTarget) {
        this.target = RealTarget;
    }

    public Object getProxyInstance(){
        //Cglib中的加强器,用来创建动态代理
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(this.target.getClass());
        //设置回调,这里相当于是对于代理类上所有方法的调用,都会调用Callback,而Callback则需要实现intercept()方法进行拦截
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //此处加入增强逻辑  start
        //....
        //此处加入增强逻辑  end
        return methodProxy.invokeSuper(object, objects);
    }
}

3.3 动态代理测试/调用

    //Jdk代理--匿名类
    @Test
    public void testJdkProxy1(){
        ProxyJdk proxyJdk = new ProxyJdk(new RealCarFactory());
        CarFactoryService carFactoryService = (CarFactoryService)proxyJdk.getProxyInstance();
        Car car = carFactoryService.produceCar();
    }

    //Jdk代理--实现 InvocationHandler 接口
    @Test
    public void testJdkProxy2(){
        ProxyInvocation proxyInvocation = new ProxyInvocation(new RealCarFactory());
        CarFactoryService carFactoryService = (CarFactoryService)proxyInvocation.getProxyInstance();
        Car car = carFactoryService.produceCar();
    }

    //Cglib代理--实现 MethodInterceptor 接口
    @Test
    public void testCglibProxy(){
        ProxyCglib proxyCglib = new ProxyCglib(new RealCarFactory());
        CarFactoryService carFactoryService = (CarFactoryService)proxyCglib.getProxyInstance();
        Car car = carFactoryService.produceCar();
    }

总结

  1. 目标接口存在父类或实现了接口,使用 Jdk 代理;
  2. 目标接口不存在父类或未实现接口,使用 cglib 代理;
  3. 代理模式尤其是动态代理应用特别广泛,大到一个系统架构,小到某个小小的代码片段等,都可能/可以用到代理模式。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值