JAVA 代理模式
来源:互联网 发布:八爪鱼数据抓取 知乎 编辑:程序博客网 时间:2024/06/14 17:15
代理模式的应用场景主要有四种。
1) 远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中(例:WebService, WCF, RPC 之类的)。
2) 虚拟代理(Virtual Proxy):如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建(例:浏览器分阶段载入信息,先文字再图片)。
3) 保护代理(Protect Proxy):控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限(例:多级权限系统)。
4) 缓冲代理(Cache Proxy):为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果(例:访问频繁时用的缓冲机制)。
5) 智能引用代理(Smart Reference Proxy):当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数、方法的执行记录下来等。
实际上,各种应用场景的实现方式是类似的,下面以智能引用代理场景为例对代理模式进行介绍。假设我们有一个服务是用户登录到网站的操作。其接口及实现类如下。
public interface UserLogin { boolean login(User user);}public class UserLoginImpl implements UserLogin { @Override public boolean login(User user) { //validateUser 检查是否是合法用户 if(validateUser(user)) return true; return false; }}
现在需要在用户登录前,打印用户登录日志,那么我们可以创建一个 UserLoginProxy 代理类,在其中添加打印日志的操作。代理类需要实现被代理类的接口,这样代理类才能替代被代理类而被客户端调用。
public class UserLoginProxy implements UserLogin { private UserLogin userLogin; //1. 控制用户对 UserLoginImpl 的访问权限,在代理类中生成被代理对象 public UserLoginProxy(){ userLogin = new UserLoginImpl(); } //2. 采用注入的方式得到被代理的对象,Spring AOP 即用注入获得被代理对象 public UserLoginProxy(UserLogin userLogin){ this.userLogin = userLogin; } @Override public boolean login(User user) { System.out.println("User " + user.getUserId() + " is logging in."); return userLogin.login(user); }}
客户端调用 UserLogin 的地方改为调用其代理类 UserLoginProxy ,即实现了代理。
public class UserLoginService { public boolean consumer(UserLogin userLogin, User user){ return userLogin.login(user); } public static void main(String[] args) { UserLoginService userLoginService = new UserLoginService(); User user = new User("John Smith"); UserLoginProxy userLogin = new UserLoginProxy(); userLoginService.consumer(userLogin, user); }}
代理类 UserLoginProxy 和被代理类 UserLoginImpl 实现相同的接口,从客户端消费者角度来看,二者并没有区别,因此代理类可以出现在原本需要被代理类的地方,达到了记录执行日志的目的。这种手动写出代理类的方式我们称之为静态代理,其实用性并不高,我们不可能对每个需要记录执行日志的类手动创建一个代理类。
Java 提供了动态代理的方式,使得开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。
首先,我们提供一个统一的代理类生成类(实现 InvocationHandler 接口),并在其中写明代理类需要增加的操作(例如打印执行日志)。注意,DynamicProxy 定义的是代理行为而非代理类本身。实际上代理类及其实例是在运行时通过反射动态创建出来的。
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class DynamicProxy implements InvocationHandler { //也可以采用注入的方式得到被代理的对象 private Object proxied; public DynamicProxy(Object proxied){ this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("login".equals(method.getName())){ User user = (User) args[0]; System.out.println("User "+ user.getUserId() + " is logging in."); }else{ System.out.println("Before " + proxy.getClass().getSimpleName() + " " + method + " method"); } Object rtn = method.invoke(proxied, args); return rtn; }}
在客户端消费者需要使用被代理类时,采用如下的方式进行调用。
public class UserLoginService { public boolean consumer(UserLogin userLogin, User user){ return userLogin.login(user); } public static void main(String[] args) { UserLoginService userLoginService = new UserLoginService(); UserLogin userLogin = (UserLogin) Proxy.newProxyInstance(UserLogin.class.getClassLoader(), new Class[]{UserLogin.class}, new DynamicProxy(new UserLoginImpl())) User user = new User("John Smith"); userLoginService.consumer(userLogin, user); }}
不止 UserLogin ,当需要对其它的方法进行执行日志记录时,我们可以用同样的方式,动态生成其代理类。
从以上的例子可以看出,使用 JDK 生成动态代理类要求被代理类至少实现了一个接口,如果被代理类实现了多个接口,可以在 proxy.newProxyInstance()
时对多个接口同时实现代理,使代理类实现相同的每一个接口,这样在每一个用到了被代理类的地方,都能使用代理类替代。
如果被代理类没有实现任何接口,而又需要对其进行代理时,可以借助一个高性能的代码生成库 cglib 来实现。Spring AOP 也引入了 cglib 工具,当被代理类实现了接口时,Spring AOP 使用 JDK 自带的动态代理方式进行 AOP 操作;如果被代理类没有实现任何接口,Spring AOP 则借助于 cglib 生成目标的动态代理类,实现 AOP 操作。
- Java代理之代理模式
- java代理模式---静态代理
- java代理模式--动态代理
- 代理模式&java动态代理
- JAVA代理模式--静态代理
- JAVA代理模式--动态代理
- JAVA动态代理 代理模式
- Java代理模式-静态代理
- java代理模式-动态代理
- Java代理模式 静态代理 动态代理
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- JAVA代理模式与动态代理模式
- Java代理模式和kotlin代理模式
- Java中的代理模式
- POJ 3922 A simple stone game(K倍减法游戏)
- Kafka学习(一):Kafka背景及架构介绍
- zabbix变量 【转】
- MySQL的主从复制(gtid)
- JQuery入门(二)
- JAVA 代理模式
- 【C语言】最大公约数和最小公倍数
- Android保存Bitmap为本地文件
- PHP 选择排序 案例
- 数据结构学习笔记
- SCU
- Excel在统计分析中的应用—第四章—数据库统计函数与数据透视表-Part3-(数据透视表、图)
- Kafka学习(二):Kafka的基本结构和概念
- 小白学tkinter(Entry组件)