愚蠢的代码?某程序员强行编写了一段开发阶段无法调试的代码,大佬们快来救救他!

本文主要是介绍愚蠢的代码?某程序员强行编写了一段开发阶段无法调试的代码,大佬们快来救救他!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、开场白
    • 1. 程序员打赌的故事
    • 2. 目标: 尽量在不修改代码的情况下将springmvc框架以独立jar方式运行
  • 二、出师不利
    • 方案一、Spring Web工程转Spring Boot
    • 方案二、引入内置服务器jetty
    • 其余备用方案
  • 三、柳暗花明
    • 遇见jetty-runner
    • 测试验证
      • 准备工作:
      • 部署工作
  • 四、再接再厉
    • 一、新建maven工程pom.xml
    • 二、编写核心逻辑
    • 三、测试
  • 五、遗留难题
    • 难难难!!! 小C突然发现这个代码在开发阶段竟然是无法调试的。

一、开场白

1. 程序员打赌的故事

    小A、小B、小C都在一家初创公司工作,小A是系统运维,小B和小C都是后台开发,他们都是能力卓越的IT工程狮。
    某日加班后,三人聚在一起闲聊。小A向其余2人抱怨说,咱们公司开发小组维护的那个历史比较悠久的B项目,在测试服务上部署太麻烦了,每次更新都需要先停Tomcat服务器,再删掉旧的war和目录,然后上传war包,最后再重启服务。你们看看能不能改造下,最好能象springboot工程一样,上传一个jar,一个命令启停就搞定了,能这样就谢天谢地了!

    小B说,据我所知,那个B项目是springmvc框架开发的,历史悠久,想把他转换为springboot框架Jar运行,基本上不太可能,除非大动。
    小C说,我看有一定可行性,只是需要时间做技术预研。

    于是,3人约定将这件事情作为一个技术攻坚工作,谁能够先成功解决,另外2人请吃饭。而且可以上报本季度的效率提升之星(获得免费2天的调休时间以及物质奖励)

2. 目标: 尽量在不修改代码的情况下将springmvc框架以独立jar方式运行

二、出师不利

经过一段时间的技术预研,小B、小C他们提出了以下2个主要方案和备用方案

方案一、Spring Web工程转Spring Boot

步骤1:删除web.xml

步骤2:pom.xml导入springboot

步骤3:添加springboot 启动代码,保留springmvc工程xml配置文件,用ImportResource注解引入

参考案例: springmvc-dbutils-redis、 springmvc-dbutils-to-boot

方案二、引入内置服务器jetty

步骤1:pom.xml导入jetty相关组件,一般包含jetty-webapp、jetty-jsp、jetty-server等。

步骤2:编写启动类,设置jetty启动的各项参数。

参考案例:keta-custom

其余备用方案

自己实现一套web逻辑,可以参考的项目主要有:h2-database、Jenkins

不幸的是以上几种方案,均违背了以下前提:

  1. 代码修改变动太大,对原始代码侵入太强
  2. java web程序一般都是war,改造成boot工程未必就是Jar(其实war如果能独立运行的也是可以接受的)

事情似乎陷入了死胡同。。。

三、柳暗花明

遇见jetty-runner

大家继续寻找方案,这天小C,在查找资料时,忽然在jetty官网看到这样一句话:
Jetty Runner ,This chapter explains how to use the jetty-runner to run your webapps without needing an installation of Jetty.

Deploying a Simple Context Let’s assume we have a very simple webapp that does not need any resources from its environment, nor any configuration apart from the defaults. Starting it is as simple as performing the following:

java -jar jetty-runner.jar simple.war

官网文档:https://eclipse.dev/jetty/documentation/jetty-9/index.html#runner

测试验证

准备工作:

从maven中央仓库下载jetty-runner jar
因为本地开发环境是jdk8,所以下载了支持jdk版本为1.8的9.3或者9.4系列版本。

部署工作

小C急忙将之前开发的一个springmvc工程打成的dbtool_simple.war找出来,与jetty-runner.jar放在同一级目录
在这里插入图片描述
并敲下这个命令:java -jar jetty-runner-9.4.52.v20230823.jar dbtool_simple.war
后台打印出一段日志后,dbtool_simple.war竟然成功启动了
在这里插入图片描述
小C激动的都快喊出来了。

四、再接再厉

小C冷静下来之后,看着jar、war陷入了沉思,现在jar、war其实是分离的,其实可以将war打包到jar里面运行,经过一段思考之后,小C提出了如下优化方案:

暂时将此项目命名为jetty-runner-extra,这样项目打出的jar为jetty-runner-extra.jar
我们需要完成如下优化:

  1. 执行 java -jar jetty-runner-extra.jar 搜索jar内存在的war运行,否则给出提示 war不存在,程序终止。
  2. 执行 java -jar jetty-runner-extra.jar --addwar 交互运行,列出当前目录(包含子目录)war供选择添加,添加后生成新的jar,jar执行逻辑同1。
  3. 执行 java -jar jetty-runner-extra.jar --addwar war/simple.war 如指定的war存在,直接添加,添加后生成新的jar,jar执行逻辑同1。否则给出提示 war不存在,程序终止。

说干就干!

一、新建maven工程pom.xml

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.fly</groupId><artifactId>jetty-runner-extra</artifactId><version>1.0.0</version><name>jetty-runner-extra</name><url>http://maven.apache.org</url><packaging>jar</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><log4j.version>2.12.1</log4j.version><java.version>1.8</java.version><skipTests>true</skipTests></properties><dependencies><dependency><groupId>org.eclipse.jetty</groupId><artifactId>jetty-runner</artifactId><version>9.4.52.v20230823</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.5</version></dependency><!-- slf4j + log4j2 begin --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>${log4j.version}</version></dependency><!-- log4j end --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency></dependencies><build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.4.0</version><executions><execution><phase>package</phase><goals><goal>shade</goal></goals><configuration><minimizeJar>false</minimizeJar><filters><filter><artifact>*:*</artifact></filter></filters><transformers><!-- 往MANIFEST文件中写入Main-Class是可执行包的必要条件。ManifestResourceTransformer可以轻松实现。 --><transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"><mainClass>com.fly.JettyExtraRunner</mainClass></transformer><!-- AppendingTransformer 用来处理多个jar包中存在重名的配置文件的合并,尤其是spring --><transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"><resource>META-INF/services/javax.servlet.ServletContainerInitializer</resource></transformer></transformers></configuration></execution></executions></plugin></plugins></build>
</project>

这里我们引入了jetty-runner、commons-io、log4j2、lombok还有maven-shade-plugin插件,插件主要实现可执行jar的配置。

二、编写核心逻辑

JettyExtraRunner.java

package com.fly;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Scanner;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.eclipse.jetty.runner.Runner;import lombok.extern.slf4j.Slf4j;@Slf4j
@SuppressWarnings("deprecation")
public class JettyExtraRunner
{private static URL url = JettyExtraRunner.class.getProtectionDomain().getCodeSource().getLocation();/*** 遍历文件或Jar寻找war运行* * @param args* @throws IOException*/public static void main(String[] args)throws IOException{log.info("类加载路径: {}", url.getPath());boolean isJar = url.getPath().endsWith(".jar");if (isJar){processInJar(args);}}/*** Jar遍历-寻找war-拷贝-运行* * @param args* @throws IOException*/private static void processInJar(String[] args)throws IOException{// 调用方式1: java -jar jetty-runner-extra.jar 搜索jar内存在的war运行,否则给出提示 war不存在,程序终止if (args.length == 0){try (JarFile jarFile = new JarFile(url.getFile())){int num = 0;Enumeration<JarEntry> entrys = jarFile.entries();while (entrys.hasMoreElements()){JarEntry jar = entrys.nextElement();String name = jar.getName();if (name.endsWith(".war")){num++;log.info("即将加载运行:{}", name);try (InputStream is = JettyExtraRunner.class.getResourceAsStream("/" + name)){File file = new File(name);FileUtils.copyInputStreamToFile(is, file);Runner.main(new String[] {file.getCanonicalPath()});return;}}}if (num == 0){log.error("未发现war文件,程序终止");}}return;}// 调用方式2: java -jar jetty-runner-extra.jar --addwar 交互运行,列出当前目录(包含子目录)war供选择添加if (args.length == 1 && "--addwar".equals(args[0])){Collection<File> files = FileUtils.listFiles(new File(url.getPath()).getParentFile(), new String[] {"war"}, true);if (files.isEmpty()){log.error("未发现war文件,无法添加");return;}File selected;if (files.size() == 1){selected = files.toArray(new File[0])[0];}else{// 列出->选择try (Scanner sc = new Scanner(System.in)){int input;do{int index = 1;for (File file : files){log.info("序号{}: {}", index++, file.getCanonicalPath());}log.info("请输入序号1-{}选择war文件", files.size());input = sc.nextInt();} while (input < 1 || input > files.size());selected = files.toArray(new File[0])[input - 1];log.info("你选择了war文件:{} ", selected.getCanonicalPath());}}addWar(selected);return;}// 调用方式3: java -jar jetty-runner-extra.jar --addwar war/simple.war 如指定的war存在,直接添加,否则给出提示 war不存在,程序终止if (args.length == 2 && "--addwar".equals(args[0])){String path = args[1];File war = new File(path);if (war.exists()){log.info("文件:{}", war.getCanonicalPath());addWar(war);}else{log.error("{} 不存在,程序终止", path);}return;}}/*** 添加war到新jar中* * @param war* @see [类、类#方法、类#成员]*/private static void addWar(File war){try{File srcJar = new File(url.getPath());String newJar = srcJar.getCanonicalPath().replace(".jar", DateFormatUtils.format(System.currentTimeMillis(), "_HHmmssSSS") + ".jar");addWarToJar(war, srcJar, newJar);}catch (IOException e){log.error(e.getMessage(), e);}}/*** 将war添加到srcJar并重命名为newJar* * @param war* @param srcJar* @param newJar* @throws IOException*/private static void addWarToJar(File war, File srcJar, String newJar)throws IOException{log.info("即将添加war文件:{} 到Jar中...", war.getCanonicalPath());try (JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(newJar)); JarFile jarFile = new JarFile(srcJar)){// 遍历jar文件数据写入新jarEnumeration<JarEntry> entrys = jarFile.entries();while (entrys.hasMoreElements()){JarEntry jarEntry = entrys.nextElement();if (jarEntry != null){jarOutputStream.putNextEntry(jarEntry);try (InputStream entryInputStream = jarFile.getInputStream(jarEntry)){IOUtils.copy(entryInputStream, jarOutputStream);}}}// 追加war写入数据JarEntry warEntry = new JarEntry("war/" + war.getName());jarOutputStream.putNextEntry(warEntry);try (InputStream entryInputStream = new FileInputStream(war)){IOUtils.copy(entryInputStream, jarOutputStream);}}}
}

三、测试

我们在项目的根目录执行mvn clean package 便生成了 jetty-runner-extra.jar
目录结构如下:
在这里插入图片描述
我们来实际运行下:
在这里插入图片描述
在这里插入图片描述

五、遗留难题

难难难!!! 小C突然发现这个代码在开发阶段竟然是无法调试的。

各位大佬,快来帮帮他,提供思路来解决他的难处!!
把这段代码变得聪明起来!!解决问题有帮助的网友,版主会点名感谢!!
俗话说得好: 军功章上有你的一半也有我的一半

这篇关于愚蠢的代码?某程序员强行编写了一段开发阶段无法调试的代码,大佬们快来救救他!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/134

相关文章

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

在C#中调用Python代码的两种实现方式

《在C#中调用Python代码的两种实现方式》:本文主要介绍在C#中调用Python代码的两种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#调用python代码的方式1. 使用 Python.NET2. 使用外部进程调用 Python 脚本总结C#调

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

电脑win32spl.dll文件丢失咋办? win32spl.dll丢失无法连接打印机修复技巧

《电脑win32spl.dll文件丢失咋办?win32spl.dll丢失无法连接打印机修复技巧》电脑突然提示win32spl.dll文件丢失,打印机死活连不上,今天就来给大家详细讲解一下这个问题的解... 不知道大家在使用电脑的时候是否遇到过关于win32spl.dll文件丢失的问题,win32spl.dl

Java中&和&&以及|和||的区别、应用场景和代码示例

《Java中&和&&以及|和||的区别、应用场景和代码示例》:本文主要介绍Java中的逻辑运算符&、&&、|和||的区别,包括它们在布尔和整数类型上的应用,文中通过代码介绍的非常详细,需要的朋友可... 目录前言1. & 和 &&代码示例2. | 和 ||代码示例3. 为什么要使用 & 和 | 而不是总是使

pip无法安装osgeo失败的问题解决

《pip无法安装osgeo失败的问题解决》本文主要介绍了pip无法安装osgeo失败的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 进入官方提供的扩展包下载网站寻找版本适配的whl文件注意:要选择cp(python版本)和你py

Java强制转化示例代码详解

《Java强制转化示例代码详解》:本文主要介绍Java编程语言中的类型转换,包括基本类型之间的强制类型转换和引用类型的强制类型转换,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录引入基本类型强制转换1.数字之间2.数字字符之间引入引用类型的强制转换总结引入在Java编程语言中,类型转换(无论