原文链接

动态代理是一种强大的功能,它可以在运行时动态创建一个类,实现一个或多个接口,可以在不修改原有类的基础上动态为通过该类获取的对象添加方法、修改行为,这些特性使得它广泛应用于各种系统程序、框架和库中,比如Spring, Hibernate, MyBatis, Guice等。

动态代理是实现面向切面的编程(AOP - Aspect Oriented Programming)的基础,切面的例子有日志、性能监控、权限检查、数据库事务等,它们在程序的很多地方都会用到,代码都差不多,但与某个具体的业务逻辑关系也不太密切,如果在每个用到的地方都写,代码会很冗余,也难以维护,AOP将这些切面与主体逻辑相分离,代码简单优雅的多。

和注解类似,在大部分的应用编程中,我们不需要自己实现动态代理,而只需要按照框架和库的文档说明进行使用就可以了。不过,理解动态代理有助于我们更为深刻的理解这些框架和库,也能更好的应用它们,在自己的业务需要时,也能自己实现。

理解动态代理,我们首先要了解静态代理,了解了静态代理后,我们再来看动态代理。动态代理有两种实现方式,一种是Java SDK提供的,另外一种是第三方库如cglib提供的。

静态代理

我们首先来看代理,代理是一个比较通用的词,作为一个软件设计模式,它在《设计模式》一书中被提出,基本概念和日常生活中的概念是类似的,代理背后一般至少有一个实际对象,代理的外部功能和实际对象一般是一样的,用户与代理打交道,不直接接触实际对象,虽然外部功能和实际对象一样,但代理有它存在的价值,比如:

  • 节省成本比较高的实际对象的创建开销,按需延迟加载,创建代理时并不真正创建实际对象,而只是保存实际对象的地址,在需要时再加载或创建
  • 执行权限检查,代理检查权限后,再调用实际对象
  • 屏蔽网络差异和复杂性,代理在本地,而实际对象在其他服务器上,调用本地代理时,本地代理请求其他服务器

动态代理

相比静态代理,动态代理看起来麻烦了很多,它有什么好处呢?使用它,可以编写通用的代理逻辑,用于各种类型的被代理对象,而不需要为每个被代理的类型都创建一个静态代理类。

Java SDK代理与cglib代理比较

Java SDK代理面向的是一组接口,它为这些接口动态创建了一个实现类,接口的具体实现逻辑是通过自定义的InvocationHandler实现的,这个实现是自定义的,也就是说,其背后都不一定有真正被代理的对象,也可能多个实际对象,根据情况动态选择。cglib代理面向的是一个具体的类,它动态创建了一个新类,继承了该类,重写了其方法。

从代理的角度看,Java SDK代理的是对象,需要先有一个实际对象,自定义的InvocationHandler引用该对象,然后创建一个代理类和代理对象,客户端访问的是代理对象,代理对象最后再调用实际对象的方法,cglib代理的是类,创建的对象只有一个。

如果目的都是为一个类的方法增强功能,Java SDK要求该类必须有接口,且只能处理接口中的方法,cglib没有这个限制。