1.职责链路模式
1.1UML图
1.2 职责链路模式的概念
为了解耦的任务校验,将校验对象连成一个链,沿着这个链进行访问,直到有一个对象处理位置;
1.3 优点
1.按照一定的顺序执行判断;
2.避免校验对象之间耦合关系;
3.不用担心没有代码没有执行到;
2.职责链路模式在过滤器(Filter)中的使用
1.源码查看
1.ApplicationDispatcher
这段代码总共做了三件事:1.过滤器链创建;2.过滤链逐个过滤;3.释放过滤链资源;
private void invoke(ServletRequest request, ServletResponse response,
State state) throws IOException, ServletException {
//。。。。。。。。前面的代码省略
// Get the FilterChain Here
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet); //创建过滤器校验链条
// Call the service() method for the allocated servlet instance
try {
// for includes/forwards
if ((servlet != null) && (filterChain != null)) {
filterChain.doFilter(request, response); //进行过滤器校验
}
// Servlet Service Method is called by the FilterChain
} catch (ClientAbortException e) {
//。。。。。。。省略中间错误判断代码
}
// Release the filter chain (if any) for this request
try {
if (filterChain != null)
filterChain.release();//释放过滤器资源
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
wrapper.getLogger().error(sm.getString("standardWrapper.releaseFilters",
wrapper.getName()), e);
// FIXME: Exception handling needs to be similar to what is in the StandardWrapperValue
}
//。。。。。。。。。后面的代码省略
}
2.ApplicationFilterFactory(过滤链条创建过程)
从下面可以看出主要是一下操作:
1.初始化ApplicatFilterChain 过滤器校验链;
2.从上下文环境中,获取之前配置的过滤器数据;
3.将符合URL,serveletName的过滤器配置到ApplicationFilterChain中
public static ApplicationFilterChain createFilterChain(ServletRequest request,
Wrapper wrapper, Servlet servlet) {
// If there is no servlet to execute, return null
if (servlet == null)
return null;
// Create and initialize a filter chain object 初始化链式对象
ApplicationFilterChain filterChain = null;
if (request instanceof Request) {
Request req = (Request) request;
if (Globals.IS_SECURITY_ENABLED) {
// Security: Do not recycle
filterChain = new ApplicationFilterChain();
} else {
filterChain = (ApplicationFilterChain) req.getFilterChain();
if (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} else {
// Request dispatcher in use
filterChain = new ApplicationFilterChain();
}
filterChain.setServlet(servlet);
filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());
// Acquire the filter mappings for this Context 获取过滤器配置的上下文
StandardContext context = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps();
// If there are no filter mappings, we are done
if ((filterMaps == null) || (filterMaps.length == 0))
return filterChain;
// Acquire the information we will need to match filter mappings
DispatcherType dispatcher =
(DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);
String requestPath = null;
Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
if (attribute != null){
requestPath = attribute.toString();
}
String servletName = wrapper.getName();
// Add the relevant path-mapped filters to this filter chain 将符合需求的过滤器加入到过滤链中
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
if (!matchFiltersURL(filterMaps[i], requestPath))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
}
// Add filters that match on servlet name second
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
if (!matchFiltersServlet(filterMaps[i], servletName))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
}
// Return the completed filter chain
return filterChain;
}
3.ApplicationFilterChain(过滤链增加的具体过程)
这个方法比较简单:1.数组扩容;2.增加新的过滤器;
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];//过滤器存储的实体类
private int pos = 0;//当前过滤位置
private int n = 0;//存储的过滤器的总数
public static final int INCREMENT = 10;
void addFilter(ApplicationFilterConfig filterConfig) {
// Prevent the same filter being added multiple times
for(ApplicationFilterConfig filter:filters)
if(filter==filterConfig)
return;
if (n == filters.length) {
ApplicationFilterConfig[] newFilters =
new ApplicationFilterConfig[n + INCREMENT];
System.arraycopy(filters, 0, newFilters, 0, n);
filters = newFilters;
}
filters[n++] = filterConfig;
}
4.ApplicationFilterChain 的doFilter方法
处理过程:
1.获取pos位置的过滤器;
2.Filter执行,将当前过滤链对象,作为参数进行传递;
3.pos过滤器后移1位进行调用,直到pos大于总过滤器位置;
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
try {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<Void>() {
@Override
public Void run()
throws ServletException, IOException {
internalDoFilter(req,res);
return null;
}
}
);
} catch( PrivilegedActionException pe) {
Exception e = pe.getException();
if (e instanceof ServletException)
throw (ServletException) e;
else if (e instanceof IOException)
throw (IOException) e;
else if (e instanceof RuntimeException)
throw (RuntimeException) e;
else
throw new ServletException(e.getMessage(), e);
}
} else {
internalDoFilter(request,response);
}
}
//实际处理过滤任务的方法
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];//pos默认是从0开始的,调用后+1
try {
Filter filter = filterConfig.getFilter();
if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
} else {
filter.doFilter(request, response, this);//这里是最重要的一点,过滤器将过滤链对象作为一个参数向下传递,从而可以自动的进行链式校验
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}
//。。。。。。。。。。省略部分代码
}
2.UML图(上面的链式调用的图,如有错误还请指出)
3.手写一个通用校验链
业务需求:前端传来数据,动态SQL拼接,判断SQL各个部分是否数据有问题;
1.定义接口
/**
* 参数校验锁链管理
* @param
* @author lpf
*/
public interface CheckChain{
public abstract void doCheck(Param param) throws Exception;
}
2.对过滤参数进行约束
public interface Param<T extends Param> {
public abstract <T> T get();
}
3.定义过滤接口
@Service
public interface CheckFilter<T extends Param> {
/**
* 参数校验方法
* @param chain
* @return
*/
public abstract void checkParam(Param<T> param, CheckChain chain) throws Exception;
}
4.默认链式校验实现类
/**
* 默认链式检查
*/
public class DefaultCheckChain implements CheckChain {
/**
*
*/
private ParamCheckWapper[] wappers = new ParamCheckWapper[0];
private static final int INCREMENT = 10;
private int n = 0;
private int pos = 0;
//进行链式检查
@Override
public void doCheck(Param filed) throws Exception {
if(pos < n){
ParamCheckWapper wapper = wappers[pos++];
CheckFilter paramCheck = wapper.getParamCheck();
Assert.notNull(paramCheck,"链式类不能为空");
paramCheck.checkParam(filed,this);
}
}
/**
* 增加要进行过滤处理的类
* @param checkWapper
*/
public void addCheck(ParamCheckWapper checkWapper){
for(ParamCheckWapper wapper : wappers){
if(wapper == checkWapper){return;} ;
}
if(n == wappers.length){
ParamCheckWapper[] newWappers = new ParamCheckWapper[n + INCREMENT];
System.arraycopy(wappers, 0, newWappers, 0, n);
wappers = newWappers;
}
wappers[n++] = checkWapper;
}
}
5.过滤实现类(可以有多个)
/**
* select参数校验
* @author lpf
* @since 2019-11-08
*/
public class SelectParamCheck implements CheckFilter<CheckParam> {
/**
* 参数校验
* @param param
* @param chain
*/
@Override
public void checkParam(Param<CheckParam> param, CheckChain chain) throws Exception{
CheckParam checkParam = param.get();
List<SelectField> selects = checkParam.getSelect();
List<String> columns = checkParam.getColumnList();
//对select参数进行校验
selects.forEach(select -> {
String filed = select.getFiled().toLowerCase();
boolean flag = columns.contains(filed);
if(!flag) throw new RuntimeException(select.getFiled()+"不存在,请刷新页面重新选择查询字段!!!");
});
}
6.过滤类注册(可以通过yml配置反射生成,或者通过手动注册)
@Service
public class SearchConfigService {
/**默认检查链*/
private static DefaultCheckChain checkChain ;
/**过滤链路表配置*/
static{
checkChain = new DefaultCheckChain();
//参数检查器
ParamCheckWapper selectParamCheck = new ParamCheckWapper(new SelectParamCheck(),"SelectParamCheck");
ParamCheckWapper groupParamCheck = new ParamCheckWapper(new GroupbyParamCheck(), "groupParamCheck");
ParamCheckWapper conditionParamCheck = new ParamCheckWapper(new ConditionParamCheck(), "conditionParamCheck");
ParamCheckWapper orderbyParamCheck = new ParamCheckWapper(new OrderbyParamCheck(), "orderbyParamCheck");
//参数链表增加过滤类
checkChain.addCheck(selectParamCheck);
checkChain.addCheck(groupParamCheck);
checkChain.addCheck(conditionParamCheck);
checkChain.addCheck(orderbyParamCheck);
}
/**
* 参数校验
*/
public void doCheck(Param param) throws Exception {
checkChain.doCheck(param);
}
以上,就是职责链路模式的简单使用,可以通过泛型进行代码剥离,后续涉及到链式校验的时候就可以通过限制参数进行多样使用。降低代码的耦合度;
至此,职责链路设计模式的介绍就结束了;