title | date | tags | categories | ||
---|---|---|---|---|---|
Java应用的部署 |
2018-11-21 02:56:52 -0800 |
|
|
💠
-
- 1.1. 打包Jar
- 1.2. 打包可执行Jar
- 1.3. 打包War
- 1.4. 打包Docker镜像
-
- 2.1. 命令行参数
-
- 4.1. Java在Linux上的时区问题
- 4.2. 容器中Jvm信号及参数接收问题
💠 2025-01-10 16:30:07
传统的可执行jar, war 以及Docker镜像
- 平铺式
- 所有依赖的jar和自身项目class都平铺在目录里
- 运行main方法类
java -cp . xxx.Main
需要将资源所在目录都加入classpath
- FatJar
- 所有依赖和自身项目class都打包在一个jar里
java -jar app.jar
或者java -cp app.jar xxx.Main
(没有mainfest文件)
注意
- -cp -jar 混合使用时 -cp 会被忽略
关于MANIFEST.MF文件
这个文件很重要, 如果自己手动配置就需要编写该文件
MANIFEST.MF示例
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: kcp
Created-By: Apache Maven 3.5.3
Build-Jdk: 1.8.0_152
Main-Class: com.youaishujuhui.minigame.Main
- 编译文件
javac -d *.java
- 打包字节码成jar
jar -cvf hello.jar com/test/*.*
- 打包成可执行jar
jar -cvfm hello.jar mainfest *.*
- 其中
mainfest
文本文件:Main-Class: com.test.Main
- 冒号后一定要有空格,文件最后一行一定留空行
- 其中
FatJar 所有的依赖都在一个jar里
最终将生成的war 放到 tomcat 的 webapps 目录下或者 Jetty的 webapps 目录下
以一个基础镜像,然后将war放进去构建成一个镜像, 然后推送到服务器上构建容器进行运行
- 简要概括: from jdk基础镜像, 将jar 复制进去, 设置好 CMD
- 结合 Maven Gradle 能更方便的构建 Docker镜像
多目标应用环境的发布, 可以使用Maven 多 Profile; Spring 的多profiles; 环境变量; ...
在环境中存储配置
- 通常,应用的 配置 在不同 部署 (预发布、生产环境、开发环境等等)间会有很大差异。这其中包括:
- 数据库,Memcached,以及其他 后端服务 的配置
- 第三方服务的证书,如 Amazon S3、Twitter 等
- 每份部署特有的配置,如域名等
/**
* @param path 例如 传入 /redis/lock.lua 意味着: 读取SpringBoot打包成一个UberJar里某子模块的 resources 目录下的 redis/lock.lua 文件。
* 即使子模块被打包成jar被主模块依赖也不影响,因为文件在classpath的路径都是 /redis/lock.lua
*/
private static String readFile(String path) {
try {
InputStream is = RedisSemaphore.class.getResourceAsStream(path);
if (Objects.isNull(is)) {
throw new RuntimeException("NULL");
}
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String s;
StringBuilder bb = new StringBuilder();
while ((s = br.readLine()) != null) {
bb.append(s).append("\n");
}
return bb.toString();
} catch (Exception re) {
log.error("Load failed {}", path, re);
return "";
}
}
主流方案有:class混淆;加密class;花指令; 但是总结下来混淆是投入产出比最高的方案。
引入低成本且影响小,防护效果好(因为复杂业务本身难懂,混淆后更难理解了),并引申出别的用途(压缩apk大小😅)
obfuscation - Best Java obfuscator? - Stack Overflow
Open Source Obfuscators in Java
工具列表
Allatori Java Obfuscator - Professional Java Obfuscation
ProGuard Manual: Usage | Guardsquare
jar-analyzer/class-obf
难点在于即使自定义了类加载器,加载进JVM运行的时候内存上仍是明文字节,还是有手段dump到真实的class
encryption - How can you protect/encrypt your Java classes? - Stack Overflow
serengil/encrypted-class-loader: Enabling to run encrypted java classes
- 表象
- Docker容器中运行的Linux上时区是正确的, 但是Java应用的时区不对
- 原因
- JVM获取时区配置的顺序
- 查看 环境变量 TZ
export TZ=Asia/Shanghai
- /etc/sysconfig/clock 中查找 ZONE 的值
ZONE="Asia/Shanghai" UTC=false ARC=false
- /etc/localtime 或者 /usr/share/zoneinfo
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
- 也可以加JVM参数
-Duser.timezone=GMT+8
- 或者硬编码设置时区
快速测试Java获取到的时区
import java.util.Date;
import java.time.ZoneOffset;
public class TimeTest {
public static void main(String[] args){
System.out.println(new Date());
System.out.println(ZoneOffset.systemDefault());
}
}
需要避免Java进程为容器中的1号进程,因为会带来很多问题,包括但不限:
- 无法正常接收Linux信号量
- Arthas无法注入
- 无法合理管理派生出的进程生命周期
- JDK中的工具有些也会无法正常使用例如 jstack