kettle与Springboot的集成方法,完整支持大数据组件

news2025/1/26 15:31:15

目录

    • 概要
    • 整体架构流程
    • 技术名词解释
    • 技术细节
    • 小结

概要

在现代数据处理和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 block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (NoSuchMethodException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (SecurityException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
    	
    	kettleThread.start();

	}

小结

通过上述技术细节,我成功实现了一种兼容Spring Boot和Kettle的类加载机制。这种集成方式不仅解决了传统依赖集成的诸多弊端,还实现了Kettle功能的完整扩展,为Spring Boot项目中的数据处理提供了更灵活、高效的解决方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2283508.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GitHub Actions 使用需谨慎:深度剖析其痛点与替代方案

在持续集成与持续部署&#xff08;CI/CD&#xff09;领域&#xff0c;GitHub Actions 曾是众多开发者的热门选择&#xff0c;但如今&#xff0c;其弊端逐渐显现&#xff0c;让不少人在使用前不得不深思熟虑。 团队由大约 15 名工程师组成&#xff0c;采用基于主干的开发方式&am…

<iframe>标签和定时调用函数setInterval

iframe 标签和定时调用函数 setInterval 问题描述&#xff1a;解决方法&#xff1a; 问题描述&#xff1a; 今天遇到一个前端问题&#xff0c;在浏览器页面上传Excel文件后&#xff0c;然后点击导入按钮&#xff0c;经后端Java类读取文件内容校验后&#xff0c;将校验结果返回…

Qt——界面优化

一.QSS 1.背景 在网页前端开发领域中&#xff0c; CSS 是⼀个至关重要的部分。 描述了⼀个网页的 "样式"。 从而起到对网页美化的作用。 所谓样式&#xff0c;包括不限于大小&#xff0c;位置&#xff0c;颜色&#xff0c;背景&#xff0c;间距&#xff0c;字体等等…

java基础学习——jdbc基础知识详细介绍

引言 数据的存储 我们在开发 java 程序时&#xff0c;数据都是存储在内存中的&#xff0c;属于临时存储&#xff0c;当程序停止或重启时&#xff0c;内存中的数据就会丢失&#xff0c;我们为了解决数据的长期存储问题&#xff0c;有以下解决方案&#xff1a; 通过 IO流书记&…

CukeTest使用 | 1 CukeTest是什么?如何下载安装?

CukeTest使用 | 1 CukeTest是什么&#xff1f;如何下载安装&#xff1f; 1 CukeTest是什么&#xff1f;2 关于开发者3 CukeTest有哪些特性&#xff1f;4 都支持哪些自动化技术类型&#xff1f;5 版本区别6 下载安装 特殊说明&#xff1a;学习内容主要来自官网的教程、以及网上公…

An OpenGL Toolbox

3.An OpenGL Toolbox 声明&#xff1a;该代码来自&#xff1a;Computer Graphics Through OpenGL From Theory to Experiments&#xff0c;仅用作学习参考 3.1 Vertex Arrays and Their Drawing Commands 顶点数组及其绘制命令&#xff1a;将几何数据存储在一个位置&#xff0c…

R语言学习笔记之高效数据操作

一、概要 数据操作是R语言的一大优势&#xff0c;用户可以利用基本包或者拓展包在R语言中进行复杂的数据操作&#xff0c;包括排序、更新、分组汇总等。R数据操作包&#xff1a;data.table和tidyfst两个扩展包。 data.table是当前R中处理数据最快的工具&#xff0c;可以实现快…

Linux的权限和一些shell原理

目录 shell的原理 Linux权限 sudo命令提权 权限 文件的属性 ⽂件类型&#xff1a; 基本权限&#xff1a; chmod改权限 umask chown 该拥有者 chgrp 改所属组 最后&#xff1a; 目录权限 粘滞位 shell的原理 我们广义上的Linux系统 Linux内核Linux外壳 Linux严格…

LearnOpenGL——光照

教程地址&#xff1a;简介 - LearnOpenGL CN 前言 这篇开始光照的学习。 颜色 原文链接&#xff1a; 颜色 - LearnOpenGL CN总结&#xff1a; 重新搭建了一个简单场景&#xff0c;为后面的学习做准备。 现实世界中有无数种颜色&#xff0c;每一个物体都有它们自己的颜色。我…

步入响应式编程篇(二)之Reactor API

步入响应式编程篇&#xff08;二&#xff09;之Reactor API 前言回顾响应式编程Reactor API的使用Stream引入依赖Reactor API的使用流源头的创建 reactor api的背压模式发布者与订阅者使用的线程查看弹珠图查看形成新流的日志 前言 对于响应式编程的基于概念&#xff0c;以及J…

利用Redis实现数据缓存

目录 1 为啥要缓存捏&#xff1f; 2 基本流程&#xff08;以查询商铺信息为例&#xff09; 3 实现数据库与缓存双写一致 3.1 内存淘汰 3.2 超时剔除&#xff08;半自动&#xff09; 3.3 主动更新&#xff08;手动&#xff09; 3.3.1 双写方案 3.3.2 读写穿透方案 3.3.…

【动态规划】--- 斐波那契数模型

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; 算法Journey &#x1f3e0; 第N个泰波那契数模型 &#x1f4cc; 题目解析 第N个泰波那契数 题目要求的是泰波那契数&#xff0c;并非斐波那契数。 &…

php-phar打包避坑指南2025

有很多php脚本工具都是打包成phar形式&#xff0c;使用起来就很方便&#xff0c;那么如何自己做一个呢&#xff1f;也找了很多文档&#xff0c;也遇到很多坑&#xff0c;这里就来总结一下 phar安装 现在直接装yum php-cli包就有phar文件&#xff0c;很方便 可通过phar help查看…

java提取系统应用的日志中的sql获取表之间的关系

为了获取到对应的sql数据&#xff0c;分了三步骤 第一步&#xff0c;获取日志文件&#xff0c;解析日志文件中的查询sql&#xff0c;递归解析sql&#xff0c;获取表关系集合 递归解析sql&#xff0c;获取表与表之间的关系 输出得到的对应关联关系数据 第二步&#xff0c;根据获…

PyQt6医疗多模态大语言模型(MLLM)实用系统框架构建初探(下.代码部分)

医疗 MLLM 框架编程实现 本医疗 MLLM 框架结合 Python 与 PyQt6 构建,旨在实现多模态医疗数据融合分析并提供可视化界面。下面从数据预处理、模型构建与训练、可视化界面开发、模型 - 界面通信与部署这几个关键部分详细介绍编程实现。 6.1 数据预处理 在医疗 MLLM 框架中,多…

IMX6ull项目环境配置

文件解压缩&#xff1a; .tar.gz 格式解压为 tar -zxvf .tar.bz2 格式解压为 tar -jxvf 2.4版本后的U-boot.bin移植进SD卡后&#xff0c;通过串口启动配置开发板和虚拟机网络。 setenv ipaddr 192.168.2.230 setenv ethaddr 00:04:9f:…

Gradle buildSrc模块详解:集中管理构建逻辑的利器

文章目录 buildSrc模块二 buildSrc的使命三 如何使用buildSrc1. 创建目录结构2. 配置buildSrc的构建脚本3. 编写共享逻辑4. 在模块中引用 四 典型使用场景1. 统一依赖版本管理2. 自定义Gradle任务 3. 封装通用插件4. 扩展Gradle API 五 注意事项六 与复合构建&#xff08;Compo…

六、深入了解DI

依赖注入是⼀个过程&#xff0c;是指IoC容器在创建Bean时,去提供运⾏时所依赖的资源&#xff0c;⽽资源指的就是对象. 在上⾯程序案例中&#xff0c;我们使⽤了 Autowired 这个注解&#xff0c;完成了依赖注⼊的操作. 简单来说,就是把对象取出来放到某个类的属性中。 关于依赖注…

【论文阅读】HumanPlus: Humanoid Shadowing and Imitation from Humans

作者&#xff1a;Zipeng Fu、Qingqing Zhao、Qi Wu、Gordon Wetstein、Chelsea Finn 项目共同负责人&#xff0c;斯坦福大学 项目网址&#xff1a;https://humanoid-ai.github.io 摘要 制造外形与人类相似的机器人的一个关键理由是&#xff0c;我们可以利用大量的人类数据进行…

第25篇 基于ARM A9处理器用C语言实现中断<一>

Q&#xff1a;怎样理解基于ARM A9处理器用C语言实现中断的过程呢&#xff1f; A&#xff1a;同样以一段使用C语言实现中断的主程序为例介绍&#xff0c;和汇编语言实现中断一样这段代码也使用了定时器中断和按键中断。执行该主程序会在DE1-SoC的红色LED上显示流水灯&#xf…