设计模式——职责链模式
1. 什么是职责链模式?
当请求发送过来时,经过一环扣一环地对这个请求进行处理,返回结果时从最后一环往前返回。这就是职责链,犹如老师点名一组人one by one回答问题,别问我为啥想起这个比喻。
2. 职责链要解决的问题及应用场景
职责链模式主要解决请求发送者不知道具体哪个处理者,甚至不知道有多少个处理者。决定权不在请求者,而在处理者。
常见的应用场景如:
- 对http请求进行鉴权,需要经过层层校验;
- 对http请求进行限流、黑名单等一系列功能。如Spring Cloud Gateway框架中的Filter。
可以看到职责链经常用于http过滤器,网关、鉴权等中间件中,在处理业务代码逻辑时并不常见,后面遇到适用的业务场景再跟大家分享。
3. 代码实现
需求:对一个请求进行鉴权和设备类型的处理
这里参考Spring中的过滤器写法
-
定义请求内容
/** * @author Tarzan写bug */ public class Request { /** * 是否鉴权 */ private boolean auth; /** * 设备类型 */ private DeviceType deviceType; public boolean isAuth() { return auth; } public void setAuth(boolean auth) { this.auth = auth; } public DeviceType getDeviceType() { return deviceType; } public void setDeviceType(DeviceType deviceType) { this.deviceType = deviceType; } public enum DeviceType { PC, APP, ; } }
-
处理器接口
/** * @author Tarzan写bug */ public interface Processor { void doHandler(Request request, ProcessorChain chain); }
-
处理链接口
/** * @author Tarzan写bug */ public interface ProcessorChain { void doHandler(Request request); }
-
鉴权处理器
/** * @author Tarzan写bug */ public class AuthenticationProcessor implements Processor { @Override public void doHandler(Request request, ProcessorChain chain) { if (request.isAuth()) { System.out.println("AuthenticationProcessor start"); chain.doHandler(request); System.out.println("AuthenticationProcessor end"); } } }
-
设备类型处理器
/** * @author Tarzan写bug */ public class RequestDeviceProcessor implements Processor { @Override public void doHandler(Request request, ProcessorChain chain) { if (Request.DeviceType.APP.equals(request.getDeviceType())) { System.out.println("RequestDeviceProcessor start"); chain.doHandler(request); System.out.println("RequestDeviceProcessor end"); } } }
-
处理链默认实现
/** * @author Tarzan写bug */ public class DefaultProcessorChain implements ProcessorChain { private List<Processor> processors = new ArrayList<>(); private int currentPosition = 0; public DefaultProcessorChain(Processor... processors) { this(Arrays.asList(processors)); } public DefaultProcessorChain(List<Processor> processors) { this.processors = processors; } @Override public void doHandler(Request request) { if (currentPosition == processors.size()) { return; } currentPosition++; Processor nextProcessor = processors.get(currentPosition - 1); nextProcessor.doHandler(request, this); } }
-
测试类
/** * @author Tarzan写bug */ public class ProcessorChainMain { public static void main(String[] args) { Request request = new Request(); request.setAuth(true); request.setDeviceType(Request.DeviceType.APP); DefaultProcessorChain defaultProcessorChain = new DefaultProcessorChain(new RequestDeviceProcessor(), new AuthenticationProcessor()); defaultFilterChain.doHandler(request); } }
4. Spring中的过滤器
Spring中的过滤器Filter
是职责链模式的一种实现,通过CompositeFilter
中的内部类VirtualFilterChain实现
/**
* Filter实现类,使用了组合模式
*/
public class CompositeFilter implements Filter {
private List<? extends Filter> filters = new ArrayList();
public CompositeFilter() {
}
/**
* 将其他Filter实现类存储到filters变量中
*/
public void setFilters(List<? extends Filter> filters) {
this.filters = new ArrayList(filters);
}
public void init(FilterConfig config) throws servletexception {
Iterator var2 = this.filters.iterator();
while(var2.hasNext()) {
Filter filter = (Filter)var2.next();
filter.init(config);
}
}
/**
* 调用内部类VirtualFilterChain的doFilter方法
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, servletexception {
(new CompositeFilter.VirtualFilterChain(chain, this.filters)).doFilter(request, response);
}
public void destroy() {
int i = this.filters.size();
while(i-- > 0) {
Filter filter = (Filter)this.filters.get(i);
filter.destroy();
}
}
private static class VirtualFilterChain implements FilterChain {
private final FilterChain originalChain;
private final List<? extends Filter> additionalFilters;
private int currentPosition = 0;
public VirtualFilterChain(FilterChain chain, List<? extends Filter> additionalFilters) {
this.originalChain = chain;
this.additionalFilters = additionalFilters;
}
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, servletexception {
if (this.currentPosition == this.additionalFilters.size()) {
this.originalChain.doFilter(request, response);
} else {
// 调用一次doFilter方法下标+1
++this.currentPosition;
// 返回当前下标-1的过滤器
Filter nextFilter = (Filter)this.additionalFilters.get(this.currentPosition - 1);
// 调用过滤器中的doFilter方法
// 关键在方法中的this传参,将当前类做为参数传递给过滤器
// 当过滤器再次调用FilterChain.doFilter方法时就可以知道下一个下标值了
nextFilter.doFilter(request, response, this);
}
}
}
}
重点
:这里将过滤链类做为参数传递给下一个过滤器,所以可以一直保存过滤器集合的当前下标。
将前面的需求用Spring中的过滤器实现:
/**
* @author Tarzan写bug
*/
@Component
public class AuthenticationFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, servletexception {
HttpServletRequest request = (HttpServletRequest) servletRequest;
boolean isAuth = request.getHeader("isAuth").equals("true") ? true : false;
if (isAuth) {
System.out.println("AuthenticationFilter start");
}
chain.doFilter(servletRequest, servletResponse);
System.out.println("AuthenticationFilter end");
}
}
/**
* @author Tarzan写bug
*/
@Component
public class RequestDeviceFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, servletexception {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String device = request.getHeader("device");
if (Request.DeviceType.APP.name().equals(device)) {
System.out.println("RequestDeviceFilter start");
}
chain.doFilter(servletRequest, servletResponse);
System.out.println("RequestDeviceFilter end");
}
}
5. 在其他框架中用到的职责链
由于最近在研究Nacos,看见有段这样的代码
public class ConfigFilterChainManager implements IConfigFilterChain {
private final List<IConfigFilter> filters = Lists.newArrayList();
public ConfigFilterChainManager(Properties properties) {
ServiceLoader<IConfigFilter> configFilters = ServiceLoader.load(IConfigFilter.class);
for (IConfigFilter configFilter : configFilters) {
configFilter.init(properties);
addFilter(configFilter);
}
}
/**
* Add filter.
*
* @param filter filter
* @return this
*/
public synchronized ConfigFilterChainManager addFilter(IConfigFilter filter) {
// 根据order大小顺序插入
int i = 0;
while (i < this.filters.size()) {
IConfigFilter currentValue = this.filters.get(i);
if (currentValue.getFilterName().equals(filter.getFilterName())) {
break;
}
if (filter.getorder() >= currentValue.getorder() && i < this.filters.size()) {
i++;
} else {
this.filters.add(i, filter);
break;
}
}
if (i == this.filters.size()) {
this.filters.add(i, filter);
}
return this;
}
@Override
public void doFilter(IConfigRequest request, IConfigResponse response) throws NacosException {
new VirtualFilterChain(this.filters).doFilter(request, response);
}
private static class VirtualFilterChain implements IConfigFilterChain {
private final List<? extends IConfigFilter> additionalFilters;
private int currentPosition = 0;
public VirtualFilterChain(List<? extends IConfigFilter> additionalFilters) {
this.additionalFilters = additionalFilters;
}
@Override
public void doFilter(final IConfigRequest request, final IConfigResponse response) throws NacosException {
if (this.currentPosition != this.additionalFilters.size()) {
this.currentPosition++;
IConfigFilter nextFilter = this.additionalFilters.get(this.currentPosition - 1);
nextFilter.doFilter(request, response, this);
}
}
}
}
熟悉的味道,熟悉的配方。不能说相似,简直跟Spring中Filter实现一模一样。这个类的作用是Nacos做为配置中心时,客户端收到了配置变更的事件,ConfigFilterChainManager对配置文件的内容进行过滤,再保存在客户端内存中。
谢谢阅读,就分享到这,未完待续…
欢迎同频共振的那一部分人
作者公众号:Tarzan写bug
原文地址:https://www.jb51.cc/wenti/3280205.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。