【MyBatis源码分析】使用 Java 动态代理,实现一个简单的插件机制

文章目录

设计分析

使用 动态代理 实现类似 MyBatis 插件机制的功能,能更灵活地拦截和增强方法调用。这种方式允许你不直接修改原有类的代码,而是通过代理类在方法调用前后加入自定义逻辑。下面给出一个简单的示例,从0到1实现类似 MyBatis 插件机制的例子,重点在于使用 Java 动态代理。

设计思路

【1】插件接口:插件的核心是一个接口,用于定义插件的方法和属性配置。

【2】目标对象:这是你要增强的对象,插件通过代理目标对象来实现拦截。

【3】动态代理:使用 Java 的动态代理机制拦截目标方法的调用,动态地插入额外的逻辑。

【4】插件管理:管理插件的注册和配置,使插件能够在目标方法执行时执行。

代码开发

首先定义一个插件接口,插件实现该接口以提供增强逻辑。

java 复制代码
import java.util.Properties;

/*******************************************************
 * Created by ZhangYu on 2024/12/21
 * Description : 插件接口
 * History   :
 *******************************************************/
public interface IPlugin {

    void before();   // 插件在目标方法执行前执行

    void after();    // 插件在目标方法执行后执行

    void setProperties(Properties properties);  // 配置插件属性
}

目标对象通常是一些具体的业务类,在MyBatis中代理的对象是ParameterHandler/ResultSetHandler、StatementHandler或者Executor,通过插件来增强其功能

java 复制代码
/*******************************************************
 * Created by ZhangYu on 2024/12/21
 * Description :  业务接口类
 * History   :
 *******************************************************/
public interface BizService {

    void doSomething(String param);
}

业务实现类:

java 复制代码
/*******************************************************
 * Created by ZhangYu on 2024/12/21
 * Description :
 * History   :
 *******************************************************/
public class MyService implements BizService {
    @Override
    public void doSomething(String param) {
        System.out.println("Executing doSomething : " + param);
    }
}

我们将使用 Java 的 动态代理 来实现插件机制。在执行目标方法时,插件会在目标方法执行前和执行后插入增强逻辑。

java 复制代码
/*******************************************************
 * Created by ZhangYu on 2024/12/21
 * Description : 插件管理器
 * History   :
 *******************************************************/
public class PluginManager {

    /**
     * 插件列表
     */
    private List<IPlugin> plugins = new ArrayList<>();

    /**
     * 注册插件
     */
    public void registerPlugin(IPlugin plugin) {
        plugins.add(plugin);
    }

    /**
     * 配置插件
     */
    public void configurePlugin(IPlugin plugin, Properties properties) {
        plugin.setProperties(properties);
    }

    /**
     * 创建代理对象
     */
    public Object createProxy(Object target){
        // 创建代理对象
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 执行所有插件的before操作
                for (IPlugin plugin : plugins) {
                    plugin.before();
                }
                // 调用目标方法
                Object result = method.invoke(target, args);

                // 执行所有插件的after方法
                for (IPlugin plugin : plugins) {
                    plugin.after();
                }
                return result;
            }
        };
        // 创建并返回代理对象
        return Proxy.newProxyInstance(target.getClass().getClassLoader()
                ,target.getClass().getInterfaces(),invocationHandler);
    }


}

InvocationHandler 接口定义了代理对象的方法调用逻辑,invoke 方法会在目标方法执行前后插入插件逻辑。

在 invoke 方法中,在执行目标方法前调用所有插件的 before 方法,在执行后调用 after 方法。

通过 Proxy.newProxyInstance 创建一个代理对象,将目标对象和插件关联。

插件实现类,实现具体的插件类,定义插件的 before 和 after 行为。

java 复制代码
import java.util.Properties;

/*******************************************************
 * Created by ZhangYu on 2024/12/21
 * Description : 日志插件
 * History   :
 *******************************************************/
public class LogPlugin implements IPlugin {

    private String logPrefix;

    @Override
    public void before() {
        System.out.println(logPrefix + " Before method execution...");
    }

    @Override
    public void after() {
        System.out.println(logPrefix + " After method execution...");
    }

    @Override
    public void setProperties(Properties properties) {
        this.logPrefix = properties.getProperty("logPrefix", "LOG:");
    }
}
java 复制代码
import java.util.Properties;

/*******************************************************
 * Created by ZhangYu on 2024/12/21
 * Description :  性能监控插件
 * History   :
 *******************************************************/
public class PerformancePlugin  implements IPlugin {
    private long threshold;

    @Override
    public void before() {
        System.out.println("PerformancePlugin: Monitoring start...");
    }

    @Override
    public void after() {
        System.out.println("PerformancePlugin: Monitoring end...");
    }

    @Override
    public void setProperties(Properties properties) {
        this.threshold = Long.parseLong(properties.getProperty("threshold", "100"));
    }
}

流程测试

java 复制代码
import com.zy.client.plugin.impl.LogPlugin;
import com.zy.client.plugin.impl.MyService;
import com.zy.client.plugin.impl.PerformancePlugin;

import java.util.Properties;

/*******************************************************
 * Created by ZhangYu on 2024/12/21
 * Description : 测试类
 * History   :
 *******************************************************/
public class Main {

    public static void main(String[] args) {
        // 创建插件管理器
        PluginManager pluginManager = new PluginManager();

        // 创建并配置插件
        IPlugin logPlugin = new LogPlugin();
        Properties logProperties = new Properties();
        logProperties.setProperty("logPrefix", "INFO:");
        pluginManager.configurePlugin(logPlugin, logProperties);

        IPlugin performancePlugin = new PerformancePlugin();
        Properties performanceProperties = new Properties();
        performanceProperties.setProperty("threshold", "150");
        pluginManager.configurePlugin(performancePlugin, performanceProperties);
        // 注册插件
        pluginManager.registerPlugin(logPlugin);
        pluginManager.registerPlugin(performancePlugin);

        // 创建目标对象
        BizService myService = new MyService();

        // 创建代理对象,扩展原有对象功能
        BizService proxyService = (BizService) pluginManager.createProxy(myService);

        // 调用代理对象的业务方法,插件会自动插入增强逻辑
        proxyService.doSomething("Test Param");
    }

}

组合目标对象和插件,通过 PluginManager 创建代理对象,并执行增强后的业务逻辑。

总结

插件类型分类:可以根据需要设计不同类型的插件,例如 前置插件、后置插件、异常插件 等,分别控制在不同阶段执行插件。

更多动态代理功能:可以在 InvocationHandler 中进一步控制插件的执行顺序,或者加入更多复杂的逻辑。

插件优先级:可以为插件添加优先级字段,决定插件执行的顺序,类似 MyBatis 中的插件顺序。

通过使用 Java 动态代理,我们可以实现一个灵活的插件机制,允许在运行时动态地拦截和增强目标对象的方法。这个机制非常适合用于类似 MyBatis 的插件系统,可以方便地在目标方法执行前后加入自定义逻辑,而无需修改目标对象的代码。通过这种方式,可以轻松扩展系统功能,增强代码的可维护性和灵活性。

完整代码

github

相关推荐
graceyun11 分钟前
C语言进阶习题【1】指针和数组(4)——指针笔试题3
android·java·c语言
hunter20620612 分钟前
用opencv生成视频流,然后用rtsp进行拉流显示
人工智能·python·opencv
我科绝伦(Huanhuan Zhou)15 分钟前
Linux 系统服务开机自启动指导手册
java·linux·服务器
旦沐已成舟1 小时前
K8S-Pod的环境变量,重启策略,数据持久化,资源限制
java·docker·kubernetes
S-X-S1 小时前
项目集成ELK
java·开发语言·elk
Ting-yu1 小时前
项目实战--网页五子棋(游戏大厅)(3)
java·java-ee·maven·intellij-idea
Johaden2 小时前
EXCEL+Python搞定数据处理(第一部分:Python入门-第2章:开发环境)
开发语言·vscode·python·conda·excel
小虎牙^O^3 小时前
2024春秋杯密码题第一、二天WP
python·密码学
梦魇梦狸º4 小时前
mac 配置 python 环境变量
chrome·python·macos
查理零世4 小时前
算法竞赛之差分进阶——等差数列差分 python
python·算法·差分