使用原始命令编译打包部署springboot-demo项目

news2024/9/28 23:35:58

目录

  • 简介
  • 源文件介绍
  • 编译
    • 编译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")
	@ResponseBody
    public 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/Result
	at 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.Result
	at 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/Result
	at 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.Result
	at 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.Application
        at 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.Application
        at 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 [ParallelWebappClassLoader
  context: manual-springboot
  delegate: 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/Result
        at 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.Result
        at 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/

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

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

相关文章

CUDA编程笔记(7)

文章目录前言共享内存的合理使用数组归约计算使用全局内存的计算引入线程块中的同步函数使用共享内存计算静态共享内存使用动态共享内存性能比较避免共享内存的bank冲突使用共享内存进行数组转置bank概念性能比较总结前言 cuda共享内存的合理使用。 共享内存的合理使用 共享…

TF-A移植

1.对tf-a源码进行解压 $> tar xfz tf-a-stm32mp-2.2.r2-r0.tar.gz 2.打补丁 $> for p in ls -1 ../*.patch; do patch -p1 < $p; done 3.配置交叉编译工具链 将Makefile.sdk中EXTRA_OEMAKE修改为 EXTRA_OEMAKECROSS_COMPILEarm-linux-gnueabihf- 4.复制设备树…

linux 部署jmeter

一、linux 安装jdk Java Downloads | Oracle 二、 linux上传jmeter 2.1 上传jmeter jmeter 下载地址&#xff1a; Apache JMeter - Download Apache JMeter 注意&#xff1a; 我先在我本地调试脚本&#xff08;mac环境&#xff09;&#xff0c;调试完成后&#xff0c;再在…

前端首屏优化

一. 打包分析 在 package.json 中添加命令 “report”: “vue-cli-service build --report” 然后命令行执行 npm run report&#xff0c;就会在dist目录下生成一个 report.html 文件&#xff0c;右键浏览器中打开即可看到打包分析报告。 二. 路由懒加载 component: () >…

MacOS - steam 蒸汽平台安装教程,带你躲避高仿网站的陷阱

MacOS - steam 蒸汽平台安装教程 MacOS 其实也是可以安装 Steam 平台的&#xff0c;虽然 steam 上的大多游戏暂时都不支持 MacOS&#xff0c;但还是有一些游戏可以玩的&#xff0c;而且近几年支持 MacOS 的游戏也是越来越多了。另外现在高仿网站特别多&#xff0c;所以才有了这…

transformer库使用

Transformer库简介 是一个开源库&#xff0c;其提供所有的预测训练模型&#xff0c;都是基于transformer模型结构的。 Transformer库 我们可以使用 Transformers 库提供的 API 轻松下载和训练最先进的预训练模型。使用预训练模型可以降低计算成本&#xff0c;以及节省从头开…

Grafana 系列文章(三):Tempo-使用 HTTP 推送 Spans

&#x1f449;️URL: https://grafana.com/docs/tempo/latest/api_docs/pushing-spans-with-http/ &#x1f4dd;Description: 有时&#xff0c;使用追踪系统是令人生畏的&#xff0c;因为它似乎需要复杂的应用程序仪器或 span 摄取管道&#xff0c;以便 ... 有时&#xff0c;使…

SurfaceFlinger学习笔记(七)之SKIA

关于Surface请参考下面文章 SurfaceFlinger学习笔记(一)应用启动流程 SurfaceFlinger学习笔记(二)之Surface SurfaceFlinger学习笔记(三)之SurfaceFlinger进程 SurfaceFlinger学习笔记(四)之HWC2 SurfaceFlinger学习笔记(五)之HWUI SurfaceFlinger学习笔记(六)之View Layout Dr…

react 实现表格列表拖拽排序

问题描述 在项目开发中&#xff0c;遇到这样一个需求&#xff1a;需要对表格里面的数据进行拖拽排序。 效果图如下所示&#xff1a; 思路 安装两个插件&#xff1a; react-sortable-hoc &#xff08;或者 react-beautiful-dnd&#xff09;array-move npm install --save r…

59 多线程环境普通变量作为标记循环不结束

前言 最近看到这篇例子的时候, [讨论] 内存可见性问题, 吧其中的 demo 拿到本地来跑 居然 和楼主一样, testBasicType 这里面的这个子线程 居然 不结束了, 卧槽 我还以为 只是可能 用的时间稍微长一点 哪知道 直接 无限期执行下去了, 然后 另外还有一个情况就是 加上了 -…

Segmenter论文解读

Segmenter: Transformer for Semantic Segmentation 论文&#xff1a;[2105.05633] Segmenter: Transformer for Semantic Segmentation (arxiv.org) 代码&#xff1a;[rstrudel/segmenter: ICCV2021] Official PyTorch implementation of Segmenter: Transformer for Semanti…

vue3+ts error TS7053:

在远程仓库拉取线上正常运行的项目&#xff0c;编译之后出现报错出现问题&#xff0c;逐步排查node版本是否与别人一致2.检查node_modules是否与别人一致检查到这一步就发现了是因为依赖版本不一致导致的原因因为目前vue-tsc等依赖更新频繁把这两个依赖的版本号锁死&#xff0c…

vuex

目录 1、什么是vuex 2、vuex的工作方式 3、vuex的使用场景 4、工作流程&#xff1a;View -> Actions -> Mutations -> State -> View 5、vuex的核心API ​ &#xff08;1&#xff09;state&#xff1a; ​ &#xff08;2&#xff09;mutations ​ &#xff…

Pinia的使用(以vue3+ts+vite为例)

文章目录Pinia1. 安装2. 引入vue33. 初始化store仓库4. 修改state5. 解构store6. store中的方法和计算属性&#xff08;actions、getters&#xff09;7. API7.1 $reset7.2 $subscribe 和 $onAction8. 插件案例&#xff1a;持久化插件Pinia Pinia官方文档 Pinia GitHub地址 1…

VSCode vscode-pandoc插件将中文Markdown转换为好看的pdf文档(使用eisvogel模板)

Markdown的使用经常需要转变其他格式&#xff0c;在VSCode里有个很好用的插件&#xff1a;vscode-pandoc&#xff0c;先进行下载。 打开设置&#xff08;左下角的小齿轮&#xff09; 输入pandoc 在HTML Opt String中粘贴入&#xff1a; -s -t html5可将Markdown转换输出HTML。…

STL-----map的常见使用

1&#xff0c;MAP的说明Map是STL的一个关联容器&#xff0c;它提供一对一&#xff08;其中第一个可以称为关键字&#xff0c;每个关键字只能在map中出现一次&#xff0c;第二个可能称为该关键字的值&#xff09;的数据 处理能力&#xff0c;由于这个特性&#xff0c;它完成有可…

3.1.8 多态

文章目录1.概念2.特点3.入门案例练习4 多态的好处5 多态的使用6 练习&#xff1a;多态成员使用测试7 拓展7.1 综合案例7.2 多态为了统一调用标准7.3 静态变量和实例变量的区别7.4 向上转型和向下转型1.概念 多态是面向对象程序设计&#xff08;OOP&#xff09;的一个重要特征&…

【数据结构初阶】第三篇——单链表

链表的概念及其结构 初始化链表 打印单链表 增加结点 头插 尾插 在给定位置之前插入 在给定位置之后插入 删除结点 头删 尾删 删除给定位置的结点 查找数据 修改数据 链表的概念及其结构 基本概念 链表是一种物理存储结构上非连续&#xff0c;非顺序的存储结构&a…

盘点保护隐私安全的浏览器,密码锁屏这个功能,真香

在互联网时代&#xff0c;大家都比较关心自己的隐私安全。一些互联网公司和在线客服会跟踪用户的在线活动&#xff0c;收集用户的个人信息&#xff0c;有时候甚至因为个人的不良习惯导致信息泄露&#xff0c;因此选择隐私和安全性好的浏览器尤其重要。下面给大家介绍隐私安全做…

大数据技术架构(组件)11——Hive:日期函数

1.4.5、日期函数1.4.5.1、from_unixtimeselect from_unixtime(1638602968),from_unixtime(1638602968,yyyy-MM-dd HH:mm:SS),from_unixtime(1638602968,yyyy-MM-dd);1.4.5.2、unix_timestampselect unix_timestamp();1.4.5.3、to_dateselect to_date(2021-12-04 2021-12-04 15:…