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

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

文章目录

  • 一、开场白
    • 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

相关文章

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Redis实现高效内存管理的示例代码

《Redis实现高效内存管理的示例代码》Redis内存管理是其核心功能之一,为了高效地利用内存,Redis采用了多种技术和策略,如优化的数据结构、内存分配策略、内存回收、数据压缩等,下面就来详细的介绍... 目录1. 内存分配策略jemalloc 的使用2. 数据压缩和编码ziplist示例代码3. 优化的

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

Python从Word文档中提取图片并生成PPT的操作代码

《Python从Word文档中提取图片并生成PPT的操作代码》在日常办公场景中,我们经常需要从Word文档中提取图片,并将这些图片整理到PowerPoint幻灯片中,手动完成这一任务既耗时又容易出错,... 目录引言背景与需求解决方案概述代码解析代码核心逻辑说明总结引言在日常办公场景中,我们经常需要从 W

使用Spring Cache本地缓存示例代码

《使用SpringCache本地缓存示例代码》缓存是提高应用程序性能的重要手段,通过将频繁访问的数据存储在内存中,可以减少数据库访问次数,从而加速数据读取,:本文主要介绍使用SpringCac... 目录一、Spring Cache简介核心特点:二、基础配置1. 添加依赖2. 启用缓存3. 缓存配置方案方案

MySQL的配置文件详解及实例代码

《MySQL的配置文件详解及实例代码》MySQL的配置文件是服务器运行的重要组成部分,用于设置服务器操作的各种参数,下面:本文主要介绍MySQL配置文件的相关资料,文中通过代码介绍的非常详细,需要... 目录前言一、配置文件结构1.[mysqld]2.[client]3.[mysql]4.[mysqldum

Python多线程实现大文件快速下载的代码实现

《Python多线程实现大文件快速下载的代码实现》在互联网时代,文件下载是日常操作之一,尤其是大文件,然而,网络条件不稳定或带宽有限时,下载速度会变得很慢,本文将介绍如何使用Python实现多线程下载... 目录引言一、多线程下载原理二、python实现多线程下载代码说明:三、实战案例四、注意事项五、总结引

IDEA与MyEclipse代码量统计方式

《IDEA与MyEclipse代码量统计方式》文章介绍在项目中不安装第三方工具统计代码行数的方法,分别说明MyEclipse通过正则搜索(排除空行和注释)及IDEA使用Statistic插件或调整搜索... 目录项目场景MyEclipse代码量统计IDEA代码量统计总结项目场景在项目中,有时候我们需要统计

MySQL设置密码复杂度策略的完整步骤(附代码示例)

《MySQL设置密码复杂度策略的完整步骤(附代码示例)》MySQL密码策略还可能包括密码复杂度的检查,如是否要求密码包含大写字母、小写字母、数字和特殊字符等,:本文主要介绍MySQL设置密码复杂度... 目录前言1. 使用 validate_password 插件1.1 启用 validate_passwo

基于Python编写自动化邮件发送程序(进阶版)

《基于Python编写自动化邮件发送程序(进阶版)》在数字化时代,自动化邮件发送功能已成为企业和个人提升工作效率的重要工具,本文将使用Python编写一个简单的自动化邮件发送程序,希望对大家有所帮助... 目录理解SMTP协议基础配置开发环境构建邮件发送函数核心逻辑实现完整发送流程添加附件支持功能实现htm