面试官问 Spring AOP 中两种代理模式的区别,我懵逼了( 四 )

代理模式适合应用场景使用代理模式的方式多种多样 ,  我们来看看最常见的几种 。

  • 延迟初始化 (虚拟代理):如果你有一个偶尔使用的重量级服务对象 ,  一直保持该对象运行会消耗系统资源时 ,  可使用代理模式 。你无需在程序启动时就创建该对象 ,  可将对象的初始化延迟到真正有需要的时候 。
  • 访问控制 (保护代理):如果你只希望特定客户端使用服务对象 ,  这里的对象可以是操作系统中非常重要的部分 ,  而客户端则是各种已启动的程序 (包括恶意程序) ,  此时可使用代理模式 。代理可仅在客户端凭据满足要求时将请求传递给服务对象 。
  • 本地执行远程服务 (远程代理):适用于服务对象位于远程服务器上的情形 。在这种情形中 ,  代理通过网络传递客户端请求 ,  负责处理所有与网络相关的复杂细节 。
  • 记录日志请求 (日志记录代理):适用于当你需要保存对于服务对象的请求历史记录时 。代理可以在向服务传递请求前进行记录 。
  • 缓存请求结果 (缓存代理):适用于需要缓存客户请求结果并对缓存生命周期进行管理时 ,  特别是当返回结果的体积非常大时 。代理可对重复请求所需的相同结果进行缓存 ,  还可使用请求参数作为索引缓存的键值 。比如请求图片、文件等资源时 , 先到代理缓存取 , 如果没有就去公网取并缓存到代理服务器
  • 智能引用:可在没有客户端使用某个重量级对象时立即销毁该对象 。代理会将所有获取了指向服务对象或其结果的客户端记录在案 。代理会时不时地遍历各个客户端 ,  检查它们是否仍在运行 。如果相应的客户端列表为空 ,  代理就会销毁该服务对象 ,  释放底层系统资源 。代理还可以记录客户端是否修改了服务对象 。其他客户端还可以复用未修改的对象 。
AOP 中的代理模式AOP(面向切面编程)主要的的实现技术主要有 Spring AOP 和 AspectJ
AspectJ 的底层技术就是静态代理 , 用一种 AspectJ 支持的特定语言编写切面 , 通过一个命令来编译 , 生成一个新的代理类 , 该代理类增强了业务类 , 这是在编译时增强 , 相对于下面说的运行时增强 , 编译时增强的性能更好 。(AspectJ 的静态代理 , 不像我们前边介绍的需要为每一个目标类手动编写一个代理类 , AspectJ 框架可以在编译时就生成目标类的“代理类” , 在这里加了个冒号 , 是因为实际上它并没有生成一个新的类 , 而是把代理逻辑直接编译到目标类里面了)
Spring AOP 采用的是动态代理 , 在运行期间对业务方法进行增强 , 所以不会生成新类 , 对于动态代理技术 , Spring AOP 提供了对 JDK 动态代理的支持以及 CGLib 的支持 。
默认情况下 , Spring对实现了接口的类使用 JDK Proxy方式 , 否则的话使用CGLib 。不过可以通过配置指定 Spring AOP 都通过 CGLib 来生成代理类 。
面试官问 Spring AOP 中两种代理模式的区别,我懵逼了

文章插图
 
具体逻辑在
org.springframework.aop.framework.DefaultAopProxyFactory类中 , 使用哪种方式生成由AopProxy 根据 AdvisedSupport 对象的配置来决定源码如下:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {    public DefaultAopProxyFactory() {    }    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {        if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {            return new JdkDynamicAopProxy(config);        } else {            Class<?> targetClass = config.getTargetClass();            if (targetClass == null) {                throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");            } else {                //如果目标类是接口且是代理类, 使用JDK动态代理类 , 否则使用Cglib生成代理类                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));            }        }    }    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {    }}


推荐阅读