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

前言

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

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

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

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

  5. 前三个小节主要介绍了 Tomcat 的 Filter 设计、SpringMVC 的 Interceptor 设计、 Spring 中 AOP 的设计,本小节主要讲 Mybatis 的 Plugin 设计。

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

Mybatis 之 Plugin

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {

    /**
     * Returns the java type.
     *
     * @return the java type
     */
    Class<?> type();

    /**
     * Returns the method name.
     *
     * @return the method name
     */
    String method();

    /**
     * Returns java types for method argument.
     *
     * @return java types for method argument
     */
    Class<?>[] args();

}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {
    /**
     * Returns method signatures to intercept.
     *
     * @return method signatures
     */
    Signature[] value();
}
public interface Interceptor {

    Object intercept(Invocation invocation) throws Throwable;

    default Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
}
public class Invocation {

    private final Object target;
    private final Method method;
    private final Object[] args;

    public Invocation(Object target, Method method, Object[] args) {
        this.target = target;
        this.method = method;
        this.args = args;
    }

    public Object getTarget() {
        return target;
    }

    public Method getMethod() {
        return method;
    }

    public Object[] getArgs() {
        return args;
    }

    public Object proceed() throws InvocationTargetException, IllegalAccessException {
        return method.invoke(target, args);
    }
}
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;
    }

    /**
     * 包装代理
     *
     * @param interceptor 拦截器
     */
    public static Object wrap(Object t, Interceptor interceptor) {
        Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
        return Proxy.newProxyInstance(
                t.getClass().getClassLoader(),
                t.getClass().getInterfaces(),
                new Plugin(t, interceptor, signatureMap));
    }

    @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 new RuntimeException(e.getMessage());
        }
    }

    private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
        Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
        // 检查类是否被@Intercepts标记
        if (interceptsAnnotation == null) {
            throw new RuntimeException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
        }
        Signature[] sings = interceptsAnnotation.value();
        Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
        // 检查被@Signature标记的方法是否存在
        for (Signature sig : sings) {
            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 RuntimeException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
            }
        }
        return signatureMap;
    }
}
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;
    }

    /**
     * 添加拦截器
     *
     * @param interceptor 拦截器
     */
    public void addInterceptor(Interceptor interceptor) {
        interceptors.add(interceptor);
    }


    /**
     * 获取所有拦截器
     *
     * @return 拦截器集合
     */
    public List<Interceptor> getInterceptors() {
        return Collections.unmodifiableList(interceptors);
    }
}

测试

public interface Download {

    String download(String request);
}
public class SimpleDownload implements Download{
    @Override
    public String download(String request) {
        System.out.println("执行了下载");
        return "dddddddddddddddddddddddddd";
    }
}
public interface Parser {

    Map<String, String> parse(String response);
}
public class SimpleParser implements Parser{
    @Override
    public Map<String, String> parse(String response) {
        System.out.println("执行解析");
        Map<String, String> map = new HashMap<>();
        map.put("key", response);
        map.put("value", response);
        return map;
    }
}

拦截器

@Intercepts({@Signature(type = Download.class,method = "download",args = {String.class})})
public class DownloadPlugin implements Interceptor {

    /**
     * 这个方法会直接覆盖原有方法
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("DownloadPlugin............Before");
        final Object proceed = invocation.proceed();//调用原方法
        System.out.println("DownloadPlugin............After");
        return proceed;
    }
}
@Intercepts({
        @Signature(type = Download.class, method = "download", args = {String.class}),
        @Signature(type = Parser.class, method = "parse", args = {String.class})
})
public class GlobalPlugin implements Interceptor {

    /**
     * 这个方法会直接覆盖原有方法
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("GlobalPlugin............Before");
        final Object proceed = invocation.proceed();//调用原方法
        System.out.println("GlobalPlugin............After");
        return proceed;
    }
}
@Intercepts({@Signature(type = Parser.class,method = "parse",args = {String.class})})
public class ParserPlugin implements Interceptor {

    /**
     * 这个方法会直接覆盖原有方法
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("ParserPlugin............Before");
        final Object proceed = invocation.proceed();//调用原方法
        System.out.println("ParserPlugin............After");
        return proceed;
    }
}

测试主类

public class PluginTest {
    public static void main(String[] args) {
        InterceptorChain interceptorChain = new InterceptorChain();

        interceptorChain.addInterceptor(new DownloadPlugin());
        interceptorChain.addInterceptor(new ParserPlugin());
        interceptorChain.addInterceptor(new GlobalPlugin());

        Download downloadProxy = (Download) interceptorChain.pluginAll(new SimpleDownload());
        Parser parserProxy = (Parser) interceptorChain.pluginAll(new SimpleParser());

        String response = downloadProxy.download("aaaaaa");
        Map<String, String> parse = parserProxy.parse(response);

        System.out.println(parse.toString());
    }
}

输出结果:

GlobalPlugin............Before
DownloadPlugin............Before
执行了下载
DownloadPlugin............After
GlobalPlugin............After
GlobalPlugin............Before
ParserPlugin............Before
执行解析
ParserPlugin............After
GlobalPlugin............After
{value=dddddddddddddddddddddddddd, key=dddddddddddddddddddddddddd}

欢迎把你的测试结果打在评论区

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值