责任链设计模式实战系列(三)

文章详细介绍了SpringAOP中基于MethodInvocation接口的拦截器设计,包括BaseMethodInvocation和IMethodInvocation的实现,以及如何通过MethodInterceptor接口创建和执行拦截器链。通过示例代码展示了如何使用这些拦截器在方法调用前后插入额外的处理逻辑。
摘要由CSDN通过智能技术生成

前言

  1. 这个系列主要讲优秀的开源框架对于责任链这个设计模式的运用,对于好的设计,我们关键是学习他的思想并运用在我们的编码中。

  2. 这个系列的所有代码都是我根据源码提炼之后的代码,不依赖原项目或框架,可以直接跑。

  3. 我不会讲每个具体是如何实现的,如果你觉得光看代码比较吃力,那么可以将代码复制下来,自己多运行几遍,我相信你一定能掌握,所以主打一个动手能力。

  4. 欢迎访问我的个人网站,里面有超多开源组件和项目,另外还有付费项目和博客,地址:https://openbytecode.com/

  5. 前两个小节主要介绍了 Tomcat 的 Filter 设计 和 SpringMVC 的 Interceptor 设计,本小节主要讲 Spring 中 AOP 的拦截器设计。

  6. 本系列 Github 地址:https://github.com/lijunping365/Open-Design

Spring 之 AOP 拦截器

public interface MethodInvocation {

    /**
     * Proceed to the next interceptor in the chain.
     * <p>The implementation and the semantics of this method depends
     * on the actual joinpoint type (see the children interfaces).
     * @return see the children interfaces' proceed definition
     * @throws Throwable if the joinpoint throws an exception
     */
    Object proceed() throws Throwable;

    /**
     * Get the method being called.
     * <p>This method is a friendly implementation of the
     * {@link Joinpoint#getStaticPart()} method (same result).
     * @return the method being called
     */
    Method getMethod();

    /**
     * Get the arguments as an array object.
     * It is possible to change element values within this
     * array to change the arguments.
     * @return the argument of the invocation
     */
    Object[] getArguments();

    /**
     * Return the object that holds the current joinpoint's static part.
     * <p>For instance, the target object for an invocation.
     * @return the object (can be null if the accessible object is static)
     */
    Object getThis();
}
public class BaseMethodInvocation implements MethodInvocation{

    protected Object[] arguments;

    protected final Object proxy;

    protected final Object target;

    protected final Method method;

    protected final Class<?> targetClass;

    protected final List<?> interceptors;

    /**
     * Index from 0 of the current interceptor we're invoking.
     * -1 until we invoke: then the current interceptor.
     */
    private int currentInterceptorIndex = -1;

    protected BaseMethodInvocation(Object proxy,
                                   Object target,
                                   Method method,
                                   Object[] arguments,
                                   Class<?> targetClass,
                                   List<?> interceptors) {
        this.proxy = proxy;
        this.target = target;
        this.method = BridgeMethodResolver.findBridgedMethod(method);
        this.arguments = adaptArgumentsIfNecessary(method, arguments);
        this.targetClass = targetClass;
        this.interceptors = interceptors;
    }

    @Override
    public Object proceed() throws Throwable {
        // We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptors.size() - 1) {
            return invoke();
        }
        Object interceptor = this.interceptors.get(++this.currentInterceptorIndex);
        return ((MethodInterceptor) interceptor).invoke(this);
    }

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

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

    @Override
    public Object getThis() {
        return this.target;
    }
    /**
     * Invoke the joinpoint using reflection.
     * Subclasses can override this to use custom invocation.
     * @return the return value of the joinpoint
     * @throws Throwable if invoking the joinpoint resulted in an exception
     */
    @Nullable
    protected Object invoke() throws Throwable {
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }

    /**
     * @since 4.2.3
     */
    static Object[] adaptArgumentsIfNecessary(Method method, @Nullable Object[] arguments) {
        //...
        return arguments;
    }
}
public class IMethodInvocation extends BaseMethodInvocation{

    private final MethodProxy methodProxy;

    public IMethodInvocation(Object proxy,
                             Object target,
                             Method method,
                             Object[] arguments,
                             Class<?> targetClass,
                             List<?> interceptors,
                             MethodProxy methodProxy) {

        super(proxy, target, method, arguments, targetClass, interceptors);

        // Only use method proxy for public methods not derived from java.lang.Object
        this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
                method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
                !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
                methodProxy : null);
    }

    @Override
    public Object proceed() throws Throwable {
        return super.proceed();
    }

    @Override
    protected Object invoke() throws Throwable {
        if (this.methodProxy != null) {
            return this.methodProxy.invoke(this.target, this.arguments);
        }
        else {
            return super.invoke();
        }
    }
}
@FunctionalInterface
public interface MethodInterceptor {

    /**
     * Implement this method to perform extra treatments before and
     * after the invocation. Polite implementations would certainly
     * like to invoke {@link Joinpoint#proceed()}.
     * @param invocation the method invocation joinpoint
     * @return the result of the call to {@link Joinpoint#proceed()};
     * might be intercepted by the interceptor
     * @throws Throwable if the interceptors or the target object
     * throws an exception
     */
    Object invoke(MethodInvocation invocation) throws Throwable;

}

测试

/**
 * 注意这里是实现我们自己的 MethodInterceptor
 *
 * @author lijunping on 2022/11/8
 */
public class FirstMethodInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("FirstMethodInterceptor .......Before");
        Object proceed = invocation.proceed();// 调用 IMethodInvocation 的 proceed 方法,形成递归调用
        System.out.println("FirstMethodInterceptor .......After");
        return proceed;
    }
}
/**
 * 注意这里是实现我们自己的 MethodInterceptor
 *
 * @author lijunping on 2022/11/8
 */
public class SecondMethodInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("SecondMethodInterceptor .......Before");
        Object proceed = invocation.proceed();// 调用 IMethodInvocation 的 proceed 方法,形成递归调用
        System.out.println("SecondMethodInterceptor .......After");
        return proceed;
    }
}
public class DemoService {

    public String test(){
        System.out.println("tttttttttttttttttttt");
        return "hello";
    }
}
/**
 * 注意这里的 MethodInterceptor 是 net.sf.cglib.proxy.MethodInterceptor
 *
 * @author lijunping on 2022/11/8
 */
public class DemoMethodInterceptor implements MethodInterceptor {

    private final Object target;
    private final List<?> chain;

    public DemoMethodInterceptor(Object target, List<Object> chain) {
        this.target = target;
        this.chain = chain;
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 构建调用链
        IMethodInvocation invocation = new IMethodInvocation(proxy, target, method, args, target.getClass(), chain, methodProxy);
        // 执行调用链
        return invocation.proceed();
    }
}
public class ProxyFactory {

    /**
     * 实例化动态代理对象
     * @param tClass 代理目标对象类型
     * @param <T> 代理目标对象类型泛型
     * @return 动态代理对象
     */
    public static <T> T getProxyInstance(Class<T> tClass, MethodInterceptor interceptor) {
        return getProxyInstance(tClass, tClass, interceptor);
    }

    /**
     * 实例化动态代理对象,并转换为对应接口类型
     * @param tClass 代理目标对象类型
     * @param interfaceClass 代理目标对象接口类型
     * @param <T> 代理目标对象接口类型泛型
     * @return 动态代理对象
     */
    public static <T> T getProxyInstance(Class<? extends T> tClass, Class<T> interfaceClass, MethodInterceptor interceptor) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(tClass);
        enhancer.setClassLoader(tClass.getClassLoader());
        enhancer.setCallback(interceptor); // 实现了 MethodInterceptor 接口的类
        return interfaceClass.cast(enhancer.create());
    }
}
public class ChainDemo {
    public static void main(String[] args) {
        // 创建目标对象
        DemoService demoService = new DemoService();
        // 构建拦截器链
        List<Object> chain = new ArrayList<>();
        chain.add(new FirstMethodInterceptor());
        chain.add(new SecondMethodInterceptor());
        // 创建 cglib 动态代理的 Interceptor
        DemoMethodInterceptor interceptor = new DemoMethodInterceptor(demoService, chain);
        // 获取代理对象
        DemoService proxyInstance = ProxyFactory.getProxyInstance(DemoService.class, interceptor);
        // 执行代理对象
        proxyInstance.test();
    }
}

输出结果:

FirstMethodInterceptor .......Before
SecondMethodInterceptor .......Before
tttttttttttttttttttt
SecondMethodInterceptor .......After
FirstMethodInterceptor .......After

欢迎在评论区留下你的总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值