zoukankan      html  css  js  c++  java
  • 责任链模式(Chain)

    前言:责任链模式在很多框架中都有体现,比如Spring,Mybatis等。

    概念:使多个对象都有处理请求的机会,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象串成一条链,并沿着这条链一直传递该请求,直到有对象处理它为止。责任链模式的重点在“链上”,由一条链去处理相似的请求,在链中决定谁来处理这个请求,并返回相应的结果。

    一:代码模拟生活场景

           在公司上班,遇到突发事件都需要请假,而请假根据天数不同需要不同的主管来同意我们的请求,比如我们要请1-3天的假期一级主管就可以直接同意,不需要再往上请求,如果是4-6天就需要二级主管同意,如果是7-10天就需要3级主管同意,大于10天需要我们的boss来同意才行。现在我们用责任链模式来模拟这个场景。

    //处理者基类
    public abstract class LeaveHandler {
    
        //持有指向后继者的引用
        protected LeaveHandler successor;
    
        //设置后继者
        public void setSuccessor(LeaveHandler successor) {
            this.successor = successor;
        }
    
        public abstract void handleRequest(int request);
    }
    
    //一级主管
    public class FirstLevelSupervisor extends LeaveHandler {
        @Override
        public void handleRequest(int request) {
            if (request<=3){
                System.out.println("一级主管已同意");
            }else {
                if (successor!=null){
                    //请请求传递给责任链的下一个处理对象处理
                    successor.handleRequest(request);
                }
            }
        }
    }
    
    //二级主管
    public class SecondLevelSupervisor extends LeaveHandler{
        @Override
        public void handleRequest(int request) {
            if (4<=request&&request<=6){
                System.out.println("二级主管已同意");
            }else {
                if (successor!=null){
                    //请请求传递给责任链的下一个处理对象处理
                    successor.handleRequest(request);
                }
            }
        }
    }
    
    //三级主管
    public class ThirdLevelSupervisor extends LeaveHandler {
        @Override
        public void handleRequest(int request) {
            if (7<=request&&request<=10){
                System.out.println("三级主管已同意");
            }else {
                if (successor!=null){
                    //请请求传递给责任链的下一个处理对象处理
                    successor.handleRequest(request);
                }
            }
        }
    }
    
    //Boss
    public class Boss extends LeaveHandler {
        @Override
        public void handleRequest(int request) {
            System.out.println("Boss已同意");
        }
    }
    
       //测试
        public static void main(String[] args) {
            LeaveHandler firstLevelSupervisor=new FirstLevelSupervisor();
            LeaveHandler secondLevelSupervisor=new SecondLevelSupervisor();
            LeaveHandler thirdLevelSupervisor=new ThirdLevelSupervisor();
            LeaveHandler boss=new Boss();
            //形成责任链
            firstLevelSupervisor.setSuccessor(secondLevelSupervisor);
            secondLevelSupervisor.setSuccessor(thirdLevelSupervisor);
            thirdLevelSupervisor.setSuccessor(boss);
    
            //向一级主管提交7天的假期申请
            firstLevelSupervisor.handleRequest(7);
        }

    二:优缺点  

           优点

              1.请求的发送者和处理解耦。

              2.可以根据不同的需求进行动态的组合。

              3.增强了给对象指派职责的灵活性,可以很方便的修改、增加、减少责任链中的元素。

           缺点
               影响性能。当责任链太长,如果只有最后一个可以处理,就会创建许多处理对象并且请求会在它们之间传递。

    下面我们来看责任链模式在Spring和Mybatis源码中的体现

    三:Spring源码中的责任链模式

             Spring中对象大多都是代理对象,如果实现了接口,都是通过JDK动态代理生成的,代理类JdkDynamicAopProxy(代理模式),而当调用方法时会调用类的invoke方法

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            MethodInvocation invocation;
            Object oldProxy = null;
            boolean setProxyContext = false;
    
            TargetSource targetSource = this.advised.targetSource;
            Object target = null;
    
            try {
                //eqauls()方法,目标对象未实现此方法
                if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                    return equals(args[0]);
                }
                //hashCode()方法,目标对象未实现此方法
                else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                    return hashCode();
                }
                else if (method.getDeclaringClass() == DecoratingProxy.class) {
                    return AopProxyUtils.ultimateTargetClass(this.advised);
                }
                //Advised接口或者其父接口中定义的方法,直接反射调用,不应用通知
                else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                        method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                    return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
                }
    
                Object retVal;
    
                if (this.advised.exposeProxy) {
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }
                 //获得目标对象的类
                target = targetSource.getTarget();
                Class<?> targetClass = (target != null ? target.getClass() : null);
                 //获取可以应用到此方法上的Interceptor列表
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                 //如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)
                if (chain.isEmpty()) {
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                }
                else {//创建MethodInvocation
                    invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                    //开始责任链调用
                    retVal = invocation.proceed();
                }
    
                Class<?> returnType = method.getReturnType();
                if (retVal != null && retVal == target &&
                        returnType != Object.class && returnType.isInstance(proxy) &&
                        !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                    retVal = proxy;
                }
                else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                    throw new AopInvocationException(
                            "Null return value from advice does not match primitive return type for: " + method);
                }
                return retVal;
            }
            finally {
                if (target != null && !targetSource.isStatic()) {
                    targetSource.releaseTarget(target);
                }
                if (setProxyContext) {
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }
          invocation.proceed()方法:责任链调用
    //ReflectiveMethodInvocation类
    public Object proceed() throws Throwable {//如果Interceptor执行完了,则执行joinPoint
            if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                return invokeJoinpoint();
            }
            Object interceptorOrInterceptionAdvice =
                    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            //如果要动态匹配joinPoint
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                InterceptorAndDynamicMethodMatcher dm =
                        (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
                //动态匹配:运行时参数是否满足匹配条件
                if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
    //
    interceptor相当于就是一个切面,可能是前置,后置等切面,以前置切面举例
    //public Object invoke(MethodInvocation mi) throws Throwable {
    //this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
    //return mi.proceed();}重新走proceed方法,开始层层调用
                   return dm.interceptor.invoke(this); } else {//动态匹配失败时,略过当前Intercetpor,调用下一个Interceptor
    //类似递归调用 return proceed(); } } else {//执行当前Intercetpor return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }

    四:Mybatis源码中的责任链模式

               Mybatis中可以添加插件,比如PageHelper,多个插件对对象的包装采用的动态代理,而且是层层代理。

    //插件责任链
    public class InterceptorChain {
    
      private final List<Interceptor> interceptors = new ArrayList<>();
    //生成代理对象
    public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target; }
    //添加拦截器也就是插件,可以添加很多个,利用层层代理生成的对象,方法调用的时候就是责任链模式,层层处理
    public void addInterceptor(Interceptor interceptor) { interceptors.add(interceptor); } public List<Interceptor> getInterceptors() { return Collections.unmodifiableList(interceptors); } }

    什么时候调用pluginAll方法:四种插件类型:ParameterHandler(参数处理器)  ResultSetHandler(结果集处理器)  StatementHandler(语句集处理器)  Executor(执行器)

    分页插件PageHelper的PageInterceptor源码

    @Intercepts(
        {
            @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
            @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        }
    )
    public class PageInterceptor implements Interceptor {
        //缓存count查询的ms
        protected Cache<CacheKey, MappedStatement> msCountMap = null;
        private Dialect dialect;
        private String default_dialect_class = "com.github.pagehelper.PageHelper";
        private Field additionalParametersField;
    
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            try {
                Object[] args = invocation.getArgs();
                MappedStatement ms = (MappedStatement) args[0];
                Object parameter = args[1];
                RowBounds rowBounds = (RowBounds) args[2];
                ResultHandler resultHandler = (ResultHandler) args[3];
                Executor executor = (Executor) invocation.getTarget();
                CacheKey cacheKey;
                BoundSql boundSql;
                //由于逻辑关系,只会进入一次
                if(args.length == 4){
                    //4 个参数时
                    boundSql = ms.getBoundSql(parameter);
                    cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
                } else {
                    //6 个参数时
                    cacheKey = (CacheKey) args[4];
                    boundSql = (BoundSql) args[5];
                }
                List resultList;
                //调用方法判断是否需要进行分页,如果不需要,直接返回结果
                if (!dialect.skip(ms, parameter, rowBounds)) {
                    //反射获取动态参数
                    Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql);
                    //判断是否需要进行 count 查询
                    if (dialect.beforeCount(ms, parameter, rowBounds)) {
                        //创建 count 查询的缓存 key
                        CacheKey countKey = executor.createCacheKey(ms, parameter, RowBounds.DEFAULT, boundSql);
                        countKey.update("_Count");
                        MappedStatement countMs = msCountMap.get(countKey);
                        if (countMs == null) {
                            //根据当前的 ms 创建一个返回值为 Long 类型的 ms
                            countMs = MSUtils.newCountMappedStatement(ms);
                            msCountMap.put(countKey, countMs);
                        }
                        //调用方言获取 count sql
                        String countSql = dialect.getCountSql(ms, boundSql, parameter, rowBounds, countKey);
                        BoundSql countBoundSql = new BoundSql(ms.getConfiguration(), countSql, boundSql.getParameterMappings(), parameter);
                        //当使用动态 SQL 时,可能会产生临时的参数,这些参数需要手动设置到新的 BoundSql 中
                        for (String key : additionalParameters.keySet()) {
                            countBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
                        }
                        //执行 count 查询
                        Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql);
                        Long count = (Long) ((List) countResultList).get(0);
                        //处理查询总数
                        //返回 true 时继续分页查询,false 时直接返回
                        if (!dialect.afterCount(count, parameter, rowBounds)) {
                            //当查询总数为 0 时,直接返回空的结果
                            return dialect.afterPage(new ArrayList(), parameter, rowBounds);
                        }
                    }
                    //判断是否需要进行分页查询
                    if (dialect.beforePage(ms, parameter, rowBounds)) {
                        //生成分页的缓存 key
                        CacheKey pageKey = cacheKey;
                        //处理参数对象
                        parameter = dialect.processParameterObject(ms, parameter, boundSql, pageKey);
                        //调用方言获取分页 sql
                        String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, pageKey);
                        BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(), pageSql, boundSql.getParameterMappings(), parameter);
                        //设置动态参数
                        for (String key : additionalParameters.keySet()) {
                            pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
                        }
                        //执行分页查询
                        resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql);
                    } else {
                        //不执行分页的情况下,也不执行内存分页
                        resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql);
                    }
                } else {
                    //rowBounds用参数值,不使用分页插件处理时,仍然支持默认的内存分页
                    resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
                }
                return dialect.afterPage(resultList, parameter, rowBounds);
            } finally {
                dialect.afterAll();
            }
        }
    
    //为了生成代理对象 @Override
    public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { //缓存 count ms msCountMap = CacheFactory.createCache(properties.getProperty("msCountCache"), "ms", properties); String dialectClass = properties.getProperty("dialect"); if (StringUtil.isEmpty(dialectClass)) { dialectClass = default_dialect_class; } try { Class<?> aClass = Class.forName(dialectClass); dialect = (Dialect) aClass.newInstance(); } catch (Exception e) { throw new PageException(e); } dialect.setProperties(properties); try { //反射获取 BoundSql 中的 additionalParameters 属性 additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters"); additionalParametersField.setAccessible(true); } catch (NoSuchFieldException e) { throw new PageException(e); } } }
    Plugin类源码
    //Plugin类源码
    public class Plugin implements InvocationHandler {
    
      private final Object target;
      private final Interceptor interceptor;
      private final Map<Class<?>, Set<Method>> signatureMap;
    
      private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
        this.target = target;
        this.interceptor = interceptor;
        this.signatureMap = signatureMap;
      }
    
      //生成代理对象,这里有点特别是层层代理,代理对象又生成代理对象
      public static Object wrap(Object target, Interceptor interceptor) {
        Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
        Class<?> type = target.getClass();
        Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
        if (interfaces.length > 0) {
          return Proxy.newProxyInstance(
              type.getClassLoader(),
              interfaces,
              new Plugin(target, interceptor, signatureMap));
        }
        return target;
      }
    
      //代理对象真实调用方法
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
          Set<Method> methods = signatureMap.get(method.getDeclaringClass());
          if (methods != null && methods.contains(method)) {
    //插件调用
    return interceptor.intercept(new Invocation(target, method, args)); } return method.invoke(target, args); } catch (Exception e) { throw ExceptionUtil.unwrapThrowable(e); } } private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) { Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class); if (interceptsAnnotation == null) { throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName()); } Signature[] sigs = interceptsAnnotation.value(); Map<Class<?>, Set<Method>> signatureMap = new HashMap<>(); for (Signature sig : sigs) { Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>()); try { Method method = sig.type().getMethod(sig.method(), sig.args()); methods.add(method); } catch (NoSuchMethodException e) { throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e); } } return signatureMap; } private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) { Set<Class<?>> interfaces = new HashSet<>(); while (type != null) { for (Class<?> c : type.getInterfaces()) { if (signatureMap.containsKey(c)) { interfaces.add(c); } } type = type.getSuperclass(); } return interfaces.toArray(new Class<?>[interfaces.size()]); } }

              

     

  • 相关阅读:
    2020年秋招三星面试题
    物联网金融和互联网金融的区别与联系
    数据库事务的4种隔离级别
    Access-cookie之sqlmap注入
    SDL-软件安全开发周期流程
    图片马的制作
    ssrf内网端口爆破扫描
    逻辑漏洞_验证码绕过_密码找回漏洞
    平行越权与垂直越权
    xff注入
  • 原文地址:https://www.cnblogs.com/dyg0826/p/11329924.html
Copyright © 2011-2022 走看看