动态代理

简介

动态代理在java中有着广泛的应用。比如Spring AOP、Hibernate数据查询、测试框架的后端mock、RPC远程调用、Java注解对象获取、日志、用户鉴权、全局性异常处理、性能监控,甚至事务处理等。

静态代理

假如有1个接口,如下:

public interface OrderService {
    void create(int id);
    void pay(int id);
}

实现为:

public class OrderServiceImpl implements OrderService {

    @Override
    public void create(int id) {
        System.out.println("create order");
    }

    @Override
    public void pay(int id) {
        System.out.println("pay order");
    }
}

使用静态代理对其增强

使用

优点

这样就在不侵入原先代码的情况下,对原有对象进行了增强。

不足

  1. 新增,删除方法时,需要同时修改目标类和代理类。

  2. 当代理多个类的时候,造成代码混乱。

思考

代理类是根据目标类产生,有一定的规律。有没有什么办法在类加载阶段完成代理类的自动生成呢?

介绍2种现成的实现:

  1. 通过实现接口生成代理类。-->JDK动态代理。

  2. 通过继承生成代理类-->CGLib。

JDK动态代理

通过实现 InvocationHandler,生成代理处理器。

使用

查看下生成的代理类

  1. 代理类继承了 Proxy 类,并且实现了被代理的所有接口,以及equals、hashCode、toString等方法。

  2. 类和所有方法都被 public final 修饰,所以代理类只可被使用,不可以再被继承。

  3. 目标类的每个方法,在代理类中通过反射生成Method对象。

  4. 每个方法中的super.h都是之前设置的代理控制器(LogHandler),来执行真正的逻辑。

代理对象UML

可以看出,代理对象执行方法时,会通过继承于父类的InvocationHandler来调用代理控制器,最终调用目标类的方法。

CGLIB动态代理

目标类

日志拦截器

使用

  1. 查找目标类上的所有非final 的public类型的方法定义;

  2. 将这些方法的定义转换成字节码;

  3. 将组成的字节码转换成相应的代理的class对象;

  4. 实现 MethodInterceptor接口,用来处理对代理类上所有方法的请求。

JDK动态代理与CGLIB动态代理对比

JDK动态代理:基于Java反射机制实现,必须要实现了接口的业务类才能用这种办法生成代理对象。

cglib动态代理:基于ASM机制实现,通过生成业务类的子类作为代理类。

推荐使用:如spring一般,如果目标类实现了接口,就用jdk动态代理,反之则用cglib。

Last updated