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

本文详细介绍了代理模式在Java中的应用,包括静态代理和动态代理。静态代理通过接口实现,动态代理则分为JDK动态代理和Cglib动态代理。代理模式常用于日志记录、事务管理、安全性控制等场景,它能实现方法增强,提高代码复用。JDK动态代理基于接口生成代理类,而Cglib则是通过继承实现,效率相对更高。
摘要由CSDN通过智能技术生成

代理设计模式主要对方法前后实现增强

应用场景

1 打印日志
2 AOP底层通过代理模式封装
3 事务@Transactional 底层AOP
4 Mybatis中的mapper接口
5 全局捕获异常
6 Lcn、Seata、分表分库框架sharding-jdbc 代理数据源
7 自定义注解生效
8 Rpc远程调用技术(通过dubbo调用接口只会引入接口)

代理模式优缺点

优点:实现扩展功能、对方法实现增强、安全性、解决代码冗余提高代码复用机制
缺点:生成非常多的class文件(代理类)

代理模式的分类

静态代理与动态代理

代理模式实现的原理

代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy),如图所示:

请添加图片描述

  • 抽象主题角色:可以是接口,也可以是抽象类;
  • 委托类(被代理类)角色:真实主题角色,业务逻辑的具体执行者;
  • 代理类角色:内部含有对真实对象的引用,负责对真实主题角色的调用,并在真实主题角色处理前后做预处理和后处理。

eg:买房 中介 卖房(被代理类) 

1.静态代理的实现方式

基于接口实现(Jdk动态代理)和继承模式(Cglib字节码)

1.1 基于接口方式

接口

public interface OrderService {
    String addOrder(String orderId, String orderName);
}

实现类

public class OrderServiceImpl implements OrderService {
    @Override
    public String addOrder(String orderId, String orderName) {
        System.out.println("OrderServiceImpl真实方法执行...");
        return orderId + "," + orderName;
    }
}

代理类

public class OrderServiceProxy implements OrderService {
    //被代理类
    private OrderServiceImpl orderServiceImpl;

    public OrderServiceProxy(OrderServiceImpl orderServiceImpl) {
        this.orderServiceImpl = orderServiceImpl;
    }

    @Override
    public String addOrder(String orderId, String orderName) {
        System.out.println("采用代理模式统一打印日志 orderId:" + orderId + ",orderName:" + orderName);
        return orderServiceImpl.addOrder(orderId, orderName);

    }
}

测试

public class Test {
    public static void main(String[] args) {
        OrderService orderServiceProxy = new OrderServiceProxy(new OrderServiceImpl());
        orderServiceProxy.addOrder("mayikt", "111");
    }
}

1.2 基于继承方式

接口

public interface OrderService {
    String addOrder(String orderId, String orderName);
}

实现类

public class OrderServiceImpl implements OrderService {
    @Override
    public String addOrder(String orderId, String orderName) {
        System.out.println("OrderServiceImpl真实方法执行...");
        return orderId + "," + orderName;
    }
}

代理类

public class OrderServiceProxy extends OrderServiceImpl {
    @Override
    public String addOrder(String orderId, String orderName) {
        System.out.println("采用代理模式统一打印日志 orderId:" + orderId + ",orderName:" + orderName);
        return super.addOrder(orderId, orderName);
    }
}

测试

public class Test {
    public static void main(String[] args) {
        OrderService orderServiceProxy = new OrderServiceProxy();
        orderServiceProxy.addOrder("mayikt", "111");
    }
}

2.动态代理的实现方式

jdk动态代理和cglib动态代理

2.1 JDK动态代理方式

接口

public interface OrderService {
    String addOrder(String orderId, String orderName);
}

实现类

public class OrderServiceImpl implements OrderService {
    @Override
    public String addOrder(String orderId, String orderName) {
        System.out.println("OrderServiceImpl真实方法执行...");
        return orderId + "," + orderName;
    }
}

事件处理器(用于动态生成代理类)

public class JdkInvocationHandler implements InvocationHandler {
    //目标对象(被代理类)
    private Object target;

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

    /**
     * @param proxy  jdk动态生成的代理类
     * @param method 不是真正的目标方法,接口中的方法,底层通过反射执行真正目标方法
     * @param args   代理类参数
     *               使用生成的代理类去拦截回调
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("jdk动态代理执行开始>>>" + args[0]);
        // 执行目标方法 java反射执行目标方法
        Object result = method.invoke(target, args);
        System.out.println("jdk动态代理执行结束>>>" + args[0]);
        return result;
    }

    /**
     * 使用jdk创建代理类对象
     *
     * @param <T>
     * @return
     */
    public <T> T getProxy() {
        // ClassLoader 读取代理类class文件
        // Class<?>[] interfaces 基于该接口拼接代理类的源代码
        // InvocationHandler this
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}

测试

public class Test {
    public static void main(String[] args) {
        JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(new OrderServiceImpl());
        // 创建代理类
        OrderService proxy = jdkInvocationHandler.getProxy();
        proxy.addOrder("mayikt", "maplefire");
    }
}

2.2 Cglib动态代理方式

接口

public interface OrderService {
    String addOrder(String orderId, String orderName);
}

实现类

public class OrderServiceImpl implements OrderService {
    @Override
    public String addOrder(String orderId, String orderName) {
        System.out.println("OrderServiceImpl真实方法执行...");
        return orderId + "," + orderName;
    }
}

方法拦截器(用于动态生成代理类)

public class CglibMethodInterceptor implements MethodInterceptor {

    /**
     * @param obj cglib生成好的代理类对象
     * @param method 目标方法
     * @param args 参数
     * @param proxy 代理
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("cglib动态代理执行开始>>>");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("cglib动态代理执行结束>>>");
        return result;
    }
}

测试

public class Test {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        //设置即将生成的代理类的父类
        enhancer.setSuperclass(OrderServiceImpl.class);
        //设置回调方法
        enhancer.setCallback(new CglibMethodInterceptor());

        // 创建代理对象
        OrderServiceImpl orderServiceImpl= (OrderServiceImpl) enhancer.create();
        orderServiceImpl.addOrder("mayikt", "maplefire");
    }
}

3.Jdk与Cglib动态代理的区别

Jdk动态代理:基于实现接口的形式生成代理类对象;使用java反射机制调用目标方法

  • 需要拼接java源代码$proxy.java
  • 需要将java源代码编译为class文件
  • 采用类加载器读取class文件到程序中
  • 采用java的反射机制执行目标方法

反射机制:method.invoke(target, args);

Cglib动态代理:基于继承目标对象生成代理类对象;(ASM)字节码技术

  • 直接采用字节码技术生成class文件(无需编译过程)
  • 采用类加载器读取class文件到程序中
  • 采用FastClass机制调用到目标方法(比反射机制效率要高)

FastClass机制:memberService.add()
FastClass对目标对象中所有的方法生成一个索引的标记,直接根据索引调用到目标方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值