责任链模式和自定义过滤器链
什么是责任链模式:
使多个对象都有机会处理请求,从而避免请求的发送着和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
通俗理解:责任链模式就像是一条产品生产流水线,每个生产车间处理过后才会把该产品流到下一个生产车间。 如图:
java里面的责任链设计模式类图:
案例分析1:
现在有一个集合,对应三个处理方法,这三个方法各自判断集合中是否存在当前方法执行的条件,如果有则输出如果没有适合自己处理的条件则把当前请求传递下去。
以下是实现的代码片段:
抽象父类:
public abstract class Hanler {
protected Hanler successor;
public void SetSuccessor(Hanler successor){
this.successor=successor;
}
// 处理请求的方法,需要子类重写
public abstract void HandlerRequest(int request);
}
责任链上的三个角色:
ConcreteHandler1
public class ConcreteHandler1 extends Hanler {
@Override
public void HandlerRequest(int request) {
if(request>=0 && request<10){
System.out.println("ConcreteHandler1处理请求"+request);
// 其他逻辑
}
else if(successor!=null){
// 转移到下一位
successor.HandlerRequest(request);
}
}
}
ConcreteHandler2:
public class ConcreteHandler2 extends Hanler {
@Override
public void HandlerRequest(int request) {
if(request>=10 && request<20){
System.out.println("ConcreteHandle2处理请求"+request);
// 其他逻辑
}
else if(successor!=null){
// 转移到下一位
successor.HandlerRequest(request);
}
}
}
ConcreteHandler3:
public class ConcreteHandler3 extends Hanler {
@Override
public void HandlerRequest(int request) {
if(request>=20 && request<30){
System.out.println("ConcreteHandler3处理请求"+request);
// 其他逻辑
}
else if(successor!=null){
// 转移到下一位
successor.HandlerRequest(request);
}
}
}
main方法:把各个实现类串联起来形成一条“链”,如下:
public static void main(String[] args) {
Hanler h1 = new ConcreteHandler1();
Hanler h2 = new ConcreteHandler2();
Hanler h3 = new ConcreteHandler3();
// 将各个实现类串联
h1.SetSuccessor(h2);
h2.SetSuccessor(h3);
int[] requests={0,15,20,62};
for(int i=0;i<requests.length;i++){
h1.HandlerRequest(requests[i]);
}
}
测试结果为:
相信这几个代码片段大家理解起来应该不是问题啦,责任链模式就是这么简单。
责任链模式案例2
如果有使用过SpringSecurity的同学对责任链模式应该是很熟悉了,其原理设计也是使用了责任链模式,以下我们根据Filter过滤器自定义一个简易版的责任链模式。
基于Filter实现过滤器链版本1
实现思路: 新建多个类实现Filter接口,通过@Order注解指定各个实现类的执行顺序:
过滤器1: MyFilter1 获取请求地址
@Component
@Order(1)
public class MyFilter1 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
System.out.println("执行MyFilter1当前请求地址==" + request.getRequestURL());
filterChain.doFilter(servletRequest,servletResponse);
}
}
过滤器2:获取请求方式
@Component
@Order(2)
public class MyFilter2 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
System.out.println("执行MyFilter2当前请求方式==" + request.getMethod());
filterChain.doFilter(servletRequest,servletResponse);
}
}
过滤器3:获取请求请求URI
@Component
@Order(3)
public class MyFilter3 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
System.out.println("执行MyFilter3当前请求URI==" + request.getRequestURI());
filterChain.doFilter(servletRequest,servletResponse);
}
}
运行结果如图:
在以上每个过滤器上都有@Order() 这个注解,而且我们默认给的值从第一个过滤器到第三个过滤器依次递增,结果自然也是依次执行所有过滤器。
修改过滤器上的@Order()值,从MyFilter3-MyFilter1执行如图:
可以看到MyFilter3是第一个执行,MyFilter1是最后一个执行了!
通过以上例子我们可以知道可以通过@Order()这个注解的属性值大小来定义过滤器的执行顺序。以上版本我们是每个过滤器都去实现Filter接口重写其方法,然后通过@Order()值的大小来给这些过滤器排序。
基于Filter实现过滤器链版本2
设计思路:过滤器链上的过滤器大可不必每个都实现Filter接口,我们可以把所有的过滤器保持到一个集合里面,由一个过滤器去调用执行集合里面的过滤器即可。
添加MyFilter接口:
/**
* 不必实现Filter接口
*/
public interface MyFilter {
// 由子类从写方法
Boolean doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;
}
MyFilter1: 去掉@Component 和@Order注解,通过返回 true 或者false 控制拦截或者 放行
public class MyFilter1 implements MyFilter {
@Override
public Boolean doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
System.out.println("执行MyFilter1当前请求地址==" + request.getRequestURL());
// 通过返回 true 或者false 控制拦截或者 放行
return true;
}
}
MyFilter2:
public class MyFilter2 implements MyFilter {
@Override
public Boolean doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
System.out.println("执行MyFilter2当前请求方式==" + request.getMethod());
return true;
}
}
MyFilter3:
public class MyFilter3 implements MyFilter {
@Override
public Boolean doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
System.out.println("执行MyFilter3当前请求URI==" + request.getRequestURI());
return true;
}
}
定义一个过滤器控制类MyFilterContainer实现Filter,用来执行过滤器,这里是关键点:
@Component
public class MyFilterContainer implements Filter {
//存储过滤器
public List<MyFilter> filterList=new ArrayList<>();
// 当前执行的过滤器
private Integer current=0;
// 项目启动时扫描时会执行addFilter()方法,会把所有过滤器存入到 集合中
@Bean
public void addFilter(){
filterList.add(new MyFilter1());
filterList.add(new MyFilter2());
filterList.add(new MyFilter3());
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//保证每次请求都从第一个拦截器开始
this.current=0;
//获取下一个过滤器并执行
Boolean isDoNext= doMyFilter(servletRequest, servletResponse, filterChain);
if(!isDoNext){
// 返回结果为false 则拦截当前请求
return;
}
// 放行
filterChain.doFilter(servletRequest,servletResponse);
}
// 获取下一个过滤器并执行
private Boolean doMyFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//根据当前索引获取执行的过滤器对象
MyFilter myFilter = filterList.get(this.current);
Boolean aBoolean = myFilter.doFilter(servletRequest, servletResponse, filterChain);
if(aBoolean && this.current<this.filterList.size()-1){
this.current=this.current+1;
//递归调用下一个过滤器对象
return doMyFilter(servletRequest, servletResponse, filterChain);
} else if(aBoolean && this.current==this.filterList.size()-1){
return true;
}else {
return false;
}
}
}
启动项目测试结果如下图:
过滤器执行的顺序是由该过滤器处于集合的顺序而定,切换为以下顺序
@Bean
public void addFilter(){
filterList.add(new MyFilter3());
filterList.add(new MyFilter1());
filterList.add(new MyFilter2());
}
运行结果如图:
拦截规则配置测试
现在有个接口:
@RestController
public class FilterController {
@GetMapping("test")
public String test(){
return "hello filter";
}
}
当请求为/test的 的时候放行,否则拦截。只需要简单需改 MyFilter3即可 如下:
public class MyFilter3 implements MyFilter {
@Override
public Boolean doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
System.out.println("执行MyFilter3当前请求URI==" + request.getRequestURI());
//当请求为/test的 的时候放行,否则拦截
if(!request.getRequestURI().equals("/test")){
System.out.println("MyFilter3拦截请求,当前请求URI==" + request.getRequestURI());
return false;
}
return true;
}
}
运行测试:
从上图中可以看出测试结果和我们所需要的是一致的,至于返回拦截信息那也是很容易扩展的了,这里不再演示。至此本篇内容完结啦!!!
最后
本篇文章从责任链设计模式讲起,相信通过本篇学习大家也应该掌握了责任链模式、过滤器等知识。