前言
想根据过滤器 filter
来实现 sdk
的一些功能, 但是配置多个过滤器又给调用方带来了配置的复杂性。所以这里模仿 SpringSecurity
中的 DelegatingFilterProxy
和 FilterChainProxy
来实现了一个自定义的 FilterChain
。源码参照 spring-boot-starter-security
中的源码, 相关代码位于 spring-security-web
包中
实现
1. 首先我们随意定义2个过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package com.example.filterchain.filter;
import javax.servlet.*; import java.io.IOException;
public class AnonymousFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("AnonymousFilter init..."); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("AnonymousFilter doFilter..."); chain.doFilter(request, response); }
@Override public void destroy() { System.out.println("AnonymousFilter destroy..."); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package com.example.filterchain.filter;
import javax.servlet.*; import java.io.IOException;
public class FormAuthenticationFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("FormAuthenticationFilter init..."); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("FormAuthenticationFilter doFilter..."); chain.doFilter(request, response); }
@Override public void destroy() { System.out.println("FormAuthenticationFilter destroy..."); } }
|
2. 用枚举将过自定义滤器管理起来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import org.springframework.objenesis.instantiator.util.ClassUtils;
import javax.servlet.Filter;
public enum DefaultFilter {
anon(AnonymousFilter.class), authc(FormAuthenticationFilter.class);
private final Class<? extends Filter> filterClass;
private DefaultFilter(Class<? extends Filter> filterClass) { this.filterClass = filterClass; }
public Filter newInstance() { return (Filter) ClassUtils.newInstance(this.filterClass); } }
|
3. 代理过滤器
代理过滤器也是 servlet
标准过滤器, 需要能够注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| package com.example.filterchain.filter;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.ArrayList; import java.util.List;
@Slf4j public class FilterChainProxy implements Filter {
private List<Filter> filters;
@Override public void init(FilterConfig filterConfig) throws ServletException { this.filters = new ArrayList<>(); for (DefaultFilter defaultFilter : DefaultFilter.values()) { this.filters.add(defaultFilter.newInstance()); } }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; log.info("FilterChainProxy.doFilter.uri:{}", httpServletRequest.getRequestURI()); doFilterInternal(request, response, chain); }
private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { List<Filter> filters = getFilters();
if (filters == null || filters.size() == 0) { chain.doFilter(request, response); return; }
VirtualFilterChain vfc = new VirtualFilterChain(request, chain, filters); vfc.doFilter(request, response); }
public List<Filter> getFilters() { return filters; }
public void setFilters(List<Filter> filters) { this.filters = filters; }
private class VirtualFilterChain implements FilterChain{
private final FilterChain originalChain; private final List<Filter> additionalFilters; private final int size; private int currentPosition = 0;
public VirtualFilterChain(ServletRequest request, FilterChain chain, List<Filter> additionalFilters) { this.originalChain = chain; this.additionalFilters = additionalFilters; this.size = additionalFilters.size(); }
@Override public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if (currentPosition == size) { originalChain.doFilter(request, response); } else { currentPosition++; Filter nextFilter = additionalFilters.get(currentPosition - 1); nextFilter.doFilter(request, response, this); } } } }
|
4. 注册过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package com.example.filterchain.config;
import com.example.filterchain.filter.FilterChainProxy; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered;
@Configuration public class FilterConfig {
@Bean public FilterRegistrationBean filterChainProxy() { FilterRegistrationBean<FilterChainProxy> filterRegistrationBean = new FilterRegistrationBean<>(); filterRegistrationBean.setFilter(new FilterChainProxy()); filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE + 100); filterRegistrationBean.setName("filterChainProxy"); filterRegistrationBean.addUrlPatterns("/*"); filterRegistrationBean.setEnabled(true); return filterRegistrationBean; } }
|
执行结果
1 2 3
| 2021-03-28 14:55:40.405 INFO 11175 --- [nio-8080-exec-1] c.e.filterchain.filter.FilterChainProxy : FilterChainProxy.doFilter.uri:/actuator/prometheus AnonymousFilter doFilter... FormAuthenticationFilter doFilter...
|
我们可以看到首先执行了我们的标准代理过滤器 FilterChainProxy
, 然后执行自定义的过滤器链
最后
本文到此结束,感谢阅读。如果您觉得不错,请关注公众号【当我遇上你】,您的支持是我写作的最大动力。
参考