代理模式适合应用场景使用代理模式的方式多种多样 , 我们来看看最常见的几种 。
- 延迟初始化 (虚拟代理):如果你有一个偶尔使用的重量级服务对象 , 一直保持该对象运行会消耗系统资源时 , 可使用代理模式 。你无需在程序启动时就创建该对象 , 可将对象的初始化延迟到真正有需要的时候 。
- 访问控制 (保护代理):如果你只希望特定客户端使用服务对象 , 这里的对象可以是操作系统中非常重要的部分 , 而客户端则是各种已启动的程序 (包括恶意程序) , 此时可使用代理模式 。代理可仅在客户端凭据满足要求时将请求传递给服务对象 。
- 本地执行远程服务 (远程代理):适用于服务对象位于远程服务器上的情形 。在这种情形中 , 代理通过网络传递客户端请求 , 负责处理所有与网络相关的复杂细节 。
- 记录日志请求 (日志记录代理):适用于当你需要保存对于服务对象的请求历史记录时 。代理可以在向服务传递请求前进行记录 。
- 缓存请求结果 (缓存代理):适用于需要缓存客户请求结果并对缓存生命周期进行管理时 , 特别是当返回结果的体积非常大时 。代理可对重复请求所需的相同结果进行缓存 , 还可使用请求参数作为索引缓存的键值 。比如请求图片、文件等资源时 , 先到代理缓存取 , 如果没有就去公网取并缓存到代理服务器
- 智能引用:可在没有客户端使用某个重量级对象时立即销毁该对象 。代理会将所有获取了指向服务对象或其结果的客户端记录在案 。代理会时不时地遍历各个客户端 , 检查它们是否仍在运行 。如果相应的客户端列表为空 , 代理就会销毁该服务对象 , 释放底层系统资源 。代理还可以记录客户端是否修改了服务对象 。其他客户端还可以复用未修改的对象 。
AspectJ 的底层技术就是静态代理 , 用一种 AspectJ 支持的特定语言编写切面 , 通过一个命令来编译 , 生成一个新的代理类 , 该代理类增强了业务类 , 这是在编译时增强 , 相对于下面说的运行时增强 , 编译时增强的性能更好 。(AspectJ 的静态代理 , 不像我们前边介绍的需要为每一个目标类手动编写一个代理类 , AspectJ 框架可以在编译时就生成目标类的“代理类” , 在这里加了个冒号 , 是因为实际上它并没有生成一个新的类 , 而是把代理逻辑直接编译到目标类里面了)
Spring AOP 采用的是动态代理 , 在运行期间对业务方法进行增强 , 所以不会生成新类 , 对于动态代理技术 , Spring AOP 提供了对 JDK 动态代理的支持以及 CGLib 的支持 。
默认情况下 , Spring对实现了接口的类使用 JDK Proxy方式 , 否则的话使用CGLib 。不过可以通过配置指定 Spring AOP 都通过 CGLib 来生成代理类 。
文章插图
具体逻辑在
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) { }}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 如何在面试中解释各种机器学习模型
- 求职|思维策略:一项目完胜大多数所谓面试神技的策略(上)
- Spring Boot 上传图片完整示例
- SpringBoot中获取微信用户信息从未如此简单
- Spring Boot配置文件yml格式详解
- 超全、超详的Spring Boot配置讲解笔记
- 面试|我月薪5千,面试如何谈到1万?
- Java包装类与基本类型区别与应用,解析面试题
- 面试官:先来简单聊一下SQL Join,看你对数据了解的怎么样
- 谷歌面试问题50%需要用递归:理解递归算法的本质这篇够不够?