使用原始命令编译打包部署springboot-demo项目
创始人
2024-05-21 10:25:59
0

目录

  • 简介
  • 源文件介绍
  • 编译
    • 编译restful-common
    • 编译manual-springboot
  • 打包&部署&执行
    • jar命令介绍
    • 不打包直接运行
    • 打普通jar包,通过java -jar运行
    • 打fat jar通过java -jar
    • 打war,通过部署至tomcat运行
  • 纯手工命令开发打包部署的缺点
  • 参考

简介

本文将使用jdk命令进行java文件编译、打包、部署启动

  • 编译:使用javac进行编译
  • 打包:使用jar分别打jar包、war包
  • 部署执行:使用直接java -jar执行jar包、使用tomcat+war包

源文件介绍

以下是目录和源文件,一共有三个源文件。这个目录不是生成的,就是我的个人习惯自己创建的目录

|manual-springboot
| |____classes 
| |____lib 
| |____src 
| | |____Application.java|restful-common
| |____classes
| |____src
| | |____ResultFactory.java
| | |____Result.java
package com.jaan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.jaan.restful.common.*;
@SpringBootApplication
@Controller
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}@PostMapping("/hello")@ResponseBodypublic Result hello(){return ResultFactory.succ();}}
package com.jaan.restful.common;public class Result{private String code;private String errorCode;private String errorDesc;public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getErrorCode() {return errorCode;}public void setErrorCode(String errorCode) {this.errorCode = errorCode;}public String getErrorDesc() {return errorDesc;}public void setErrorDesc(String errorDesc) {this.errorDesc = errorDesc;}public Result(String code, String errorCode, String errorDesc) {this.code = code;this.errorCode = errorCode;this.errorDesc = errorDesc;}}
package com.jaan.restful.common;public class ResultFactory{public static Result succ(){return new Result("1",null,null);}
}

编译

Application 中import了spring的好多类,我们怎么知道import哪些类呢,我这是直接从其他spring项目中复制的。当我们使用三方代码的时候,我们肯定能先拿到三方的jar包或者文档,阅读后才知道如何使用才会再去使用的,所以这种情况下肯定知道import什么。如果我们使用了别人的代码,但是没有import,这种情况下进行编译会出错的,如我把Application.java中的import全部删掉,进行编译javac -d classes src/*,如下报错

jaan@zhangdeshuaideMacBook-Pro manual-springboot % javac -d classes src/*
src/Application.java:3: 错误: 找不到符号
@SpringBootApplication^符号: 类 SpringBootApplication
src/Application.java:4: 错误: 找不到符号
@Controller^符号: 类 Controller
src/Application.java:12: 错误: 找不到符号public Result hello(){^符号:   类 Result位置: 类 Application
src/Application.java:10: 错误: 找不到符号@PostMapping("/hello")^符号:   类 PostMapping位置: 类 Application
src/Application.java:11: 错误: 找不到符号@ResponseBody^符号:   类 ResponseBody位置: 类 Application
src/Application.java:7: 错误: 找不到符号SpringApplication.run(Application.class, args);^符号:   变量 SpringApplication位置: 类 Application
src/Application.java:13: 错误: 找不到符号return ResultFactory.succ();^符号:   变量 ResultFactory位置: 类 Application
7 个错误

原因是我们使用了别人的类但是没有进行import导致的,只有在使用java基础类库或者与源文件同包或是源文件子包下的类的时候才不用import。

我们撤销掉刚才的删除的import,即此时的代码就是上文源文件介绍中贴出的源码,再次编译javac -d classes src/*

jaan@zhangdeshuaideMacBook-Pro manual-springboot % javac -d classes src/*
src/Application.java:2: 错误: 程序包org.springframework.boot不存在
import org.springframework.boot.SpringApplication;^
src/Application.java:3: 错误: 程序包org.springframework.boot.autoconfigure不存在
import org.springframework.boot.autoconfigure.SpringBootApplication;^
src/Application.java:4: 错误: 程序包org.springframework.stereotype不存在
import org.springframework.stereotype.Controller;^
src/Application.java:5: 错误: 程序包org.springframework.web.bind.annotation不存在
import org.springframework.web.bind.annotation.PostMapping;^
src/Application.java:6: 错误: 程序包org.springframework.web.bind.annotation不存在
import org.springframework.web.bind.annotation.ResponseBody;^
src/Application.java:7: 错误: 程序包com.jaan.restful.common不存在
import com.jaan.restful.common.*;
^
src/Application.java:8: 错误: 找不到符号
@SpringBootApplication^符号: 类 SpringBootApplication
src/Application.java:9: 错误: 找不到符号
@Controller^符号: 类 Controller
src/Application.java:17: 错误: 找不到符号public Result hello(){^符号:   类 Result位置: 类 Application
src/Application.java:15: 错误: 找不到符号@PostMapping("/hello")^符号:   类 PostMapping位置: 类 Application
src/Application.java:16: 错误: 找不到符号@ResponseBody^符号:   类 ResponseBody位置: 类 Application
src/Application.java:12: 错误: 找不到符号SpringApplication.run(Application.class, args);^符号:   变量 SpringApplication位置: 类 Application
src/Application.java:18: 错误: 找不到符号return ResultFactory.succ();^符号:   变量 ResultFactory位置: 类 Application
13 个错误

这次多了程序包xxx不存在的报错,找不到符号的错误依然存在的原因就是因为import的包没找到,所以符号依然找不到,如果包找到了,那么这些错误都将会被解决

为什么会报程序包xxx不存在呢?

是因为javac在编译的时候搜索类是按这样顺序搜索的①在当前路径下搜索②如果有使用-cp(-classpath)参数则在-cp指定的路径下搜索③若没有使用-cp则读取环境变量CLASSPATH的值进行搜索,②和③只会执行一个

我们刚才的命令为javac -d classes src/*没有使用-cp执行classpath,我的电脑也没有设置CLASSPATH。所有只在当前路径下搜索,但是没有搜索到,所以就报错了


编译restful-common

因为manual-springboot依赖restful-common,故我们切到restful-common目录下先编译restful-common,因为restful-common没有使用包外的任何类,所以直接执行javac -d classes src/*-d是指定编译后class文件保存的目录地址

编译manual-springboot

我们将所有import类所在的jar包下载(我是从其他项目里复制的)并放入lib目录下,图片中是lib中的所有包
lib包

在manual-springboot目录下执行javac -cp classes:lib/spring-boot-2.3.2.RELEASE.jar:lib/spring-boot-autoconfigure-2.1.6.RELEASE.jar:lib/spring-web-5.1.8.RELEASE.jar:lib/spring-context-5.2.8.RELEASE.jar:lib/spring-core-5.2.8.RELEASE.jar:lib/spring-beans-5.2.8.RELEASE.jar:lib/spring-jcl-5.2.8.RELEASE.jar:lib/spring-aop-5.2.8.RELEASE.jar:lib/spring-expression-5.2.8.RELEASE.jar:lib/spring-boot-starter-tomcat-2.1.6.RELEASE.jar:lib/spring-boot-starter-web-2.1.6.RELEASE.jar:lib/spring-webmvc-5.1.8.RELEASE.jar:lib/tomcat-embed-core-9.0.21.jar:lib/javax.annotation-api-1.3.2.jar:lib/tomcat-embed-websocket-9.0.21.jar:lib/spring-boot-starter-2.1.6.RELEASE.jar:../restful-common/classes -d classes src/Application.java
至此,编译完成。

javac的-cp后面跟的参数是有说法的,我当时在这里踩了几个坑,①-cp会面跟的只能包含class文件夹的地址或归档文件的文件地址,这里不是对应的class文件名,而是放class文件的文件夹名,但是如果是归档文件的话,可以放文件地址;②如果有多个路径的时候使用分隔符分割,这个分隔符不同的操作系统可能是不一样的,在Linux中,用“:”分隔classpath,而在windows中,用“;”分隔
-cp <路径> 指定查找用户类文件和注释处理程序的位置

此外,我只编译了restful-common,并没有将restful-common的class文件打包放入manual-springboot的lib,从我上面的javac命令中也可以看出我写的是文件夹的路径 …/restful-common/classes,如果打了jar包,这里也可以写成jar文件的地址

打包&部署&执行

  • 无论打jar还是打war,都是使用jar命令,自己的目录是啥样打完的包里的目录结构就是啥样
  • 通过java -jar执行,所有环境变量和命令行指定的搜索路径都将被忽略,除了java基础包中的类外,其他类的只从指定运行的jar中搜搜索

jar命令介绍

用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
选项:-c  创建新档案-t  列出档案目录-x  从档案中提取指定的 (或所有) 文件-u  更新现有档案-v  在标准输出中生成详细输出-f  指定档案文件名-m  包含指定清单文件中的清单信息-n  创建新档案后执行 Pack200 规范化-e  为捆绑到可执行 jar 文件的独立应用程序指定应用程序入口点-0  仅存储; 不使用任何 ZIP 压缩-P  保留文件名中的前导 '/' (绝对路径) 和 ".." (父目录) 组件-M  不创建条目的清单文件-i  为指定的 jar 文件生成索引信息-C  更改为指定的目录并包含以下文件 #跟两个参数 一个是目录 第二个是这个目录下的那个文件或目录
如果任何文件为目录, 则对其进行递归处理。
清单文件名, 档案文件名和入口点名称的指定顺序
与 'm', 'f' 和 'e' 标记的指定顺序相同。示例 1: 将两个类文件归档到一个名为 classes.jar 的档案中: jar cvf classes.jar Foo.class Bar.class 
示例 2: 使用现有的清单文件 'mymanifest' 并将 foo/ 目录中的所有文件归档到 'classes.jar' 中: jar cvfm classes.jar mymanifest -C foo/ .

不打包直接运行

在不打包的情况下我们可以直接通过java -cp xxxxx:xxxx:xxx com.jaan.Application方式运行

jaan@zhangdeshuaideMacBook-Pro manual-springboot % java -cp classes:lib/spring-boot-2.3.2.RELEASE.jar:lib/spring-boot-autoconfigure-2.1.6.RELEASE.jar:lib/spring-web-5.1.8.RELEASE.jar:lib/spring-context-5.2.8.RELEASE.jar:lib/spring-core-5.2.8.RELEASE.jar:lib/spring-beans-5.2.8.RELEASE.jar:lib/spring-jcl-5.2.8.RELEASE.jar:lib/spring-aop-5.2.8.RELEASE.jar:lib/spring-expression-5.2.8.RELEASE.jar:lib/spring-boot-starter-tomcat-2.1.6.RELEASE.jar:lib/spring-boot-starter-web-2.1.6.RELEASE.jar:lib/spring-webmvc-5.1.8.RELEASE.jar:lib/tomcat-embed-core-9.0.21.jar:lib/javax.annotation-api-1.3.2.jar:lib/tomcat-embed-websocket-9.0.21.jar:lib/spring-boot-starter-2.1.6.RELEASE.jar:../restful-common/classes  com.jaan.Application.   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v2.3.2.RELEASE)[2023-01-16 19:34:00.188] - 99179 信息 [main] --- com.jaan.Application: Starting Application on zhangdeshuaideMacBook-Pro.local with PID 99179 (/Users/jaan/code/manual/manual-springboot/classes started by jaan in /Users/jaan/code/manual/manual-springboot)

打普通jar包,通过java -jar运行

jar包指定Main-Class的方式有两种,可以通过自己创建META-INF/MENIFEST.MF并将Main-Class写入,也可以通过-e参数指定Main-Class,让jar命令帮我们生成META-INF/MENIFEST.MF

-C这个大C参数后跟两个参数 一个是目录 第二个是这个目录下的那个文件,通过用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files …可以看出,-C是应该写在所有的后面的

jaan@zhangdeshuaideMacBook-Pro manual-springboot % jar -cvfe manual-springboot.jar com.jaan.Application -C classes .
已添加清单
正在添加: .DS_Store(输入 = 6148) (输出 = 443)(压缩了 92%)
正在添加: com/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: com/jaan/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: com/jaan/Application.class(输入 = 908) (输出 = 504)(压缩了 44%)

我们打了jar包之后我们可以通过java -cp xxxxx:xxxx:xxx com.jaan.Application运行,也可以java -jar manual-springboot.jar运行,java -jar的方式,执行的是jar包中META-INF/MENIFEST.MF里的Main-Class的main方法

jaan@zhangdeshuaideMacBook-Pro manual-springboot % java -jar manual-springboot.jar 
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: com/jaan/restful/common/Resultat java.lang.Class.getDeclaredMethods0(Native Method)at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)at java.lang.Class.privateGetMethodRecursive(Class.java:3048)at java.lang.Class.getMethod0(Class.java:3018)at java.lang.Class.getMethod(Class.java:1784)at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:650)at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:632)
Caused by: java.lang.ClassNotFoundException: com.jaan.restful.common.Resultat java.net.URLClassLoader.findClass(URLClassLoader.java:382)at java.lang.ClassLoader.loadClass(ClassLoader.java:419)at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)at java.lang.ClassLoader.loadClass(ClassLoader.java:352)... 7 more

可以看到这样执行报错了,我们通过前面的编译经验可大概猜测应该是没有通过-cp指定其他的依赖导致的,那我们加上-cp就行了吗?

jaan@zhangdeshuaideMacBook-Pro manual-springboot % java -cp lib/spring-boot-2.3.2.RELEASE.jar:lib/spring-boot-autoconfigure-2.1.6.RELEASE.jar:lib/spring-web-5.1.8.RELEASE.jar:lib/spring-context-5.2.8.RELEASE.jar:lib/spring-core-5.2.8.RELEASE.jar:lib/spring-beans-5.2.8.RELEASE.jar:lib/spring-jcl-5.2.8.RELEASE.jar:lib/spring-aop-5.2.8.RELEASE.jar:lib/spring-expression-5.2.8.RELEASE.jar:lib/spring-boot-starter-tomcat-2.1.6.RELEASE.jar:lib/spring-boot-starter-web-2.1.6.RELEASE.jar:lib/spring-webmvc-5.1.8.RELEASE.jar:lib/tomcat-embed-core-9.0.21.jar:lib/javax.annotation-api-1.3.2.jar:lib/tomcat-embed-websocket-9.0.21.jar:lib/spring-boot-starter-2.1.6.RELEASE.jar:../restful-common/classes -jar manual-springboot.jar 
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: com/jaan/restful/common/Resultat java.lang.Class.getDeclaredMethods0(Native Method)at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)at java.lang.Class.privateGetMethodRecursive(Class.java:3048)at java.lang.Class.getMethod0(Class.java:3018)at java.lang.Class.getMethod(Class.java:1784)at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:650)at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:632)
Caused by: java.lang.ClassNotFoundException: com.jaan.restful.common.Resultat java.net.URLClassLoader.findClass(URLClassLoader.java:382)at java.lang.ClassLoader.loadClass(ClassLoader.java:419)at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)at java.lang.ClassLoader.loadClass(ClassLoader.java:352)... 7 more

答案是不行的,因为如下对-jar的使用介绍
“-jar filename
执行封装在 JAR 文件中的程序。参数是带有清单的 JAR 文件的filename名称,清单中包含一行定义类和用作应用程序起点的方法的表单。当您使用该选项时,指定的 JAR 文件是所有用户类的源,其他类路径设置将被忽略。”

jar包中META-INF/MENIFEST.MF里有一个参数是Class-Path,我们这里可以写我们依赖的类路径。回想之前我们在只指定Main-Class的时候,我们可以通过-e的方式指定,这种方式jar命令会自动帮我们创建一个含有Main-Class的META-INF/MENIFEST.MF,可以不手工创建META-INF/MENIFEST.MF。我们现在要指定Class-Path了,jar命令没有选项给我们让我们指定Class-Path,只能自己手动生成META-INF/MENIFEST.MF然后自己填写MENIFEST.MF的内容然后-m选项来指定MENIFEST.MF文件
我们将我们依赖的地址类路径或jar包通过空格分割写入Class-Path,如下

Main-Class: com.jaan.Application
Class-Path: lib/spring-boot-2.3.2.RELEASE.jar lib/spring-boot-autoconfigure-2.1.6.RELEASE.jar lib/spring-web-5.1.8.RELEASE.jar lib/spring-context-5.2.8.RELEASE.jar lib/spring-core-5.2.8.RELEASE.jar lib/spring-beans-5.2.8.RELEASE.jar lib/spring-jcl-5.2.8.RELEASE.jar lib/spring-aop-5.2.8.RELEASE.jar lib/spring-expression-5.1.8.RELEASE.jar lib/spring-boot-starter-tomcat-2.1.6.RELEASE.jar lib/spring-boot-starter-web-2.1.6.RELEASE.jar lib/spring-webmvc-5.1.8.RELEASE.jar lib/tomcat-embed-core-9.0.21.jar lib/javax.annotation-api-1.3.2.jar lib/tomcat-embed-websocket-9.0.21.jar lib/spring-boot-starter-2.1.6.RELEASE.jar ../restful-common/restful-common.jar #也可以是../restful-common/classes/但是../restful-common/classes不行
  • 记着要换行不然打包的时候会报错:java.io.IOException: line too long
  • 并且使用了-m,并且MENIFEST.MF中含有Main-Class的话就不能使用-e,不然会报错:不能同时指定 'e' 标记和具有 'Main-Class' 属性的清单!
  • Class-Path分多行写时注意:从第二行开始,必须以两个空格开头,不用空格开头和一个空格开头都是不行的,我已经试过了。
  • Class-Path中的各项应使用空格分隔,不是逗号或分号。
  • Class-Path写完之后最后一定要有一个空行
  • jar包内有些配置文件想放在jar包外面,比如文件config.properties:如果这个文件是以路径方式载入的,比如new file(“./config/config.properties”),那么将config.properties放在jar包相同目录下的config目录下即可,也就是说“./”路径等价于jar包所在目录;如果这个文件是以ClassPath下的文件这种方式载入的,比如在Spring中载入classpath:config.properties,则在MF文件的配置文件的ClassPath中添加“./”,然后将这个配置文件与jar包放在同一个目录即可,当然也可以在MF文件的配置文件的ClassPath中添加“./config/”,然后把配置文件都放在jar包相同目录下的config目录下
  • MENIFEST.MF中Class-Path下填写class文件的目录的时候必须写成这样…/restful-common/classes/,最后的/一定要有不然查找不到类,这里跟java -cp指定class文件目录的时候有区别,java -cp指定的时候目录最后的/写不写都可以
jaan@zhangdeshuaideMacBook-Pro manual-springboot % java -jar manual-springboot.jar.   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v2.3.2.RELEASE)[2023-01-30 16:09:52.412] - 21000 信息 [main] --- com.jaan.Application: Starting Application on zhangdeshuaideMacBook-Pro.local with PID 21000 (/Users/jaan/code/manual/manual-springboot/manual-springboot.jar started by jaan in /Users/jaan/code/manual/manual-springboot)
[2023-01-30 16:09:52.423] - 21000 信息 [main] --- com.jaan.Application: No active profile set, falling back to default profiles: default
[2023-01-30 16:09:53.019] - 21000 警告 [main] --- org.apache.tomcat.util.modeler.Registry: The MBean registry cannot be disabled because it has already been initialised
[2023-01-30 16:09:53.091] - 21000 信息 [main] --- org.springframework.boot.web.embedded.tomcat.TomcatWebServer: Tomcat initialized with port(s): 8080 (http)
[2023-01-30 16:09:53.111] - 21000 信息 [main] --- org.apache.catalina.core.StandardService: Starting service [Tomcat]
[2023-01-30 16:09:53.112] - 21000 信息 [main] --- org.apache.catalina.core.StandardEngine: Starting Servlet engine: [Apache Tomcat/9.0.21]
[2023-01-30 16:09:53.177] - 21000 信息 [main] --- org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]: Initializing Spring embedded WebApplicationContext
[2023-01-30 16:09:53.177] - 21000 信息 [main] --- org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext: Root WebApplicationContext: initialization completed in 717 ms
[2023-01-30 16:09:53.297] - 21000 信息 [main] --- org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor: Initializing ExecutorService 'applicationTaskExecutor'
[2023-01-30 16:09:53.440] - 21000 信息 [main] --- org.springframework.boot.web.embedded.tomcat.TomcatWebServer: Tomcat started on port(s): 8080 (http) with context path ''
[2023-01-30 16:09:53.454] - 21000 信息 [main] --- com.jaan.Application: Started Application in 1.307 seconds (JVM running for 1.528

打fat jar通过java -jar

  • fat jar就是胖jar,也就是说这个jar里就包含运行时需要的所有类,包括依赖包。
    虽然上节里的也是java -jar,但是跟这节的还是有区别的,区别就是,上节jar包里MENIFEST.MF存在Class-Path,且指定的都是jar包外的目录或其他jar包。
  • jar 包里嵌套其他 jar,这个方法可以彻底避免解压同名覆盖的问题,但是这个方法不被 JVM 原生支持,因为 JDK 提供的 ClassLoader 仅支持装载嵌套 jar 包的 class 文件。所以这种方法需要自定义 ClassLoader 以支持嵌套 jar。

故打这种包是需要自定义ClassLoader并在MENIFEST.MF存在Class-Path指定出的,所以一般我们不会自己写,都是使用插件来进行打包,插件将会把他们开发好的自定义ClassLoader的这套代码来放到我们的jar里,并且以他们自定义ClassLoader约定的目录格式来打包,如果我们不用插件的话,这相当于我们自己开发了个软件,这个软件是专门读取jar包里嵌套jar包的,还有就是我们需要自己将jar包的目录调整到ClassLoader代码里约定的结构。如果使用插件的话这些工作全部自动完成。

本文不进行打fat jar实操,下面我放一个打完的springboot项目的fat jar里的目录结构及个别文件内容
顶级目录就是这三个BOOT-INF、META-INF、org在这里插入图片描述

|____org
| |____springframework
| | |____boot
| | | |____loader
| | | | |____archive
| | | | | |____*****.class(很多class文件)
| | | | |____util
| | | | | |____SystemPropertyUtils.class
| | | | |____jar
| | | | | |____******.class(很多class文件)
| | | | |____PropertiesLauncher$PrefixMatchingArchiveFilter.class
| | | | |____MainMethodRunner.class
| | | | |____PropertiesLauncher$1.class
| | | | |____JarLauncher.class
| | | | |____LaunchedURLClassLoader.class
| | | | |____WarLauncher.class
| | | | |____ExecutableArchiveLauncher.class
| | | | |____Launcher.class
| | | | |____PropertiesLauncher$ArchiveEntryFilter.class
|____LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
| | | | |____data
| | | | | |____RandomAccessData.class
| | | | | |____RandomAccessDataFile.class
| | | | | |____RandomAccessDataFile$1.class
| | | | | |____RandomAccessDataFile$DataInputStream.class
| | | | | |____RandomAccessDataFile$FileAccess.class
| | | | |____PropertiesLauncher.class
|____META-INF
| |____MANIFEST.MF
| |____maven
| | |____com.iboxchain.goodarights
| | | |____pay-web
| | | | |____pom.xml
| | | | |____pom.properties
| |____build-info.properties
| |____dubbo
| | |____com.alibaba.dubbo.rpc.Filter
|____BOOT-INF(我们自己写的代码和配置文件,代码略,部分配置文件略)
| |____classes
| | |____mybatis
| | | |____mybatis-config.xml
| | |____errorCode.properties
| | |____dubbo
| | | |____applicationContext-dubbo-provider.xml
| | | |____applicationContext-dubbo.xml
| | | |____dubbo-provider-biz.xml
| | |____com(我们的代码-略)
| |____lib(所有依赖的jar包都在这里)
| | |____*******.jar

下面是MANIFEST.MF文件的内容

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: appl
Start-Class: com.iboxchain.goodarights.pay.Application
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 2.1.6.RELEASE
Created-By: Apache Maven 3.6.3
Build-Jdk: 1.8.0_65
Main-Class: org.springframework.boot.loader.JarLauncher

打war,通过部署至tomcat运行

如果是非.war的文件无反应
如果是.war的文件,可以部署,且支持热部署,也就是说不用重启tomcat,只要你丢进去webappst里tomcat会检测到,然后进行部署,
如果是.war但是war里的文件目录结构不符合约定,则访问不了
如果.war里的无继承SpringBootServletInitializer无重写SpringApplicationBuilder configure(SpringApplicationBuilder application)则没有spring启动的日志,就好像部署了没任何反应。
此时浏览器访问http://localhost:8080/manual-springboot/hello
在这里插入图片描述

继承并重写之后出现spring日志,此时catalina.out报错:

  .   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v2.3.2.RELEASE)一月 30, 2023 9:33:55 下午 org.springframework.boot.SpringApplication reportFailure
严重: Application run failed
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.jaan.Application]; nested exception is java.lang.IllegalStateException: Fail
ed to introspect annotated methods on class com.jaan.Applicationat org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:188)at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:319)at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236)at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:280)at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:96)at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:707)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:533)at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143)at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758)at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750)at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:173)at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:153)at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:95)at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:171)at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5218)at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:753)at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:727)at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:695)at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1016)at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1903)at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: Failed to introspect annotated methods on class com.jaan.Applicationat org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods(StandardAnnotationMetadata.java:162)at org.springframework.context.annotation.ConfigurationClassParser.retrieveBeanMethodMetadata(ConfigurationClassParser.java:402)at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:325)at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:249)at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:206)at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:174)... 27 more
Caused by: java.lang.IllegalStateException: Failed to introspect Class [com.jaan.Application] from ClassLoader [ParallelWebappClassLoadercontext: manual-springbootdelegate: false
----------> Parent Classloader:
java.net.URLClassLoader@e9e54c2
]at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:481)at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:455)at org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods(StandardAnnotationMetadata.java:151)... 32 more
Caused by: java.lang.NoClassDefFoundError: com/jaan/restful/common/Resultat java.lang.Class.getDeclaredMethods0(Native Method)at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)at java.lang.Class.getDeclaredMethods(Class.java:1975)at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463)... 34 more
Caused by: java.lang.ClassNotFoundException: com.jaan.restful.common.Resultat org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1420)at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1228)... 38 more

根据报错看出应该是打的war包中缺少了com.jaan.restful.common.Result类的jar包,将该jar包放入manual-springboot/war/WEB-INF/lib下,重新打包

重新打包后catalina.out日志无报错,但只有spring logo

  .   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v2.3.2.RELEASE)30-Jan-2023 21:50:39.214 信息 [localhost-startStop-6] org.apache.catalina.startup.HostConfig.deployWAR web应用程序存档文件[/Library/tomcat-8.5.84/webapps/manual-springboot.war]的部
署已在[2,419]ms内完成

此时浏览器访问http://localhost:8080/manual-springboot/hello
在这里插入图片描述
说明项目是部署成功了,只是浏览器请求hello接口的时候项目报错了而已

纯手工命令开发打包部署的缺点

参考

  1. https://blog.csdn.net/bible_reader/article/details/105110864
  2. https://blog.csdn.net/sayyy/article/details/81120749
  3. https://docs.oracle.com/javase/10/tools/java.htm#JSWOR624
  4. https://blog.csdn.net/wter26/article/details/104758345/

相关内容

热门资讯

最绚丽的安卓系统,最绚丽版本全... 哇,你知道吗?在安卓的世界里,有一款系统,它就像是一颗璀璨的明珠,闪耀着最绚丽的色彩。它就是——最绚...
小米系统安卓通知权限,深度解析... 亲爱的手机控们,你是否曾为手机通知栏里乱糟糟的信息而烦恼?又或者,你是否好奇过,为什么有些应用总是能...
安卓7.0系统能玩吗,体验全新... 你有没有想过,你的安卓手机升级到7.0系统后,那些曾经陪伴你度过无数时光的游戏,还能不能继续畅玩呢?...
平板安卓系统哪家好,安卓平板系... 你有没有想过,在这个科技飞速发展的时代,拥有一台性能出色的平板电脑是多么重要的事情呢?想象无论是追剧...
安卓好的点歌系统,打造个性化音... 你有没有想过,在安卓手机上,点歌系统竟然也能如此精彩?没错,就是那个我们每天都会用到,却又常常忽略的...
熊猫安卓系统直播软件,解锁互动... 你知道吗?最近有个超级酷炫的直播软件在熊猫迷们中间火得一塌糊涂!它就是熊猫安卓系统直播软件。别看它名...
安卓点播系统开发,Androi... 你有没有想过,手机里那些让你爱不释手的视频,其实背后有着一套复杂的安卓点播系统在默默支撑呢?今天,就...
安卓6.0系统加权限,深度解析... 你有没有发现,自从手机升级到安卓6.0系统后,权限管理变得超级严格呢?这可真是让人又爱又恨啊!今天,...
哪些电视带安卓系统,多款热门智... 你有没有想过,家里的电视竟然也能装上安卓系统?听起来是不是有点不可思议?没错,现在市面上就有不少电视...
苹果怎么运用安卓系统,揭秘如何... 你知道吗?最近有个大新闻在科技圈里炸开了锅,那就是苹果竟然开始运用安卓系统了!是不是觉得有点不可思议...
安卓系统能转什么系统好,探索最... 你有没有想过,你的安卓手机是不是也能换换口味,体验一下其他系统的魅力呢?没错,今天就来聊聊这个话题:...
龙之狂热安卓系统,释放龙族狂热 亲爱的手机控们,你是否曾为拥有一款独特的安卓系统而疯狂?今天,就让我带你走进一个充满奇幻色彩的龙之狂...
vivo手机安卓系统怎么升级系... 亲爱的手机控们,你是不是也和我一样,对手机的新功能充满期待呢?尤其是vivo手机的用户,是不是也在想...
鸿蒙2.0退回安卓系统,一场系... 你知道吗?最近科技圈里可是炸开了锅,因为华为的鸿蒙2.0操作系统竟然要退回安卓系统了!这可不是一个简...
安卓系统怎么复制卡,安卓系统卡... 你有没有遇到过这种情况:手机里的照片、视频或者重要文件,突然想备份到电脑上,却发现安卓系统的卡复制功...
app兼容低安卓系统,打造全民... 你有没有发现,现在手机APP更新换代的速度简直就像坐上了火箭!不过,你知道吗?有些APP可是特别贴心...
中间安卓系统叫什么,中间安卓系... 你有没有想过,安卓系统里竟然还有一个中间的版本?没错,就是那个让很多手机用户既熟悉又陌生的版本。今天...
安卓怎么用os系统,利用And... 你有没有想过,你的安卓手机其实可以变身成一个功能强大的操作系统呢?没错,就是那个我们平时在电脑上使用...
pe系统安卓能做么,探索安卓平... 亲爱的读者,你是否曾好奇过,那款在安卓设备上大受欢迎的PE系统,它究竟能做什么呢?今天,就让我带你一...
安卓 打印机系统,安卓打印机系... 你有没有想过,家里的安卓手机和打印机之间竟然能建立起如此紧密的联系?没错,就是那个安卓打印机系统!今...