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