责任链模式
本文链接:https://blog.csdn.net/feather_wch/article/details/131760462
1、是一种行为型设计模式
2、主要角色
- 抽象处理者
- 具体处理者
3、允许将请求沿着一系列处理者进行传递,直到有一个处理者可以处理该请求
- 解耦请求 发送者 和 处理者
- 可以动态改变处理者链条的顺序和内容
4、在Java中,责任链模式有多种实现方式,例如:
- 使用抽象处理者类和具体处理者类,每个处理者类都有一个指向下一个处理者的引用,以及一个抽象的处理请求的方法。这种方式可以实现灵活的链构建和动态地添加或删除处理者。²
- 使用过滤器接口和过滤器链类,每个过滤器都实现了一个过滤方法,过滤器链类负责将过滤器串联起来,并提供一个执行过滤的方法。这种方式可以实现简单的责任链模式,常用于对请求进行预处理或后处理。³
- 使用注解和反射机制,每个处理者都使用注解来标识自己的优先级或顺序,通过反射机制来获取所有的处理者并按照注解来排序,然后依次执行处理请求的方法。这种方式可以实现无侵入性的责任链模式,不需要修改原有的代码结构。
优点和缺点
责任链模式的优点有:
- 请求与处理解耦,降低了系统的耦合度¹
- 处理者只需要关心自己的处理逻辑,不需要知道链条的结构和其他处理者的情况²
- 易于维护,可以灵活地增加或删除处理者,符合开闭原则³
责任链模式的缺点有:
- 产生很多细粒度的对象,增加了系统的复杂度和开销¹
- 不一定能处理请求,可能出现请求无人响应的情况,需要提供默认处理和检查链条的有效性⁴
实例:日志处理->抽象处理者类和具体处理者类
// 定义日志级别常量
public class LogLevel {public static final int INFO = 1;public static final int DEBUG = 2;public static final int ERROR = 3;
}
抽象处理者
// 定义抽象日志记录器类
public abstract class Logger {// 保存下一个日志记录器的引用protected Logger nextLogger;// 保存当前日志记录器的日志级别protected int level;// 设置下一个日志记录器public void setNextLogger(Logger nextLogger) {this.nextLogger = nextLogger;}// 处理日志请求public void logMessage(int level, String message) {// 如果当前日志记录器的级别大于等于请求的级别,则输出日志信息if (this.level <= level) {write(message);}// 如果存在下一个日志记录器,则传递给它继续处理if (nextLogger != null) {nextLogger.logMessage(level, message);}}// 抽象方法,由具体子类实现protected abstract void write(String message);
}
具体处理者
// 定义具体日志记录器类:控制台日志记录器
public class ConsoleLogger extends Logger {// 构造方法,设置当前日志记录器的级别为INFOpublic ConsoleLogger() {this.level = LogLevel.INFO;}// 实现write方法,输出到控制台@Overrideprotected void write(String message) {System.out.println("Console Logger: " + message);}
}// 定义具体日志记录器类:文件日志记录器
public class FileLogger extends Logger {// 构造方法,设置当前日志记录器的级别为DEBUGpublic FileLogger() {this.level = LogLevel.DEBUG;}// 实现write方法,输出到文件(这里简化为控制台)@Overrideprotected void write(String message) {System.out.println("File Logger: " + message);}
}// 定义具体日志记录器类:错误日志记录器
public class ErrorLogger extends Logger {// 构造方法,设置当前日志记录器的级别为ERRORpublic ErrorLogger() {this.level = LogLevel.ERROR;}// 实现write方法,输出到错误日志(这里简化为控制台)@Overrideprotected void write(String message) {System.out.println("Error Logger: " + message);}
}// 定义客户端类
public class Client {public static void main(String[] args) {// 创建各个日志记录器对象Logger consoleLogger = new ConsoleLogger();Logger fileLogger = new FileLogger();Logger errorLogger = new ErrorLogger();// 构建责任链,设置每个日志记录器的下一个日志记录器consoleLogger.setNextLogger(fileLogger);fileLogger.setNextLogger(errorLogger);// 发送不同级别的日志请求,观察输出结果consoleLogger.logMessage(LogLevel.INFO, "This is an information.");consoleLogger.logMessage(LogLevel.DEBUG, "This is a debug message.");consoleLogger.logMessage(LogLevel.ERROR, "This is an error message.");}
}
输出结果:
Console Logger: This is an information.
Console Logger: This is a debug message.
File Logger: This is a debug message.
Console Logger: This is an error message.
File Logger: This is an error message.
Error Logger: This is an error message.
从输出结果可以看出,每个日志记录器都会根据自己的级别来决定是否输出日志信息,并且会将请求传递给下一个日志记录器继续处理。这样就实现了责任链模式的功能。
实例二:
责任链和OkHttp
1、OkHttp采用的哪种责任链模式
- 采用的是不纯的责任链模式
- 每个拦截器都组装了响应的一部分
2、OkHttp定义了两个接口
- Interceptor:Response r = intercept(Chain c)
- Interceptor.Chain: Response r = intercept(Request q)
- 实现了Chain接口的内部类RealInterceptorChain
3、抽象处理者:Interceptor
- Interceptor接口中只有一个方法:intercept
- 接收一个Chain对象作为参数
- 返回一个Response对象作为结果。
4、具体处理者:每个实现了Interceptor接口的类都负责处理响应的一部分,并调用Chain对象的proceed方法来传递给下一个拦截器继续处理。
5、Chain接口中也只有一个方法:proceed
- 接收一个Request对象作为参数
- 返回一个Response对象作为结果
- Chain对象负责执行intercept方法,并维护当前拦截器的索引和列表。
4、RealInterceptorChain类是Chain接口的具体实现类,1. 包含了一个拦截器列表、一个网络连接对象、一个请求对象、一个响应对象、一个重试次数和一个索引。
2. 它在proceed方法中根据索引来获取当前拦截器
3. 并调用其intercept方法来处理请求和响应,并将自身作为参数传递给下一个拦截器。
5、OkHttp和责任链模式的总结
- Interceptor负责处理请求和响应的一部分
- Interceptor通过Chain.proceed()传递给下一个拦截器处理
- Chain会找到下一个拦截器,并且执行器intercept()方法
6、RealInterceptorChain是什么
- 内部维护了List interceptors
- proceed()方法中通过index找到下一个拦截器,并且执行其intercept()方法,返回其Response给上一层
- 用于用户拦截器和网络拦截器
OkHttp源码流程
6、OkHttp拦截器执行流程是指OkHttp如何通过一系列的拦截器来实现网络请求和响应的处理的过程。
拦截器是一种可以对请求和响应进行修改或监控的组件,它实现了Interceptor接口,该接口只有一个方法:intercept,它接收一个Chain对象作为参数,并返回一个Response对象作为结果。
Chain是一个接口,它提供了一个方法:proceed,用于调用链中的下一个拦截器,并维护当前拦截器的索引和列表。Chain对象负责执行intercept方法,并将自身作为参数传递给下一个拦截器继续处理。
7、OkHttp中的拦截器
OkHttp中有多种拦截器,它们可以对请求和响应进行修改或监控,例如重试、重定向、缓存、连接、桥接等。³
8、OkHttp拦截器执行流程大致如下:
- 首先,用户通过OkHttpClient发起一个网络请求,该请求会被封装成一个Call对象,并加入到任务队列中等待执行。⁴
- 然后,Call对象会被分配给一个异步线程来执行,该线程会创建一个Transmitter对象,用于管理请求的发送和取消。⁴
- 【应用层拦截器】然后,会创建拦截器列表。将用户添加的应用层拦截器添加到列表中interceptors.addAll(client.interceptors())(通过OkHttpClient.addInterceptor方法添加)
- 【重试和重定向拦截器】接着,将RetryAndFollowUpInterceptor对象作为第二个拦截器添加到拦截器列表中。该拦截器负责实现重试和重定向的功能。⁴
- 【桥接拦截器】接着,将BridgeInterceptor对象,并将其作为第三个拦截器加入到拦截器列表中。该拦截器负责将用户构造的请求转换为向服务器发送的请求,将服务器返回的响应转换为对用户友好的响应。⁴
- 【缓存拦截器】然后,会创建一个CacheInterceptor对象,并将其作为第四个拦截器加入到拦截器列表中。该拦截器负责读取缓存、更新缓存、处理缓存策略等。⁴
- 【链接拦截器】接着,会创建一个ConnectInterceptor对象,并将其作为第五个拦截器加入到拦截器列表中。该拦截器负责建立与服务器的连接,并创建一个Exchange对象来管理连接的使用和释放。⁴
- 【网络拦截器】然后,将用户添加的网络层拦截器添加到列表中interceptors.addAll(client.networkInterceptors())(通过OkHttpClient.addNetworkInterceptor方法添加)
- 【请求服务拦截器】接着,创建一个CallServerInterceptor对象,并将其作为最后一个拦截器加入到拦截器列表中。该拦截器负责从服务器读取响应,并处理异常情况。⁴
- 将拦截器列表作为参数,构造出RealInterceptorChain
- response = chain.proceed() 开始责任链的调用,并且获取到响应
应用层拦截器
OkHttp应用层拦截器的使用方法有:
- 创建一个实现了Interceptor接口的类
- 重写intercept方法,该方法接收一个Chain参数,代表当前的拦截器链,
- 可以通过chain.request()获取请求对象
- 可以通过chain.proceed(request)获取响应对象,也可以修改请求或者响应对象。
- 使用OkHttpClient.Builder().addInterceptor(interceptor)方法添加自定义的拦截器,可以添加多个拦截器,它们会按照添加的顺序执行。
- 使用OkHttpClient.newCall(request)方法发起请求,请求会经过所有的应用层拦截器,然后到达网络层。
代码:请求+getResponseWithInterceptorChain
// 用户通过OkHttpClient发起一个网络请求
Request request = new Request.Builder().url("https://www.example.com").build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);// Call对象被分配给一个异步线程来执行
call.enqueue(new Callback() {@Overridepublic void onResponse(Call call, Response response) {// 处理响应结果}@Overridepublic void onFailure(Call call, IOException e) {// 处理异常情况}
});
RealCall
//依次执行拦截器链中的拦截器获取结果Response getResponseWithInterceptorChain() throws IOException {List<Interceptor> interceptors = new ArrayList<>();//添加自定义拦截器interceptors.addAll(client.interceptors());//添加重试和重定向拦截器interceptors.add(retryAndFollowUpInterceptor);//添加桥接拦截器interceptors.add(new BridgeInterceptor(client.cookieJar()));//添加缓存拦截器interceptors.add(new CacheInterceptor(client.internalCache()));//添加链接拦截器interceptors.add(new ConnectInterceptor(client));if (!forWebSocket) {//添加网络拦截器interceptors.addAll(client.networkInterceptors());}//添加连接服务器拦截器,主要负责将我们的Http请求写进网络的IO流中interceptors.add(new CallServerInterceptor(forWebSocket));//构建拦截器链依次执行每一个拦截器Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest);return chain.proceed(originalRequest);}