设计模式—代理模式(Proxy)

代理模式的应用场景:springAOP、旧业务代码改造
静态代理:
首先有个业务接口IPayChannelService,里面有2个功能:扣款、退款

public interface IPayChannelService {
    public boolean pay(String orderId);
    public boolean refund(String orderId);
}

旧有实现类AlipayChannelService,处理扣款、退款业务

public class AlipayChannelService implements IPayChannelService {
    @Override
    public boolean pay(String orderId) {
        System.out.println("orderId: " + orderId + " ,pay success !");
        return true;
    }
    @Override
    public boolean refund(String orderId) {
        System.out.println("orderId: " + orderId + " ,refund success !");
        return true;
    }
}

业务要求:新增一个订单查询功能并且增加退款的处理逻辑,扣款功能保持不变
我们首先想到的是修改AlipayChannelService类的refund()方法,并新增一个query()方法。但是前辈们的旧代码如果晦涩难懂,那么直接改动AlipayChannelService类的勇气是值得商榷的。
这时候可以新写一个类StaticProxyService ,兼具旧类的功能,并且增加一定的功能扩展

public class StaticProxyService implements IPayChannelService {
    private AlipayChannelService alipayChannelService;
    public StaticProxyService() {
        this.alipayChannelService = new AlipayChannelService();
    }
    @Override
    public boolean pay(String orderId) {
        return alipayChannelService.pay(orderId);
    }
    @Override
    public boolean refund(String orderId) {
        /**
         *  增加新的退款处理逻辑
         */
        System.out.println("StaticProxyService - orderId: " + orderId + " , refund success !");
        return alipayChannelService.refund(orderId);
    }
    public boolean query(String orderId) {
        System.out.println("StaticProxyService - orderId: " + orderId + " ,query success !");
        return true;
    }
}

StaticProxyService 类兼具了旧AlipayChannelService 类的扣款功能、并且增加了退款处理逻辑、查询功能。这样做不需要将AlipayChannelService类中的代码复制粘贴一遍到新类,也不用冒改动旧代码的风险。

public static void main(String[] args) {

    IPayChannelService staticProxyService = new StaticProxyService();
    ((StaticProxyService) staticProxyService).query("123");
    staticProxyService.refund("456");
    staticProxyService.pay("789");
}


执行结果可以看到,依旧执行了旧类中的pay()和refund(),同时在执行refund()前加入了新退款逻辑,并且执行了新增的查询功能。
JDK动态代理:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Description 动态代理类
 * Created by  szd
 * Email 1911150175@qq.com
 * date on 2019/8/7
 **/
public class DynamicProxyService implements InvocationHandler {
    private Object proxyTarget;
    public Object getProxyInstance(Object target) {
        this.proxyTarget = target;
        return Proxy.newProxyInstance(proxyTarget.getClass().getClassLoader(), proxyTarget.getClass().getInterfaces(), this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        /**
         *  1.这里不能用入参中的proxy对象,不然会一直循环代理
         *  2.使用proxyTarget的原因,在执行getProxyInstance()方法时,已经获得了代理对象的实例,用代理对象来invoke()
         */
        return method.invoke(proxyTarget, args);
    }
}
public static void main(String[] args) {
    DynamicProxyService dynamicProxyService = new DynamicProxyService();
    IPayChannelService payChannelService = (IPayChannelService) dynamicProxyService.getProxyInstance(new AlipayChannelService());
    payChannelService.pay("123");
}

动态代理,运用场景在于做切面,尤其是springAOP,日志框架等,在执行目标方法method.invoke(proxyTarget,args)前(before)、后(after),进行其他处理

CGLIB动态代理:
对于无继承(实现接口)的类,JDK动态代理就无法实现了,这时候就只能靠cglib动态代理

public class AlipayChannelV2Service {
    public boolean pay(String orderId) {
        System.out.println("AlipayChannelV2Service orderId: " + orderId + " ,pay success !");
        return true;
    }
}
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Description CGLIB代理
 * Created by  szd
 * Email 1911150175@qq.com
 * date on 2019/8/8
 **/
public class CglibProxyService implements MethodInterceptor {
    private Object proxyTarget;
    public Object getInstance(Object target) {
        this.proxyTarget = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.proxyTarget.getClass());
        // 设置回调方法
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }
    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        return methodProxy.invokeSuper(object, args);
    }
}
public static void main(String[] args) {

    CglibProxyService cglib = new CglibProxyService();
    AlipayChannelV2Service alipayChannelV2Service = (AlipayChannelV2Service) cglib.getInstance(new AlipayChannelV2Service());
    alipayChannelV2Service.pay("123");
}

要注意的是,cglib代理对于final修饰的类是无效的,对于final修饰的方法并无影响(网上帖子说对final修饰的方法也不能代理,我没法重现,不知道是我哪里不对,希望有知道的大神可以指点一二。)
(动态代理往往用于做切面,并不去override方法,也就没有重写一说,个人觉得重写在静态代理中运用的普遍)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值