aop学习笔记之Aop责任链(四)

一 Aop责任链

如何理解责任链呢?当一个切面有多个织入时,这些需要织入的方法就形成了一个责任链,就像Filter链一样

二 原理

这里写图片描述
看了上图我们理解一下,责任链中包含每一个Handler,那每个Hanlder在执行之后,程序是怎么知道下次要执行哪个Handler呢?我们先做出假设,每个Handler中存储着NextHandler,这样程序就知道下次执行哪个了

三 责任链实现

3.1 BaseHandler

首先我们创建一个BaseHandler类

package com.example.proxy.chain;

/**
 * BaseHandler class
 *
 * @author TransientBa
 * @date 2018/3/10
 */
public abstract class BaseHandler {
    /**
     * 用来存储下一个Handler
     */
    private BaseHandler nextHandler;

    public BaseHandler getNextHandler() {
        return nextHandler;
    }

    public void setNextHandler(BaseHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    /** 如果nextHandler不为空  则执行下一个Handler**/
    public void execute(){
        handlerProcess();
        if( nextHandler != null){
            nextHandler.execute();
        }
    }

    /**
     * Handler
     * @return void
     */
    protected abstract void handlerProcess();
}

依据我们上面的假设,类中有一个nextHandler属性,我们假设他用来保存下一个Handler。
还有一个抽象方法handlerProcess(),此方法用来被继承后写执行过程。
最后在execute()中我们先执行本次Handler中的handlerProcess,然后判断NextHandler是否为空,如果不为空。则执行NextHandler也就是下一个Handler的方法。

3.2 Client测试

在这个类中我们首先创建三个Handler来继承上面的BaseHandler类,重写其中的handlerProcess方法
,然后在实例化三个雷,并将它们按照顺序赋值给各自的NextHandler,然后我们执行一下

package com.example.proxy.chain;

/**
 * Client class
 *
 * @author TransientBa
 * @date 2018/3/12
 */
public class Client {
    /**创建ABC三个Handler来继承BaseHandler**/
    static class HandlerA extends BaseHandler{
        @Override
        protected void handlerProcess() {
            System.out.println("handle by a");
        }
    }
    static class HandlerB extends BaseHandler{
        @Override
        protected void handlerProcess() {
            System.out.println("handle by b");
        }
    }
    static class HandlerC extends BaseHandler{
        @Override
        protected void handlerProcess() {
            System.out.println("handle by c");
        }
    }

    public static void main(String[] args) {
        BaseHandler handlerA = new HandlerA();
        BaseHandler handlerB = new HandlerB();
        BaseHandler handlerC = new HandlerC();
        /**
         * 将下个Handler赋值给当前Handler中的NextHandler属性
         * 有点像HashMap中的Node  每个Node存储着下一个Node
         */
        handlerA.setNextHandler(handlerB);
        handlerB.setNextHandler(handlerC);
        handlerA.execute();

    }


}

执行结果
这里写图片描述

3.3 优化

看到这里是不是已经发现了问题所在,这样虽然实现了整个链式的调用,但当我们实例化三个Handler后,需要手动的将每个Handler之前的关系表明,也就是赋值NextHandler,这样很麻烦,实现起来也不现实。那我们如何改进呢?

3.4 Chain

这里创建一个chain类,这个类用来做什么呢?我们将上面的BaseHandler类拆分为ChainBaseHandler类和Chain类两个类来实现链式调用

package com.example.proxy.chain;

import java.util.List;

/**
 * Chain class
 *
 * @author TransientBa
 * @date 2018/3/12
 */
public class Chain {
    private List<ChainBaseHandler> handlers;
    /**
     * 用来表示handlers的游标
     */
    private int index = -1;

    public  Chain(List<ChainBaseHandler> handlers){
        this.handlers = handlers;
    }

    /**
     * 通过index自增 调用excute实现递归  遍历整个handlers
     */
    public void proceed(){
        if(index == handlers.size() - 1){
            return;
        }
        handlers.get(++index).execute(this);
    }
}

可以看到,在chain中我们取消了NextHandler属性,而是改用了一个List,类型是ChainBaseHandler,
还多了一个index,初始值为-1,
然后是一个构造,在实例化时要传入一个List进来,并赋值给该类的handlers属性,
最后是proceed方法,在这个方法中我们首先判断了index是否超过List的size,如果超过了则返回,如果没操作,就得到当索引的Handler,然后执行ChainBaseHandler中的execute方法

3.5 ChainBaseHandler

在这个类中我们只有两个方法,execute和handlerProcess,其中handlerProcess依然用来被继承后写执行过程。
execute方法有一个参数Chain,这个方法首先进来会执行当前Handler的HandlerProcess执行过程,然后会调用传入Chain的proceed方法,这样调用就又回到了proceed中,继续判断index并开始下一次循环

package com.example.proxy.chain;

/**
 * ChainBaseHandler class
 *
 * @author TransientBa
 * @date 2018/3/12
 */
public abstract class ChainBaseHandler {
    /**同样先执行自己的动作 再调用chain的proceed去遍历下一个Handler**/
    public void execute(Chain chain){
        handlerProcess();
        chain.proceed();
    };
    protected abstract void handlerProcess();
}

3.6ChainClient测试

package com.example.proxy.chain;

import java.util.Arrays;
import java.util.List;

/**
 * ChainClient class
 *
 * @author TransientBa
 * @date 2018/3/12
 */
public class ChainClient {
    static class ChainHandlerA extends ChainBaseHandler{
        @Override
        protected void handlerProcess() {
            System.out.println("handler by chain a");
        }
    }

    static class ChainHandlerB extends ChainBaseHandler{
        @Override
        protected void handlerProcess() {
            System.out.println("handler by chain b");
        }
    }

    static class ChainHandlerC extends ChainBaseHandler{
        @Override
        protected void handlerProcess() {
            System.out.println("handler by chain c");
        }
    }

    public static void main(String[] args) {
        /**
         * 声明HandlerList关系链 通过数组顺序排序
         * 不再像之前那样手动给当前Handler中的NextHandler设置值
         * 同样每个chain中间没有相互的依赖 实现解耦
         */
        List<ChainBaseHandler> handlerList = Arrays.asList(
                new ChainHandlerA(),
                new ChainHandlerB(),
                new ChainHandlerC()
        );

        Chain chain = new Chain(handlerList);
        chain.proceed();

    }
}

在这个类中我们同样先创建三个类继承ChainBaseHandler,重写handlerProcess方法,
然后用Arrays.asList来初始一个handlerList,并传入Chain的构造,实例化出来一个Chain,调用proceed方法开始遍历,
执行一下:
这里写图片描述

四 ReflectiveMethodInvocation

上面我们用代码模拟了Aop的责任链,接下来我们看看源码中Aop责任链是如何实现的,该类位于org.springframework.aop.framework下

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.aop.framework;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.lang.Nullable;

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
    protected final Object proxy;
    @Nullable
    protected final Object target;
    protected final Method method;
    protected Object[] arguments = new Object[0];
    @Nullable
    private final Class<?> targetClass;
    @Nullable
    private Map<String, Object> userAttributes;
    protected final List<?> interceptorsAndDynamicMethodMatchers;
    private int currentInterceptorIndex = -1;

    protected ReflectiveMethodInvocation(Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments, @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
        this.proxy = proxy;
        this.target = target;
        this.targetClass = targetClass;
        this.method = BridgeMethodResolver.findBridgedMethod(method);
        this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }

    public final Object getProxy() {
        return this.proxy;
    }

    @Nullable
    public final Object getThis() {
        return this.target;
    }

    public final AccessibleObject getStaticPart() {
        return this.method;
    }

    public final Method getMethod() {
        return this.method;
    }

    public final Object[] getArguments() {
        return this.arguments;
    }

    public void setArguments(Object... arguments) {
        this.arguments = arguments;
    }

    @Nullable
    public Object proceed() throws Throwable {
        if(this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.invokeJoinpoint();
        } else {
            Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            if(interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)?dm.interceptor.invoke(this):this.proceed();
            } else {
                return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
            }
        }
    }

    @Nullable
    protected Object invokeJoinpoint() throws Throwable {
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }

    public MethodInvocation invocableClone() {
        Object[] cloneArguments = this.arguments;
        if(this.arguments.length > 0) {
            cloneArguments = new Object[this.arguments.length];
            System.arraycopy(this.arguments, 0, cloneArguments, 0, this.arguments.length);
        }

        return this.invocableClone(cloneArguments);
    }

    public MethodInvocation invocableClone(Object... arguments) {
        if(this.userAttributes == null) {
            this.userAttributes = new HashMap();
        }

        try {
            ReflectiveMethodInvocation clone = (ReflectiveMethodInvocation)this.clone();
            clone.arguments = arguments;
            return clone;
        } catch (CloneNotSupportedException var3) {
            throw new IllegalStateException("Should be able to clone object of type [" + this.getClass() + "]: " + var3);
        }
    }

    public void setUserAttribute(String key, @Nullable Object value) {
        if(value != null) {
            if(this.userAttributes == null) {
                this.userAttributes = new HashMap();
            }

            this.userAttributes.put(key, value);
        } else if(this.userAttributes != null) {
            this.userAttributes.remove(key);
        }

    }

    @Nullable
    public Object getUserAttribute(String key) {
        return this.userAttributes != null?this.userAttributes.get(key):null;
    }

    public Map<String, Object> getUserAttributes() {
        if(this.userAttributes == null) {
            this.userAttributes = new HashMap();
        }

        return this.userAttributes;
    }

    public String toString() {
        StringBuilder sb = new StringBuilder("ReflectiveMethodInvocation: ");
        sb.append(this.method).append("; ");
        if(this.target == null) {
            sb.append("target is null");
        } else {
            sb.append("target is of class [").append(this.target.getClass().getName()).append(']');
        }

        return sb.toString();
    }
}

可以看到该类首先同样定义了index

 private int currentInterceptorIndex = -1;

也定义了List<>和其他的一些参宿

protected final List<?> interceptorsAndDynamicMethodMatchers;

我们着重看下proceed()方法

 @Nullable
    public Object proceed() throws Throwable {
    //上面定义了从-1开始 此处判断index是否超过List该循环的长度
        if(this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.invokeJoinpoint();
        } else {
        //自增后拿到当前循环的interceptorOrInterceptionAdvice
            Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            //判断类型执行invoke或proceed
            if(interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)?dm.interceptor.invoke(this):this.proceed();
            } else {
                return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
            }
        }
    }

五 总结

责任链模式解决了请求和处理类耦合在一起的情况,用一系列的类形成一个链去处理,使得在链中的每个类都有机会去处理该请求,同样反过来说,对于链中每个类自己的动作都是高内聚的,即使拆分或剔除出去也不会影响其他的动作。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值