PowerJob容器的前世,容器是如何产生,如何上传到Server上去的

news2025/2/26 3:43:08

这不仅仅是一篇PowerJob源码分析的文章,还有很多的java基础知识,在实践中学习效果更好,感兴趣就留下来交流一下吧。

 

power容器虽然说是容器,但并不是docker容器,仅仅就是java的jar包 ,可以通过框架下载一套简单的java项目模板,然后在里面编写相对应的功能,将其上传之后,在worker中进行部署执行。这个功能是一个相对来说比较独立的功能,所以就从使用以及代码细节详细的说一说,相信即使你没有用到powerjob,这一个功能里面包含的内容,也会让你收获颇丰。

一切的源头:模板下载

该功能主要是从前台页面的上图处进入,只需要简单填入创建java项目所需要的简单信息即可,按照上图信息生成的模板,目录结构如下所示:

 生成模板时,会调用如下代码,非常简单,就是springboot的Controller中的ContainerController

@PostMapping("/downloadContainerTemplate")
public void downloadContainerTemplate(@RequestBody GenerateContainerTemplateRequest req, HttpServletResponse response) throws IOException {
    File zipFile = ContainerTemplateGenerator.generate(req.getGroup(), req.getArtifact(), req.getName(), req.getPackageName(), req.getJavaVersion());
    OmsFileUtils.file2HttpResponse(zipFile, response);
}

紧接着就是生成项目,让我们移步ContainerTemplateGenerator类的generate方法中去看一下,生成项目都做了哪些工作:

1. 通过OmsFileUtils类生成一个临时文件夹,路径是user.home/powerjob/server/temporary/随机生成的UUID/tmp.jar

String workerDir = OmsFileUtils.genTemporaryWorkPath(); File originJar = new File(workerDir + "tmp.jar");

2. 设置一个解压后的临时路径,就是在原路径后面多加一层,user.home/powerjob/server/temporary/随机生成的UUID/unzip/

String tmpPath = workerDir + "/unzip/";

3. 读取resource下的oms-template-origin.zip,将其内容复制给第一步生成的临时jar包

try (InputStream is = ContainerTemplateGenerator.class.getClassLoader().getResourceAsStream(ORIGIN_FILE_NAME + ".zip")) {
    Objects.requireNonNull(is, "generate container template failed, can't find zip file in classpath.");
    FileUtils.copyInputStreamToFile(is, originJar);
}

4. 将第一步生成的jar包,解压到第二步设置的临时文件夹中

ZipFile zipFile = new ZipFile(originJar); zipFile.extractAll(tmpPath);

5. 设置一个根目录

String rootPath = tmpPath + ORIGIN_FILE_NAME;

6. 通过根目录,获取到pom所在的位置

String pomPath = rootPath + "/pom.xml";

7. 将前台页面添加的信息加入到pom文件中去

String line;
StringBuilder buffer = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(pomPath))) {
    while ((line = br.readLine()) != null) {

        if (line.contains("<groupId>groupId</groupId>")) {
            buffer.append("    <groupId>").append(group).append("</groupId>");
        }else if (line.contains("<artifactId>artifactId</artifactId>")) {
            buffer.append("    <artifactId>").append(artifact).append("</artifactId>");
        }else if (line.contains("<name>name</name>")) {
            buffer.append("    <name>").append(name).append("</name>");
        }else if (line.contains("<maven.compiler.source>")) {
            buffer.append("        <maven.compiler.source>").append(javaVersion).append("</maven.compiler.source>");
        }else if (line.contains("<maven.compiler.target>")) {
            buffer.append("        <maven.compiler.target>").append(javaVersion).append("</maven.compiler.target>");
        } else {
            buffer.append(line);
        }
        buffer.append(System.lineSeparator());
    }
}
OmsFileUtils.string2File(buffer.toString(), new File(pomPath));

8. 根据页面信息,新建一个src下的包文件夹

String packagePath = StringUtils.replace(packageName, ".", "/");
String absPath = rootPath + "/src/main/java/" + packagePath;
FileUtils.forceMkdir(new File(absPath));

9.修改spring的配置文件,默认配置文件名为“oms-worker-container-spring-context.xml”

String resourcePath = rootPath + "/src/main/resources/";
String springXMLPath = resourcePath + ContainerConstant.SPRING_CONTEXT_FILE_NAME;
buffer.setLength(0);

try (BufferedReader br = new BufferedReader(new FileReader(springXMLPath))) {
    while ((line = br.readLine()) != null) {

        if (line.contains("<context:component-scan base-package=\"")) {
            buffer.append("    <context:component-scan base-package=\"").append(packageName).append("\"/>");
        }else {
            buffer.append(line);
        }
        buffer.append(System.lineSeparator());
    }
}
OmsFileUtils.string2File(buffer.toString(), new File(springXMLPath));

10. 生成properties文件

String propertiesPath = resourcePath + ContainerConstant.CONTAINER_PROPERTIES_FILE_NAME;
String properties = ContainerConstant.CONTAINER_PACKAGE_NAME_KEY + "=" + packageName;
OmsFileUtils.string2File(properties, new File(propertiesPath));

11. 将经过上述步骤处理后的文件打包成jar

String finPath = tmpPath + "template.zip";
ZipFile finZip = new ZipFile(finPath);
finZip.addFolder(new File(rootPath));

12. 删除原文件

FileUtils.forceDelete(originJar);

在模板中完成一个简单的功能

这一步并不重要,要完成什么功能都可以,可以是数据库清理功能,也可以是业务的新增功能,甚至是一个无关紧要的输出功能都可以,根据个人需要自己随便写一个即可,我就简简单单实现一个输出功能就可以,里面的功能暂时是不重要的,代码如下:

package zcrazy.container.test;

import tech.powerjob.worker.core.processor.ProcessResult;
import tech.powerjob.worker.core.processor.TaskContext;
import tech.powerjob.worker.core.processor.sdk.BasicProcessor;

import java.time.LocalDate;

public class UnimportantFunction implements BasicProcessor {

    @Override
    public ProcessResult process(TaskContext taskContext) throws Exception {

        String str = "你好!主人!,现在是北京时间"+ LocalDate.now()+"。希望你今天过得愉快~";

        return new ProcessResult(true);
    }

}

然后打成jar包上传的服务器上,上传功能在前台页面的这个位置:

点击新增容器之后,开始填如下信息

 

选择FatJar进行上传,为什么不选Git?因为我们公司的破网上不了Git,只能搭私服GIt,我也没有整过,这里就不弄了,就是将刚才打包的jar上传到服务器上,点击Save,会进入到ContainerController的fileUpload方法中去,代码如下:

@PostMapping("/jarUpload")
public ResultDTO<String> fileUpload(@RequestParam("file") MultipartFile file) throws Exception {
    if (file == null || file.isEmpty()) {
        return ResultDTO.failed("empty file");
    }
    return ResultDTO.success(containerService.uploadContainerJarFile(file));
}

这里面的核心是ContainerService的uploadContainerJarFile方法,下面我就将该方法一步一步再细说一下:

1. 创建一个临时jar包

String workerDirStr = OmsFileUtils.genTemporaryWorkPath(); 
String tmpFileStr = workerDirStr + "tmp.jar"; 
File workerDir = new File(workerDirStr); 
File tmpFile = new File(tmpFileStr);

2.将上传的文件下载到本地,转化给刚刚临时创建的jar中

FileUtils.forceMkdirParent(tmpFile); 
file.transferTo(tmpFile);

3.将jar包生成MD5压缩码,再将这个码作为version生成这个jar包的名字

String md5 = OmsFileUtils.md5(tmpFile);
String fileName = genContainerJarName(md5);

4.如果使用到了MongoDB数据库,就将第三步这个文件保存到MongoDB上

gridFsManager.store(tmpFile, GridFsManager.CONTAINER_BUCKET, fileName);

5. 将最终的jar包拷贝到指定的文件位置

String finalFileStr = OmsFileUtils.genContainerJarPath() + fileName;
File finalFile = new File(finalFileStr);
if (finalFile.exists()) {
    FileUtils.forceDelete(finalFile);
}
FileUtils.moveFile(tmpFile, finalFile);

上传成功之后,容器运维页面就会多出一个容器来

总结

 

这就是powerjob容器的模板生成与上传,非常的简单,代码也很好理解,如果有不明白的地方,欢迎随时留言,容器的部署与运行将在下一篇文章中继续说明。

 

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

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

相关文章

手工测试混了5年,年底接到了被裁员的消息....

大家都比较看好软件测试行业&#xff0c;只是因为表面上看起来&#xff1a;钱多事少加班少。其实这个都是针对个人运气好的童人才会有此待遇。在不同的阶段做好不同阶段的事情&#xff0c;才有可能离这个目标更近&#xff0c;作为一枚软件测试人员&#xff0c;也许下面才是我们…

阿里5年,一个女工对软件测试的理解

成为一个优秀的测试工程师需要具备哪些知识和经验&#xff1f; 针对这个问题&#xff0c;可以直接拆分以下三个小问题来详细说明&#xff1a; 1、优秀软件测试工程师的标准是什么&#xff1f; 2、一个合格的测试工程师需要具备哪些专业知识&#xff1f; 3、一个合格的测试工程…

介绍Kadence Elements元素模板:按您的方式设计网站

随着 Kadence Pro 1.0.4 和 Kadence Blocks Pro 1.5.8 的发布&#xff0c;Kadence 团队很高兴地宣布推出最强大的新方法&#xff0c;帮助网站所有者使用 Kadence Elements Templates 创建动态和高度定制的 WordPress 网站。如果您曾经创建过 WordPress 网站&#xff0c;并且发现…

Fiddler的简单使用

目录 1.断点应用 2.网络限速测试 2.1.为什么需要弱网测试 2.2.Fiddler弱网测试配置 1.断点应用 通过断点功能&#xff0c;可以在测试时方便的篡改request&#xff0c;response以达到测试的目的&#xff0c;如果&#xff1a;在请求头中的参数修改成错误的&#xff0c;或在响应…

强化学习DQN之俄罗斯方块

强化学习DQN之俄罗斯方块强化学习DQN之俄罗斯方块算法流程文件目录结构模型结构游戏环境训练代码测试代码结果展示强化学习DQN之俄罗斯方块 算法流程 本项目目的是训练一个基于深度强化学习的俄罗斯方块。具体来说&#xff0c;这个代码通过以下步骤实现训练&#xff1a; 首先…

2023最新网络工程师HCIA-Datacom“1000”道题库,光速刷题拿证

HCIA认证是华为认证体系的初级认证&#xff0c;可以说是网工进入IT行业的一张从业资格证&#xff01; HCIA-Datacom考试覆盖数通基础知识 包括 TCP/IP 协议栈基础知识&#xff0c;OSPF 路由协议基本原理以及在华为路由器中的配置实现&#xff0c;以太网技术、生成树、VLAN 原…

【Java 面试合集】final 以及finally 不同

final 以及finally 不同 1. 概述 嗨&#xff0c;大家好【Java 面试合集】又来了。今天给大家分享的主题是final 以及finally 不同. 很简单&#xff0c;但是确实很细节哦&#xff0c;好了废话不多说&#xff0c;让我们开始吧 2. final 首先我们要知道final 是一个修饰符&#x…

WordPress主题:知更鸟Begin5.2免授权版

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 HTML5CSS3响应式设计兼容IE8、Firefox、Chrome等现代浏览器。杂志布局、图片布局和博客布局后台切换 Wordpress主题 知更鸟Begin主题 无授权无加密独立页面模板 博客布局、随机文章、友…

总结:电容在电路35个基本常识

1 电压源正负端接了一个电容&#xff0c;与电路并联&#xff0c;用于整流电路时&#xff0c;具有很好的滤波作用&#xff0c;当电压交变时&#xff0c;由于电容的充电作用&#xff0c;两端的电压不能突变&#xff0c;就保证了电压的平稳。 当用于电池电源时&#xff0c;具有交流…

Python 四大主流 Web 编程框架

目前Python的网络编程框架已经多达几十个&#xff0c;逐个学习它们显然不现实。但这些框架在系统架构和运行环境中有很多共通之处&#xff0c;本文带领读者学习基于Python网络框架开发的常用知识,及目前的4种主流Python网络框架&#xff1a;Django、Tornado、Flask、Twisted。 …

【Git】Git是什么?简单说说Git的工作机制?Git的常用命令有那些?

目录 一、Git是什么? 二、简单说说Git的工作机制&#xff1f; 三、Git的常用命令有那些&#xff1f; &#x1f49f; 创作不易&#xff0c;不妨点赞&#x1f49a;评论❤️收藏&#x1f499;一下 一、Git是什么? Git 是一个免费的、开源的分布式版本控制系统&#xff0c;可…

若依(微服务版)-0 运行(踩坑日记)

本次运行采用本地运行程序&#xff0c;其他中间件全部使用docker安装在云服务器上 本次运行的若依为目前最新版本3.6.2&#xff0c;nacos/nacos-server:v2.0.4&#xff0c;mysql8.0&#xff0c;redis和nginx最新版就行。 关于nacos这里会有好几个坑&#xff0c;详情请看naocs…

【C语言】浮点型数据在内存中的存储

&#x1f680;&#x1f680;&#x1f680; 如果文章对你有帮助不要忘记点赞关注收藏哦&#x1f680;&#x1f680;&#x1f680; 文章目录⭐浮点数在内存中的存储1.1 &#x1f913;举个例子:1.2浮点数存储规则&#x1f308;&#xff1a;对于M与E有一些特别规定1.3解释前面题目&…

内存映射(1)

内存映射 将磁盘文件中的数据映射到内存&#xff0c;用户通过修改内存就能修改磁盘文件 相关的系统调用&#xff1a; void *mmap() 功能&#xff1a;将一个文件或设备的数据映射到内存中 参数&#xff1a; void *addr : NULL 由内核指定length : 要映射的数据长度&#xff0c;…

端口扫描介绍

文章目录1、端口的基本概念2、端口的常见分类3、端口扫描原理1、端口的基本概念 “端口” 在计算机网络领域中是个非常重要的概念它是专门为计算机通信而设计的&#xff0c;它不是硬件&#xff0c;不同于计算机中的“插槽”&#xff0c;可以说是个“软端口”端口是由计算机的通…

MacBook Pro 恢复出厂设置

目录1.恢复出厂设置1.1 按Command-R 键1.2 macOS 实用工具1.3 从 macOS 恢复功能的实用工具窗口中选择“磁盘工具”&#xff0c;然后点按“继续”1.4 在“磁盘工具”边栏中选择您的设备或宗卷。1.5 点按“抹掉”按钮或标签页1.6 抹掉OS X HD - 数据 完成1.7 抹掉 OS X HD1.8 查…

核心技术: springboot 启动类加载时方法执行的几种实现方式, bean声明周期, 启动执行顺序

目录 1. 业务场景 -> 1.1 初始化操作 -> 1.2 业务操作 -> 1.3优势 2. 实现方式(多种方式,不同思想) -> 2.1 定时调度任务(常用四种方式 task ) --> 2.1.1 Timer(单线程) --> 2.1.2 scheduledExecutorService(多线程并发执行,线程池) --> 2.1…

SmoothNLP新词发现算法的改进实现

SmoothNLP新词发现算法的改进实现 背景介绍 新词发现也叫未登录词提取&#xff0c;依据 《统计自然语言处理》(宗成庆)&#xff0c;中文分词有98%的错误来自"未登录词"。即便早就火遍大江南北的Bert也不能解决"未登录词"的Encoding问题&#xff0c;便索性…

棋牌类游戏测试用例怎么写?我敢打赌你绝对不知道

目录 一&#xff0e;登陆 二&#xff0e;大厅 三&#xff0e;小游戏 四&#xff0e;银行功能 五&#xff0e;其他按钮 总结感谢每一个认真阅读我文章的人&#xff01;&#xff01;&#xff01; 重点&#xff1a;配套学习资料和视频教学 一&#xff0e;登陆 1&#xff0e…

Redis高可用集群方案

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 @[TOC](文章目录)主从复制哨兵模式(sentinel)Cluster集群在生产过程中,Redis不一定会单独部署。因为一旦redis服务因为某些原因导致无法提供数,那么redis就不可用了。那么实现redis高可用的方式就…