kettle与Springboot的集成方法,完整支持大数据组件
目录
-
- 概要
- 整体架构流程
- 技术名词解释
- 技术细节
- 小结
概要
在现代数据处理和ETL(提取、转换、加载)流程中,Kettle(Pentaho Data Integration, PDI)作为一种强大的开源ETL工具,被广泛应用于各种数据处理场景。然而,将Kettle集成到Spring Boot项目中时,开发者常常面临诸多挑战。目前网上常见的集成方法大多采用依赖的方式,直接在Spring Boot项目的pom.xml文件中引入Kettle的相关依赖。
然而,这种集成方式存在诸多问题。首先,Kettle底层采用了OSGI(Open Services Gateway Initiative)模块化组件加载方式,这使得一些大数据组件无法完整集成。其次,Kettle自身引用了大量第三方包,导致依赖冲突频繁出现,严重影响项目的稳定性和可维护性。
为了解决这些问题,我尝试了多种集成方法,并找到了一种相对完善的解决方案。该方案的核心思想是通过自定义的加载机制绕过Kettle的OSGI限制,同时对依赖进行精细化管理,避免不必要的冲突。
集成策略
这种集成方式是基于了解Springboot的类加载以及Kettle的类加载方式,找到的一种能够两者都兼容起来的加载方式。
Spring Boot的类加载机制基于JDK的类加载器层级结构,通过LaunchedURLClassLoader支持嵌套JAR文件的加载,并优化了类加载顺序,避免依赖冲突。而Kettle的OSGI机制则通过动态加载和隔离插件模块,实现灵活的功能扩展。传统集成方式中,Spring Boot的类加载器与Kettle的OSGI机制相互冲突,导致部分组件无法正常加载。
因此分析得出Springboot的类加载是自己实现的一套基于LaunchedURLClassLoader的加载,而Kettle的类加载主要是依赖的系统的类加载器。这样的情况下我们可以采用替换系统类加载器的方式实现一套自定义的类加载器对kettle的类加载进行单独处理。
技术细节
这里我们实现一个自定义的类加载器,让他继承URLClassLoader这个加载器,重新实现这个类加载器中的一些方法。

在实现中让类加载单独加载Kettle下的lib和classes目录。
实现这个自定义的类加载器以后,我们还要在启动脚本中添加一些参数,用来替换系统的类加载器
java -Djava.system.class.loader=custloader.CustUrlClassloader -cp ./custloader-0.0.1-SNAPSHOT.jar;“${springboo启动jar包}” -Dloader.path=./config,./lib
至于kettle和Springboot之间的交互,还需要定义一套交互接口,在Springboot启动的时候通过反射的方式来启动Kettle,需要写一个第三方的代理包用于实现交互接口进行Springboot和Kettle的交互实现。下面是部分关键代码
public void initStart(String[] args,java.util.Map<String,String> databaseinfo) {ClassLoader classLoader=ClassLoader.getSystemClassLoader();//获取系统加载器System.out.println(classLoader.getClass().getName());if(classLoader.getClass().getName().equals("sun.misc.Launcher$AppClassLoader")) {String tip_home = System.getProperty(KETTLE_HOME);String libsPath = tip_home + File.separator + "lib";String classesPath=tip_home + File.separator + "classes";File classesFile=new File(classesPath);if(classesFile.exists()) {System.out.println("load classes libraries from: " + classesPath);//LoadJarsHelper.loadClasses(classesPath);LoadJarsHelper.loadClasses(classesPath);}System.out.println("load libs-jars from: " + libsPath);//LoadJarsHelper.loadJars(libsPath);File libsPathFile=new File(libsPath);if(libsPathFile.exists()) {LoadJarsHelper.loadJars(libsPath);}String os = System.getProperty("os.name"); String bit=System.getProperty("sun.arch.data.model");String swtpath=tip_home+File.separator +"libswt/win64";if(os.toLowerCase().startsWith("win")){ if(bit.equalsIgnoreCase("32")) {swtpath=tip_home+File.separator +"libswt/win32";}else {swtpath=tip_home+File.separator +"libswt/win64";}}else if (os.startsWith("Mac OS")){swtpath=tip_home+File.separator +"libswt/osx64";}else {if(bit.equalsIgnoreCase("32")) {swtpath=tip_home+File.separator +"libswt/linux/x86";}else {swtpath=tip_home+File.separator +"libswt/linux/x86_64";}}System.out.println("load swt from: " + swtpath);File swtpathFile=new File(swtpath);if(swtpathFile.exists()) {LoadJarsHelper.loadJars(swtpath);}}Thread kettleThread=new Thread(new Runnable() {public void run() {try {Thread.currentThread().setContextClassLoader(classLoader);Class<?> clazz = classLoader.loadClass("xx.xx.xx.KettleService");IKettleService instance = (IKettleService) clazz.newInstance();Method mainMethod = clazz.getMethod("start", String[].class,Map.class);if(args.length>1) {List<String> objs=new ArrayList<String>();for(int i=1;i<args.length;i++) {if(i==1) {if(!args[i].equals("")) {objs.add(args[i]);}}else {objs.add(args[i]);}}String[] o=objs.toArray(new String[objs.size()]);mainMethod.invoke(instance, (Object)o,databaseinfo);}else {String[] objs=new String[0];mainMethod.invoke(instance, (Object)objs,databaseinfo);}KettleService.setDatabaseManager(instance.getDatabaseManager());//接口实现KettleService.setJobManager(instance.getJobManager());KettleService.setMetaManager(instance.getMetaManager());KettleService.setModelManager(instance.getModelManager());KettleService.setRepositoryDirectoryManager(instance.getRepositoryDirectoryManager());KettleService.setTransManager(instance.getTransManager());KettleService.setLogManager(instance.getLogManager());KettleService.setJmxService(instance); KettleService.addLogListener();} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NoSuchMethodException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});kettleThread.start();}
小结
通过上述技术细节,我成功实现了一种兼容Spring Boot和Kettle的类加载机制。这种集成方式不仅解决了传统依赖集成的诸多弊端,还实现了Kettle功能的完整扩展,为Spring Boot项目中的数据处理提供了更灵活、高效的解决方案。
相关文章:
kettle与Springboot的集成方法,完整支持大数据组件
目录 概要整体架构流程技术名词解释技术细节小结 概要 在现代数据处理和ETL(提取、转换、加载)流程中,Kettle(Pentaho Data Integration, PDI)作为一种强大的开源ETL工具,被广泛应用于各种数据处理场景。…...
GitHub Actions 使用需谨慎:深度剖析其痛点与替代方案
在持续集成与持续部署(CI/CD)领域,GitHub Actions 曾是众多开发者的热门选择,但如今,其弊端逐渐显现,让不少人在使用前不得不深思熟虑。 团队由大约 15 名工程师组成,采用基于主干的开发方式&am…...
<iframe>标签和定时调用函数setInterval
iframe 标签和定时调用函数 setInterval 问题描述:解决方法: 问题描述: 今天遇到一个前端问题,在浏览器页面上传Excel文件后,然后点击导入按钮,经后端Java类读取文件内容校验后,将校验结果返回…...
MYSQL学习笔记(六):聚合函数、sql语句执行原理简要分析
前言: 学习和使用数据库可以说是程序员必须具备能力,这里将更新关于MYSQL的使用讲解,大概应该会更新30篇,涵盖入门、进阶、高级(一些原理分析);这一篇是内容较少,主要讲解:聚合函数和简要介绍sql语句执行过…...
Qt——界面优化
一.QSS 1.背景 在网页前端开发领域中, CSS 是⼀个至关重要的部分。 描述了⼀个网页的 "样式"。 从而起到对网页美化的作用。 所谓样式,包括不限于大小,位置,颜色,背景,间距,字体等等…...
MySQL 数据库常见字段类型大全及详细解析
在工作期间会遇到数据库建表的业务,经常会使用复制粘帖等操作,而不清楚数据库的字段类型。本文记录了 MySQL 数据库常见字段类型,根据不同的数据需求,可以选择不同的字段类型来存储数据。 文章目录 一、整数类型1、TINYINT&#x…...
MATLAB 工具库的使用说明和案例示例
以下是一些常见的 MATLAB 工具库的使用说明和案例示例: 信号处理工具箱(Signal Processing Toolbox): 使用说明:提供了用于生成、测量、变换、过滤和可视化信号的函数和应用程序。包括重新采样、平滑、同步信号、设计…...
对于Docker的初步了解
简介与概述 1.不需要安装环境,工具包包含了环境(jdk等) 2.打包好,“一次封装,到处运行” 3.跨平台,docker容器在任何操作系统上都是一致的,这就是实现跨平台跨服务器。只需要一次配置好环境&…...
java基础学习——jdbc基础知识详细介绍
引言 数据的存储 我们在开发 java 程序时,数据都是存储在内存中的,属于临时存储,当程序停止或重启时,内存中的数据就会丢失,我们为了解决数据的长期存储问题,有以下解决方案: 通过 IO流书记&…...
第20篇:Python 开发进阶:使用Django进行Web开发详解
第20篇:使用Django进行Web开发 内容简介 在上一篇文章中,我们深入探讨了Flask框架的高级功能,并通过构建一个博客系统展示了其实际应用。本篇文章将转向Django,另一个功能强大且广泛使用的Python Web框架。我们将介绍Django的核…...
CukeTest使用 | 1 CukeTest是什么?如何下载安装?
CukeTest使用 | 1 CukeTest是什么?如何下载安装? 1 CukeTest是什么?2 关于开发者3 CukeTest有哪些特性?4 都支持哪些自动化技术类型?5 版本区别6 下载安装 特殊说明:学习内容主要来自官网的教程、以及网上公…...
An OpenGL Toolbox
3.An OpenGL Toolbox 声明:该代码来自:Computer Graphics Through OpenGL From Theory to Experiments,仅用作学习参考 3.1 Vertex Arrays and Their Drawing Commands 顶点数组及其绘制命令:将几何数据存储在一个位置,…...
R语言学习笔记之高效数据操作
一、概要 数据操作是R语言的一大优势,用户可以利用基本包或者拓展包在R语言中进行复杂的数据操作,包括排序、更新、分组汇总等。R数据操作包:data.table和tidyfst两个扩展包。 data.table是当前R中处理数据最快的工具,可以实现快…...
构造函数及实例化的过程:实例成员
构造函数:是一种特殊的函数,主要用来初始化对象 使用场景:比如我们创建了佩奇的对象,继续创建乔治的对象还需要重新写一遍,此时可以通过构造函数来快速创建多个类似的对象。 构造函数语法:大写字母开头的函数 function Pig(name,age,gender)…...
Linux的权限和一些shell原理
目录 shell的原理 Linux权限 sudo命令提权 权限 文件的属性 ⽂件类型: 基本权限: chmod改权限 umask chown 该拥有者 chgrp 改所属组 最后: 目录权限 粘滞位 shell的原理 我们广义上的Linux系统 Linux内核Linux外壳 Linux严格…...
LearnOpenGL——光照
教程地址:简介 - LearnOpenGL CN 前言 这篇开始光照的学习。 颜色 原文链接: 颜色 - LearnOpenGL CN总结: 重新搭建了一个简单场景,为后面的学习做准备。 现实世界中有无数种颜色,每一个物体都有它们自己的颜色。我…...
落地 ORB角点检测与sift检测
ORB角点检测 可以说ORB是由FAST、灰度质心和BRIEF等技术组合优化形成的,不过更准确地说,ORB是在FAST特征检测算法基础上,结合了灰度质心确定方向以及改进后的BRIEF描述子等技术形成的,以下是具体分析: • FAST特征检…...
步入响应式编程篇(二)之Reactor API
步入响应式编程篇(二)之Reactor API 前言回顾响应式编程Reactor API的使用Stream引入依赖Reactor API的使用流源头的创建 reactor api的背压模式发布者与订阅者使用的线程查看弹珠图查看形成新流的日志 前言 对于响应式编程的基于概念,以及J…...
利用Redis实现数据缓存
目录 1 为啥要缓存捏? 2 基本流程(以查询商铺信息为例) 3 实现数据库与缓存双写一致 3.1 内存淘汰 3.2 超时剔除(半自动) 3.3 主动更新(手动) 3.3.1 双写方案 3.3.2 读写穿透方案 3.3.…...
如何使用 pytest-html 创建自定义 HTML 测试报告
关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理,构建成功的基石 在自动化测试工作之前,你应该知道的10条建议 在自动化测试中,重要的不是工具 测试 Python 代码对于提高代码质量、检测漏洞或意外行为至关重要。 但测试结果又该…...
服务器中的流量主要是指什么?
服务器流量就是指服务器在单位时间内所传输的数据量,服务器流量在互联网中起着十分重要的作用,一般会被用来处理网站的访问请求,当用户在网站中浏览网页和视频时,服务器会接收到用户的请求,同时会返回网站的内容。 服务…...
飞牛NAS安装过程中的docker源问题
采用CloudFlare进行飞牛NAS的远程访问 【安全免费】无需公网IP、端口号,NAS外网访问新方法_网络存储_什么值得买 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<EOF {"registry-mirrors": ["https://docker.1panel.dev&quo…...
【动态规划】--- 斐波那契数模型
Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏: 算法Journey 🏠 第N个泰波那契数模型 📌 题目解析 第N个泰波那契数 题目要求的是泰波那契数,并非斐波那契数。 &…...
php-phar打包避坑指南2025
有很多php脚本工具都是打包成phar形式,使用起来就很方便,那么如何自己做一个呢?也找了很多文档,也遇到很多坑,这里就来总结一下 phar安装 现在直接装yum php-cli包就有phar文件,很方便 可通过phar help查看…...
ChirpIoT技术的优势以及局限性
ChirpIoT是一种由上海磐启微电子开发的国产无线射频通讯技术,ChirpIoT技术基于磐启多年对雷达等线性扩频信号的深入研究,并在此基础上对线性扩频信号的变化进行了改进,实现了远距离传输的一种无线通信技术。相关产品型号有E29-400T22D、E290-…...
java提取系统应用的日志中的sql获取表之间的关系
为了获取到对应的sql数据,分了三步骤 第一步,获取日志文件,解析日志文件中的查询sql,递归解析sql,获取表关系集合 递归解析sql,获取表与表之间的关系 输出得到的对应关联关系数据 第二步,根据获…...
PyQt6医疗多模态大语言模型(MLLM)实用系统框架构建初探(下.代码部分)
医疗 MLLM 框架编程实现 本医疗 MLLM 框架结合 Python 与 PyQt6 构建,旨在实现多模态医疗数据融合分析并提供可视化界面。下面从数据预处理、模型构建与训练、可视化界面开发、模型 - 界面通信与部署这几个关键部分详细介绍编程实现。 6.1 数据预处理 在医疗 MLLM 框架中,多…...
IMX6ull项目环境配置
文件解压缩: .tar.gz 格式解压为 tar -zxvf .tar.bz2 格式解压为 tar -jxvf 2.4版本后的U-boot.bin移植进SD卡后,通过串口启动配置开发板和虚拟机网络。 setenv ipaddr 192.168.2.230 setenv ethaddr 00:04:9f:…...
Linux(Centos 7.6)命令详解:wc
1.命令作用 打印文件的行数、单词数、字节数,如果指定了多个文件,还会打印以上三种数据的总和(Print newline, word, and byte counts for each FILE, and a total line if more than one FILE is specified) 2.命令语法 Usage: wc [OPTION]... [FIL…...
Gradle buildSrc模块详解:集中管理构建逻辑的利器
文章目录 buildSrc模块二 buildSrc的使命三 如何使用buildSrc1. 创建目录结构2. 配置buildSrc的构建脚本3. 编写共享逻辑4. 在模块中引用 四 典型使用场景1. 统一依赖版本管理2. 自定义Gradle任务 3. 封装通用插件4. 扩展Gradle API 五 注意事项六 与复合构建(Compo…...
