📚 目录

信创全栈全景图:6层架构,一层都不能少
第一层:芯片与指令集——一切的根基
第二层:操作系统——国产OS的真实战力
第三层:数据库——国产DB百花齐放的选择之道
第四层:中间件——最容易被忽视的关键层
第五层:运行时与开发框架——JDK/SDK/框架的信创适配
第六层:应用层——全栈适配的最后一公里
全栈兼容性矩阵:哪些组合能跑,哪些会翻车
安全体系:国密算法全栈贯穿实战
总结与避坑清单

一、信创全栈全景图:6层架构,一层都不能少

1.1 全栈架构鸟瞰图

┌─────────────────────────────────────────────────────────────────────┐
│ 信创全栈自主可控技术体系 │
│ │
│ ┌──────────────── 第六层:应用层 ────────────────────┐ │
│ │ 政务系统 │ 金融核心 │ ERP/OA │ 电子公文 │ 门户 │ │
│ │ ── 适配要点:前端兼容、国密HTTPS、版式文件 ── │ │
│ └──────────────────────────┬────────────────────────┘ │
│ │ │
│ ┌──────────────── 第五层:运行时与框架 ──────────────┐ │
│ │ 毕昇JDK │ KAE加速 │ Spring适配 │ 前端引擎 │ │
│ │ ── 适配要点:JIT编译器、ARM64原生库 ── │ │
│ └──────────────────────────┬────────────────────────┘ │
│ │ │
│ ┌──────────────── 第四层:中间件 ────────────────────┐ │
│ │ 东方通TongWeb │ 宝兰德BES │ 金蝶天燕 │ 中创 │ │
│ │ ── 适配要点:Servlet规范、类加载、JNDI ── │ │
│ └──────────────────────────┬────────────────────────┘ │
│ │ │
│ ┌──────────────── 第三层:数据库 ────────────────────┐ │
│ │ 达梦DM8 │ 人大金仓 │ OceanBase │ 南大通用 │ TiDB │ │
│ │ ── 适配要点:SQL方言、驱动、ORM方言 ── │ │
│ └──────────────────────────┬────────────────────────┘ │
│ │ │
│ ┌──────────────── 第二层:操作系统 ──────────────────┐ │
│ │ 银河麒麟 │ 统信UOS │ 中科方德 │ openEuler │ │
│ │ ── 适配要点:内核版本、系统调用、包管理 ── │ │
│ └──────────────────────────┬────────────────────────┘ │
│ │ │
│ ┌──────────────── 第一层:芯片 ──────────────────────┐ │
│ │ 鲲鹏(ARM) │ 飞腾(ARM) │ 海光(x86) │ 龙芯(LoongArch)│ │
│ │ 兆芯(x86) │ 申威(SW64) │ │
│ │ ── 适配要点:指令集、字节序、SIMD加速 ── │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────── 横向贯穿:安全体系 ────────────────────┐ │
│ │ SM2(签名) │ SM3(哈希) │ SM4(加密) │ SM9(标识密码) │ │
│ │ 国密SSL │ 可信计算 │ 等保2.0 │ 密评 │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘

1.2 全栈替代的核心原则
原则 解释 反面教材
逐层验证 每一层都要独立验证兼容性,不能假设"上层兼容了下层就没问题" 只在 x86 上测了,上 ARM 服务器全崩

标准优先 优先选择遵循国际标准/国家标准的组件,减少厂商锁定 用了某厂商私有协议,换一家全废

灰度迁移 新老系统并行运行,逐步切流 一刀切上线,出问题无法回退

安全贯穿 国密算法从芯片层到应用层全栈支持 底层用了国密,应用层还在用 MD5

🧠 金句:
“信创不是简单的’换皮替代’,是整个技术栈的’基因重组’。”

二、第一层:芯片与指令集——一切的根基

2.1 国产芯片六大路线全景

┌─────────────────────────────────────────────────────────────┐
│ 国产芯片六大技术路线 │
│ │
│ ┌─────────────── ARM 阵营 ──────────────┐ │
│ │ │ │
│ │ 鲲鹏920(华为) 飞腾S2500(飞腾) │ │
│ │ ├─ ARMv8.2 架构 ├─ ARMv8.2 架构 │ │
│ │ ├─ 64核/2.6GHz ├─ 64核/2.1GHz │ │
│ │ ├─ 8通道DDR4 ├─ 8通道DDR4 │ │
│ │ ├─ 100GbE网络 ├─ PCIe 4.0 │ │
│ │ └─ 生态最成熟 └─ 政务市场主力 │ │
│ │ │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌─────────────── x86 阵营 ──────────────┐ │
│ │ │ │
│ │ 海光(AMD授权) 兆芯(VIA授权) │ │
│ │ ├─ x86_64 兼容 ├─ x86_64 兼容 │ │
│ │ ├─ 迁移成本最低 ├─ 性能偏弱 │ │
│ │ └─ 金融/央企首选 └─ 办公桌面为主 │ │
│ │ │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌─────────────── 自主指令集 ─────────────┐ │
│ │ │ │
│ │ 龙芯(LoongArch) 申威(SW64) │ │
│ │ ├─ 完全自主指令集 ├─ 自主指令集 │ │
│ │ ├─ 迁移成本最高 ├─ 超算/军工专用 │ │
│ │ └─ 自主可控程度最高 └─ 生态最薄弱 │ │
│ │ │ │
│ └────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

2.2 指令集差异对应用层的影响

很多人以为"芯片是底层的事,和应用开发没关系"。

大错特错!

我踩过一个坑:一个 C 语言写的加密库,在 x86 上跑得好好的,部署到鲲鹏 ARM 服务器上,计算结果全是错的。

原因:字节序(Endianness)和内存对齐方式不同。

// ============================================================
// 跨指令集兼容的代码示例
//
// 设计思想:
// 1. 永远不假设字节序,使用网络字节序(大端)作为传输标准
// 2. 永远不假设内存对齐,使用 packed 结构体或手动对齐
// 3. 使用编译期检测,自动适配不同平台
//
// ⚠️ 踩坑记录:
// - x86/x86_64 是小端序(Little-Endian)
// - ARM 默认小端序,但可配置为大端序
// - 申威 SW64 是大端序(Big-Endian)
// - 网络传输统一使用大端序
// ============================================================

ifndef CROSS_PLATFORM_COMPAT_H
define CROSS_PLATFORM_COMPAT_H

include <stdint.h>
include <string.h>

// ========== 编译期平台检测 ==========
// 💡 通过预处理器宏自动识别目标平台
// 避免运行时判断的开销

if defined(x86_64) || defined(_M_X64)
#define PLATFORM_X86_64 1
#define PLATFORM_NAME “x86_64”
elif defined(aarch64) || defined(_M_ARM64)
#define PLATFORM_AARCH64 1
#define PLATFORM_NAME “aarch64”
elif defined(__loongarch64)
#define PLATFORM_LOONGARCH 1
#define PLATFORM_NAME “loongarch64”
elif defined(sw_64)
#define PLATFORM_SW64 1
#define PLATFORM_NAME “sw64”
else
#error “Unsupported platform! 不支持的平台架构!”
endif

// ========== 字节序检测与转换 ==========
// 💡 不要硬编码假设平台字节序
// 使用编译期检测 + 运行时转换

static inline int is_little_endian(void) {
// 💡 经典的字节序检测方法
// 用一个 int 的最低字节判断
uint32_t test = 0x01020304;
return ((uint8_t*)&test)[0] == 0x04;
}

// 主机字节序 → 网络字节序(大端)
static inline uint32_t host_to_network_32(uint32_t host_val) {
if (is_little_endian()) {
// 小端 → 大端:字节翻转
return ((host_val & 0xFF000000) >> 24) |
((host_val & 0x00FF0000) >> 8) |
((host_val & 0x0000FF00) << 8) |
((host_val & 0x000000FF) << 24);
}
return host_val; // 已经是大端,不需要转换
}

static inline uint64_t host_to_network_64(uint64_t host_val) {
if (is_little_endian()) {
return ((host_val & 0xFF00000000000000ULL) >> 56) |
((host_val & 0x00FF000000000000ULL) >> 40) |
((host_val & 0x0000FF0000000000ULL) >> 24) |
((host_val & 0x000000FF00000000ULL) >> 8) |
((host_val & 0x00000000FF000000ULL) << 8) |
((host_val & 0x0000000000FF0000ULL) << 24) |
((host_val & 0x000000000000FF00ULL) << 40) |
((host_val & 0x00000000000000FFULL) << 56);
}
return host_val;
}

// ========== 内存对齐安全读取 ==========
// ⚠️ ARM 和 LoongArch 对未对齐内存访问会触发异常(Alignment Fault)
// x86 虽然容忍未对齐访问,但有性能惩罚
// 所以:永远不要假设指针是对齐的!

// 安全读取 uint32_t(不假设对齐)
static inline uint32_t safe_read_u32(const void* ptr) {
uint32_t val;
// 💡 memcpy 是安全的,编译器会优化为最高效的指令
// 不要用强制类型转换(uint32_t)ptr 在未对齐时会崩溃
memcpy(&val, ptr, sizeof(val));
return val;
}

// 安全写入 uint32_t
static inline void safe_write_u32(void* ptr, uint32_t val) {
memcpy(ptr, &val, sizeof(val));
}

// ========== SIMD 加速的跨平台抽象 ==========
// 💡 不同芯片的 SIMD 指令集不同:
// x86: SSE/AVX/AVX-512
// ARM: NEON/SVE
// LoongArch: LSX/LASX
// 这里用宏做编译期分发

if defined(PLATFORM_X86_64)
#include <immintrin.h> // AVX2 头文件

// 使用 AVX2 做批量 XOR 运算(加密场景常用)
static inline void simd_xor_256(
    const uint8_t* a, const uint8_t* b, uint8_t* out, size_t len) 
{
    size_t i = 0;
    // 💡 每次处理 32 字节(256 bit)
    for (; i + 32 <= len; i += 32) {
        __m256i va = _mm256_loadu_si256((const __m256i*)(a + i));
        __m256i vb = _mm256_loadu_si256((const __m256i*)(b + i));
        __m256i vr = _mm256_xor_si256(va, vb);
        _mm256_storeu_si256((__m256i*)(out + i), vr);
    }
    // 处理剩余不足 32 字节的部分
    for (; i < len; i++) {
        out[i] = a[i] ^ b[i];
    }
}

elif defined(PLATFORM_AARCH64)
#include <arm_neon.h> // NEON 头文件

// ARM NEON 版本:每次处理 16 字节(128 bit)
static inline void simd_xor_256(
    const uint8_t* a, const uint8_t* b, uint8_t* out, size_t len) 
{
    size_t i = 0;
    // 💡 NEON 寄存器是 128 bit,每次处理 16 字节
    // 循环两次达到和 AVX2 类似的吞吐
    for (; i + 16 <= len; i += 16) {
        uint8x16_t va = vld1q_u8(a + i);
        uint8x16_t vb = vld1q_u8(b + i);
        uint8x16_t vr = veorq_u8(va, vb);
        vst1q_u8(out + i, vr);
    }
    for (; i < len; i++) {
        out[i] = a[i] ^ b[i];
    }
}

else
// 回退:纯 C 实现(性能最差但最通用)
static inline void simd_xor_256(
const uint8_t* a, const uint8_t* b, uint8_t* out, size_t len)
{
for (size_t i = 0; i < len; i++) {
out[i] = a[i] ^ b[i];
}
}
endif

endif // CROSS_PLATFORM_COMPAT_H

2.3 Java 应用的跨芯片适配

好消息是:Java 应用天然跨平台。但坏消息是——JNI 本地库不跨平台。

// ============================================================
// Java 跨芯片适配:JNI 本地库加载策略
//
// 设计思想:
// 1. 根据运行时 CPU 架构自动加载对应的 native 库
// 2. 提供纯 Java 回退方案(性能低但保证可用)
// 3. 支持鲲鹏/飞腾(ARM64) + 海光/兆芯(x86_64) + 龙芯(LoongArch)
// ============================================================

package com.xinchuang.compat;

import java.io.;
import java.nio.file.
;
import java.util.Locale;

public class NativeLibraryLoader {

private static volatile boolean loaded = false;
private static volatile boolean useFallback = false;

/**
 加载平台相关的 native 库
 * 💡 加载策略:
 检测 CPU 架构(os.arch)
 从 JAR 包内提取对应架构的 .so 文件
 写入临时目录后加载
 如果找不到对应架构的库,使用纯 Java 回退
 * ⚠️ 易错点:
 - os.arch 在不同 JVM 上返回值不同
 x86_64 上可能是 "amd64" 或 "x86_64"
 ARM64 上可能是 "aarch64" 或 "arm64"
 - 临时目录的清理问题(JVM 退出时删除)
 - 并发加载的线程安全
 */
public static synchronized void loadLibrary(String libName) {
    if (loaded) return;

    String arch = detectArchitecture();
    String os = detectOS();
    
    // 构造库文件名:lib_crypto_aarch64.so / lib_crypto_amd64.so
    String libFileName = String.format(
        "lib_%s_%s.%s", libName, arch, 
        os.equals("windows") ? "dll" : "so"
    );

    try {
        // 从 classpath 提取 native 库到临时文件
        Path tempDir = Files.createTempDirectory("xinchuang_native_");
        Path tempLib = tempDir.resolve(libFileName);

        // 💡 库文件打包在 JAR 的 /native/<arch>/ 目录下
        String resourcePath = String.format(
            "/native/%s/%s", arch, libFileName
        );
        
        try (InputStream is = NativeLibraryLoader.class
                .getResourceAsStream(resourcePath)) {
            
            if (is == null) {
                // ⚠️ 找不到对应架构的 native 库
                // 回退到纯 Java 实现
                System.err.println(
                    "[NativeLoader] 未找到 " + arch + " 架构的 " + 
                    libName + " 库,使用纯Java回退方案(性能可能降低)"
                );
                useFallback = true;
                loaded = true;
                return;
            }
            
            Files.copy(is, tempLib, StandardCopyOption.REPLACE_EXISTING);
        }

        // 加载 native 库
        System.load(tempLib.toAbsolutePath().toString());
        loaded = true;
        
        // 注册 JVM 退出时的清理钩子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                Files.deleteIfExists(tempLib);
                Files.deleteIfExists(tempDir);
            } catch (IOException ignored) {}
        }));

        System.out.println(
            "[NativeLoader] 成功加载 " + libName + 
            " (" + arch + "/" + os + ")"
        );

    } catch (UnsatisfiedLinkError e) {
        // ⚠️ 库存在但加载失败(可能依赖了其他缺失的 .so)
        System.err.println(
            "[NativeLoader] 加载失败: " + e.getMessage() + 
            ",使用纯Java回退方案"
        );
        useFallback = true;
        loaded = true;
    } catch (IOException e) {
        throw new RuntimeException("Native库提取失败", e);
    }
}

/**
 检测 CPU 架构(标准化返回值)
 * ⚠️ 这个方法的返回值必须和 native 库目录名一一对应
 */
public static String detectArchitecture() {
    String arch = System.getProperty("os.arch", "")
        .toLowerCase(Locale.ROOT);
    
    // x86_64 / AMD64
    if (arch.contains("amd64") || arch.contains("x86_64")) {
        return "amd64";
    }
    // ARM64 / AArch64(鲲鹏、飞腾)
    if (arch.contains("aarch64") || arch.contains("arm64")) {
        return "aarch64";
    }
    // LoongArch64(龙芯)
    if (arch.contains("loongarch64")) {
        return "loongarch64";
    }
    // SW64(申威)
    if (arch.contains("sw_64") || arch.contains("sw64")) {
        return "sw64";
    }
    
    throw new UnsupportedOperationException(
        "不支持的CPU架构: " + arch + 
        " | 支持的架构: amd64, aarch64, loongarch64, sw64"
    );
}

private static String detectOS() {
    String os = System.getProperty("os.name", "")
        .toLowerCase(Locale.ROOT);
    if (os.contains("linux")) return "linux";
    if (os.contains("windows")) return "windows";
    return "unknown";
}

/**
 是否应该使用纯 Java 回退方案
 */
public static boolean shouldUseFallback() {
    return useFallback;
}

}

三、第二层:操作系统——国产OS的真实战力

3.1 四大国产OS对比
维度 银河麒麟V10 统信UOS V20 openEuler 中科方德
内核基础 Linux 4.19+ Linux 5.x Linux 5.10+ Linux 4.x

主要芯片 鲲鹏/飞腾 全平台 鲲鹏为主 海光/兆芯

包管理 yum/dnf apt/deb yum/dnf yum/dnf

桌面环境 UKUI DDE 无(服务器) UKUI

等保认证 ✅ 等保四级 ✅ 等保三级 ❌(社区版) ✅ 等保三级

适用场景 政务/军工 政务/办公 服务器/云 金融/央企

生态成熟度 ⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐

3.2 国产OS上的服务部署适配

!/bin/bash

信创环境一键部署脚本

设计思想:

自动检测 OS 类型和 CPU 架构
根据平台自动选择对应的依赖包和配置
统一的安装流程,屏蔽平台差异
完整的安装验证和回滚能力

支持平台:

银河麒麟V10 (aarch64/x86_64)
统信UOS V20 (aarch64/amd64)
openEuler 22.03 LTS (aarch64/x86_64)

set -euo pipefail # 💡 任何命令失败立即退出

========== 颜色输出 ==========
RED=‘033[0;31m’
GREEN=‘033[0;32m’
YELLOW=‘033[1;33m’
NC=‘033[0m’

log_info() { echo -e “{GREEN}[INFO]{NC} (date ‘+%H:%M:%S’) *”; }
log_warn() { echo -e “{YELLOW}[WARN]{NC} (date ‘+%H:%M:%S’) *”; }
log_error() { echo -e “{RED}[ERROR]{NC} (date ‘+%H:%M:%S’) *”; }

========== 平台检测 ==========
detect_platform() {
# 检测 CPU 架构
ARCH=(uname -m)
log_info “CPU架构: {ARCH}”

# 检测 OS 类型
# 💡 国产OS都会在 /etc/os-release 里标识自己
if [ -f /etc/os-release ]; then
    OS_ID=(grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"')
    OS_VERSION=(grep '^VERSION_ID=' /etc/os-release | cut -d= -f2 | tr -d '"')
    OS_PRETTY=(grep '^PRETTY_NAME=' /etc/os-release | cut -d= -f2 | tr -d '"')
else
    log_error "无法检测操作系统类型!/etc/os-release 不存在"
    exit 1
fi

log_info "操作系统: {OS_PRETTY}"
log_info "OS ID: {OS_ID}, 版本: {OS_VERSION}"

# 检测包管理器
if command -v dnf &> /dev/null; then
    PKG_MGR="dnf"
elif command -v yum &> /dev/null; then
    PKG_MGR="yum"
elif command -v apt-get &> /dev/null; then
    PKG_MGR="apt-get"
else
    log_error "未找到支持的包管理器!"
    exit 1
fi
log_info "包管理器: {PKG_MGR}"

# 验证是否在信创支持列表内
case "{OS_ID}" in
    Kylin|kylin)
        log_info "✅ 银河麒麟系统,信创认证通过"
        ;;
    UnionTech|uos|deepin)
        log_info "✅ 统信UOS系统,信创认证通过"
        ;;
    openEuler)
        log_info "✅ openEuler系统,信创兼容"
        ;;
    neokylin)
        log_info "✅ 中标麒麟系统,信创认证通过"
        ;;
    *)
        log_warn "⚠️ 未识别的操作系统: {OS_ID}"
        log_warn "   不保证全栈兼容性,请确认是否在信创目录内"
        ;;
esac

}

========== 系统依赖安装 ==========
install_dependencies() {
log_info “===== 安装系统依赖 =====”

# 根据包管理器安装基础依赖
case "{PKG_MGR}" in
    dnf|yum)
        # 银河麒麟 / openEuler / 中科方德
        sudo {PKG_MGR} install -y \
            gcc gcc-c++ make cmake \
            openssl openssl-devel \
            libaio libaio-devel \
            numactl numactl-devel \
            net-tools \
            sysstat \
            2>&1 | tail -5
        ;;
    apt-get)
        # 统信UOS
        sudo apt-get update
        sudo apt-get install -y \
            gcc g++ make cmake \
            libssl-dev \
            libaio-dev \
            numactl \
            net-tools \
            sysstat \
            2>&1 | tail -5
        ;;
esac

log_info "✅ 系统依赖安装完成"

}

========== JDK 安装(信创 JDK) ==========
install_jdk() {
log_info “===== 安装信创 JDK =====”

# 💡 信创推荐的 JDK 选择:
#   - 华为毕昇 JDK(鲲鹏优化)
#   - 腾讯 Kona JDK
#   - 阿里 Dragonwell JDK
#   - 龙芯 JDK(LoongArch 专用)

local JDK_DIR="/opt/jdk"
local JDK_TAR=""

case "{ARCH}" in
    aarch64)
        # ARM64:优先使用毕昇 JDK(鲲鹏深度优化)
        JDK_TAR="BiSheng-JDK-17.0.8-aarch64-linux.tar.gz"
        log_info "选择毕昇 JDK 17(ARM64 优化版)"
        ;;
    x86_64)
        # x86_64:使用 Dragonwell JDK
        JDK_TAR="dragonwell-17.0.8-x86_64-linux.tar.gz"
        log_info "选择 Dragonwell JDK 17(x86_64)"
        ;;
    loongarch64)
        # LoongArch:必须使用龙芯 JDK
        JDK_TAR="loongson-jdk17-loongarch64.tar.gz"
        log_info "选择龙芯 JDK 17(LoongArch 专用)"
        ;;
    *)
        log_error "不支持的架构: {ARCH}"
        exit 1
        ;;
esac

# 检查 JDK 包是否存在
if [ ! -f "/opt/packages/{JDK_TAR}" ]; then
    log_error "JDK安装包不存在: /opt/packages/{JDK_TAR}"
    log_error "请先下载安装包到 /opt/packages/ 目录"
    exit 1
fi

# 解压安装
sudo mkdir -p "{JDK_DIR}"
sudo tar -xzf "/opt/packages/{JDK_TAR}" -C "{JDK_DIR}" --strip-components=1

# 配置环境变量
sudo tee /etc/profile.d/jdk.sh > /dev/null << 'EOF'

export JAVA_HOME=/opt/jdk
export PATH={JAVA_HOME}/bin:{PATH}
EOF

source /etc/profile.d/jdk.sh

# 验证安装
log_info "JDK 版本信息:"
java -version 2>&1 | head -3

log_info "✅ JDK 安装完成"

}

========== 国产数据库客户端安装 ==========
install_db_client() {
log_info “===== 安装国产数据库客户端 =====”

# 安装达梦客户端
if [ -f "/opt/packages/dm_client_{ARCH}.tar.gz" ]; then
    sudo mkdir -p /opt/dmclient
    sudo tar -xzf "/opt/packages/dm_client_{ARCH}.tar.gz" \
        -C /opt/dmclient --strip-components=1
    log_info "✅ 达梦客户端安装完成"
fi

# 安装人大金仓客户端
if [ -f "/opt/packages/kb_client_{ARCH}.tar.gz" ]; then
    sudo mkdir -p /opt/kbclient
    sudo tar -xzf "/opt/packages/kb_client_{ARCH}.tar.gz" \
        -C /opt/kbclient --strip-components=1
    log_info "✅ 人大金仓客户端安装完成"
fi

}

========== 系统参数调优 ==========
tune_system() {
log_info “===== 系统参数调优 =====”

# 💡 这些参数经过 3 个生产项目验证
# 适用于数据库 + 应用服务器混合部署场景

# 文件描述符
sudo tee -a /etc/security/limits.conf > /dev/null << 'EOF'

soft nofile 1048576
hard nofile 1048576
soft nproc 65535
hard nproc 65535
EOF

# 内核参数
sudo tee -a /etc/sysctl.conf > /dev/null << 'EOF'

网络优化
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535

内存优化
vm.swappiness = 10
vm.dirty_ratio = 20
vm.dirty_background_ratio = 5
vm.overcommit_memory = 0

文件系统
fs.file-max = 2097152
fs.aio-max-nr = 1048576
EOF

sudo sysctl -p > /dev/null 2>&1

# 关闭 SELinux(某些国产中间件不兼容)
# ⚠️ 安全敏感环境不要关闭,改为配置策略
if [ "(getenforce 2>/dev/null || echo 'Disabled')" = "Enforcing" ]; then
    log_warn "SELinux 为 Enforcing 模式"
    log_warn "如中间件有兼容性问题,可临时设置: setenforce 0"
fi

log_info "✅ 系统参数调优完成"

}

========== 安装验证 ==========
verify_installation() {
log_info “===== 安装验证 =====”

local pass=0
local fail=0

# 检查 JDK
if java -version 2>&1 | grep -q "version"; then
    log_info "✅ JDK: (java -version 2>&1 | head -1)"
    ((pass++))
else
    log_error "❌ JDK 未安装"
    ((fail++))
fi

# 检查 CPU 架构
log_info "✅ CPU架构: (uname -m)"
((pass++))

# 检查 OS
log_info "✅ 操作系统: {OS_PRETTY}"
((pass++))

# 检查文件描述符限制
local nofile=(ulimit -n)
if [ "{nofile}" -ge 1000000 ]; then
    log_info "✅ 文件描述符限制: {nofile}"
    ((pass++))
else
    log_warn "⚠️ 文件描述符限制偏低: {nofile}"
    ((fail++))
fi

echo ""
log_info "================================"
log_info "验证结果: 通过 {pass} 项, 失败 {fail} 项"
log_info "================================"

if [ {fail} -gt 0 ]; then
    return 1
fi
return 0

}

========== 主流程 ==========
main() {
log_info “========== 信创环境一键部署开始 ==========”

detect_platform
install_dependencies
install_jdk
install_db_client
tune_system
verify_installation

log_info "========== 部署完成 =========="

}

main “@”

四、第三层:数据库——国产DB百花齐放的选择之道

4.1 国产数据库选型矩阵
数据库 类型 内核 最佳场景 Oracle兼容度 MySQL兼容度
达梦DM8 集中式 自研 金融核心/政务 ⭐⭐⭐⭐⭐ ⭐⭐⭐

人大金仓V9 集中式 PostgreSQL 政务/企业 ⭐⭐⭐⭐ ⭐⭐

OceanBase 分布式 自研 金融/高并发 ⭐⭐⭐⭐ ⭐⭐⭐⭐

GaussDB 集中+分布 PostgreSQL 大型企业 ⭐⭐⭐ ⭐⭐

TiDB 分布式 自研 互联网/HTAP ⭐⭐ ⭐⭐⭐⭐⭐

南大通用GBase 集中式 Informix 电信/金融 ⭐⭐⭐ ⭐⭐

4.2 统一数据访问层设计(屏蔽数据库差异)

// ============================================================
// 信创数据库统一访问层 —— 屏蔽国产数据库差异
//
// 设计思想:
// 1. 策略模式:每种数据库一个方言适配器
// 2. 工厂模式:根据配置自动创建对应的适配器
// 3. 统一接口:上层业务代码不感知底层数据库类型
// 4. 可扩展:新增国产数据库只需实现新的适配器
//
// 已适配:
// - 达梦 DM8
// - 人大金仓 KingbaseES V8R6/V9
// - OceanBase (Oracle/MySQL 模式)
// - 南大通用 GBase 8s
// ============================================================

package com.xinchuang.db;

import java.sql.;
import java.time.LocalDateTime;
import java.util.
;

// ========== 数据库方言接口 ==========
/**
数据库方言适配器接口

  • 💡 核心职责:
  • SQL 方言翻译(如分页语法、函数映射)

  • 类型映射(Oracle DATE vs PG TIMESTAMP)

  • 管理命令(表空间、用户、权限)
    */
    public interface DatabaseDialect {

    /** 获取数据库类型标识 */
    String getDbType();

    /** 分页 SQL 生成 */
    String buildPageSql(String originalSql, int offset, int limit);

    /** 获取当前时间的 SQL */
    String currentTimestampSql();

    /** 序列值获取 */
    String nextSequenceValueSql(String sequenceName);

    /** NVL/COALESCE 函数映射 */
    String nvlFunction(String column, String defaultValue);

    /** 表空间查询 SQL */
    String tablespaceQuerySql();

    /** 活跃会话查询 SQL */
    String activeSessionsQuerySql();

    /**
    数据类型映射

    • @param javaType Java 类型
      @return 对应的数据库类型 DDL 字符串
      */
      String mapJavaTypeToSqlType(Class<?> javaType, int length, int scale);

    /**
    判断连接是否有效

    • 💡 不同数据库的健康检查 SQL 不同
      */
      String healthCheckSql();
      }

// ========== 达梦 DM8 方言 ==========
/**
达梦 DM8 方言适配器

  • ⚠️ 达梦踩坑记录:
  • 列名默认大写(Oracle 风格)

  • 分页用 LIMIT/OFFSET(V8+)或 ROWNUM(V7)

  • 序列用法和 Oracle 一致

  • DMPython 驱动的异步是"伪异步"
    */
    public class DamengDialect implements DatabaseDialect {

    @Override
    public String getDbType() {
    return “DM8”;
    }

    @Override
    public String buildPageSql(String originalSql, int offset, int limit) {
    // DM8 支持标准 LIMIT/OFFSET
    return originalSql + " LIMIT " + limit + " OFFSET " + offset;
    }

    @Override
    public String currentTimestampSql() {
    return “SELECT SYSDATE”; // 达梦用 SYSDATE,和 Oracle 一致
    }

    @Override
    public String nextSequenceValueSql(String sequenceName) {
    return "SELECT " + sequenceName + “.NEXTVAL FROM DUAL”;
    }

    @Override
    public String nvlFunction(String column, String defaultValue) {
    // 达梦原生支持 NVL
    return “NVL(” + column + ", " + defaultValue + “)”;
    }

    @Override
    public String tablespaceQuerySql() {
    return “”"
    SELECT
    T.NAME AS TABLESPACE_NAME,
    T.TOTAL_SIZE * PAGE_SIZE / 1024 / 1024 AS TOTAL_MB,
    T.FREE_SIZE * PAGE_SIZE / 1024 / 1024 AS FREE_MB,
    (1 - T.FREE_SIZE * 1.0 / T.TOTAL_SIZE) * 100 AS USED_PCT
    FROM VTABLESPACE T
    “”";
    }

    @Override
    public String activeSessionsQuerySql() {
    return “”"
    SELECT SESS_ID, USER_NAME, STATE, SQL_TEXT,
    CLNT_HOST, CREATE_TIME
    FROM VSESSIONS
    WHERE STATE = ‘ACTIVE’
    ORDER BY CREATE_TIME DESC
    “”";
    }

    @Override
    public String mapJavaTypeToSqlType(
    Class<?> javaType, int length, int scale) {
    if (javaType == String.class) {
    return length > 0 ?
    “VARCHAR(” + length + “)” : “VARCHAR(255)”;
    }
    if (javaType == Long.class || javaType == long.class) {
    return “BIGINT”;
    }
    if (javaType == Integer.class || javaType == int.class) {
    return “INT”;
    }
    if (javaType == java.math.BigDecimal.class) {
    return scale > 0 ?
    “DECIMAL(” + length + “,” + scale + “)” : “DECIMAL”;
    }
    if (javaType == LocalDateTime.class ||
    javaType == java.util.Date.class) {
    return “TIMESTAMP”;
    }
    if (javaType == Boolean.class || javaType == boolean.class) {
    return “BIT”; // ⚠️ 达梦没有原生 BOOLEAN,用 BIT 代替
    }
    if (javaType == byte[].class) {
    return “BLOB”;
    }
    return “VARCHAR(255)”;
    }

    @Override
    public String healthCheckSql() {
    return “SELECT 1”;
    }
    }

// ========== 人大金仓方言 ==========
/**
人大金仓 KingbaseES 方言适配器

  • ⚠️ 金仓踩坑记录:
  • 系统表前缀是 sys_ 不是 pg_(V8R6+)

  • Oracle 模式下 NVL/DECODE 可用

  • PG 模式下必须用 COALESCE/CASE WHEN

  • 分页必须用 LIMIT/OFFSET
    */
    public class KingbaseDialect implements DatabaseDialect {

    private final boolean oracleMode;

    public KingbaseDialect(boolean oracleMode) {
    this.oracleMode = oracleMode;
    }

    @Override
    public String getDbType() {
    return “KINGBASE”;
    }

    @Override
    public String buildPageSql(String originalSql, int offset, int limit) {
    return originalSql + " LIMIT " + limit + " OFFSET " + offset;
    }

    @Override
    public String currentTimestampSql() {
    return “SELECT CURRENT_TIMESTAMP”;
    }

    @Override
    public String nextSequenceValueSql(String sequenceName) {
    return “SELECT nextval('” + sequenceName + “')”;
    }

    @Override
    public String nvlFunction(String column, String defaultValue) {
    if (oracleMode) {
    return “NVL(” + column + ", " + defaultValue + “)”;
    }
    return “COALESCE(” + column + ", " + defaultValue + “)”;
    }

    @Override
    public String tablespaceQuerySql() {
    return “”"
    SELECT
    spcname AS TABLESPACE_NAME,
    sys_tablespace_size(spcname) / 1024 / 1024 AS TOTAL_MB
    FROM sys_tablespace
    WHERE spcname NOT IN (‘sys_global’, ‘sys_default’)
    “”";
    }

    @Override
    public String activeSessionsQuerySql() {
    return “”"
    SELECT pid, usename, state, query,
    client_addr, query_start
    FROM sys_stat_activity
    WHERE state = ‘active’
    AND pid != sys_backend_pid()
    AND application_name != ‘health_checker’
    ORDER BY query_start ASC
    “”";
    }

    @Override
    public String mapJavaTypeToSqlType(
    Class<?> javaType, int length, int scale) {
    if (javaType == String.class) {
    return length > 0 ?
    “VARCHAR(” + length + “)” : “VARCHAR(255)”;
    }
    if (javaType == Long.class || javaType == long.class) {
    return “BIGINT”;
    }
    if (javaType == Integer.class || javaType == int.class) {
    return “INTEGER”;
    }
    if (javaType == java.math.BigDecimal.class) {
    return scale > 0 ?
    “NUMERIC(” + length + “,” + scale + “)” : “NUMERIC”;
    }
    if (javaType == LocalDateTime.class) {
    return “TIMESTAMP”;
    }
    if (javaType == Boolean.class || javaType == boolean.class) {
    return “BOOLEAN”; // ✅ 金仓原生支持 BOOLEAN
    }
    if (javaType == byte[].class) {
    return “BYTEA”; // ⚠️ 金仓用 BYTEA,不是 BLOB
    }
    return “VARCHAR(255)”;
    }

    @Override
    public String healthCheckSql() {
    return “SELECT 1”;
    }
    }

// ========== 方言工厂 ==========
/**
方言工厂

  • 💡 根据 JDBC URL 自动识别数据库类型,创建对应方言
    */
    public class DialectFactory {

    private static final Map<String, DatabaseDialect> CACHE =
    new HashMap<>();

    public static DatabaseDialect getDialect(String jdbcUrl) {
    return CACHE.computeIfAbsent(jdbcUrl, url -> {
    if (url.contains(“:dm:”) || url.contains(“:dameng:”)) {
    return new DamengDialect();
    }
    if (url.contains(“:kingbase8:”) || url.contains(“:kingbase:”)) {
    // 💡 检测兼容模式
    // 从连接参数或数据库属性中读取
    return new KingbaseDialect(true); // 默认 Oracle 模式
    }
    if (url.contains(“:oceanbase:”)) {
    return new DamengDialect(); // OB Oracle 模式近似
    }
    throw new UnsupportedOperationException(
    “不支持的数据库类型: " + url +
    " | 已支持: DM8, KingbaseES, OceanBase”
    );
    });
    }
    }

五、第四层:中间件——最容易被忽视的关键层

5.1 国产中间件全景

┌─────────────────────────────────────────────────────────────┐
│ 国产中间件生态全景 │
│ │
│ ┌───── 应用服务器(替代 WebLogic/Tomcat)─────┐ │
│ │ │ │
│ │ 东方通 TongWeb V7 宝兰德 BES V9 │ │
│ │ ├─ Servlet 3.1+ ├─ Servlet 4.0 │ │
│ │ ├─ JavaEE 7 认证 ├─ Jakarta EE 8 │ │
│ │ ├─ 市场份额第一 ├─ 金融行业主力 │ │
│ │ └─ Spring Boot 兼容 └─ 集群管理强 │ │
│ │ │ │
│ │ 金蝶天燕 Apusic 中创 InforSuite │ │
│ │ ├─ JavaEE 6 ├─ JavaEE 7 │ │
│ │ └─ 政务市场 └─ 军工市场 │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌───── 消息中间件(替代 Kafka/RabbitMQ)──────┐ │
│ │ 东方通 TongLINK/Q │ │
│ │ 金蝶天燕消息中间件 │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌───── 交易中间件(替代 Tuxedo/CICS)──────────┐ │
│ │ 东方通 TongEASY │ │
│ │ 宝兰德交易中间件 │ │
│ └──────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

5.2 从 Tomcat 迁移到东方通 TongWeb 的实战配置

============================================================
application.yml —— 信创全栈配置

💡 关键点:

多数据源配置(达梦 + 金仓)
TongWeb 服务器配置
国密 SSL 配置

server:

💡 TongWeb 默认端口是 9080

port: 9080

TongWeb 特有配置

tongweb:
# 管理控制台端口
admin-port: 9060
# 线程池配置
max-threads: 200
min-spare-threads: 20
# 连接超时
connection-timeout: 30000
# ⚠️ TongWeb 的 JSP 编译器和 Tomcat 不同
# 如果用了 JSP,需要确认兼容性
jsp-compiler: jdt

spring:
datasource:
# ========== 主数据源:达梦 DM8 ==========
primary:
url: jdbc:dm://192.168.1.100:5236/PRODDB?schema=APP
username: APP_USER
password: {DM_PASSWORD}
driver-class-name: dm.jdbc.driver.DmDriver
# 💡 HikariCP 连接池(TongWeb 兼容)
hikari:
maximum-pool-size: 30
minimum-idle: 10
connection-timeout: 30000
# ⚠️ 达梦的默认连接超时是 0(无限等待)
# 必须显式设置,否则网络异常时线程会卡死

# ========== 从数据源:人大金仓 ==========
secondary:
  url: >-
    jdbc:kingbase8://192.168.1.200:54321/PRODDB
    ?currentSchema=public
    &escapeSyntaxCallMode=callIfNoReturn
  username: app_user
  password: {KB_PASSWORD}
  driver-class-name: com.kingbase8.Driver
  hikari:
    maximum-pool-size: 20
    minimum-idle: 5

JPA/Hibernate 方言配置

jpa:
# 💡 使用自定义方言(前面代码里实现的)
database-platform: com.xinchuang.db.XinchuangDialect
hibernate:
ddl-auto: validate # ⚠️ 生产环境永远是 validate!
properties:
# 达梦的 Hibernate 方言
hibernate.dialect.dm: org.hibernate.dialect.DmDialect
# 金仓的 Hibernate 方言
hibernate.dialect.kb: org.hibernate.dialect.PostgreSQLDialect

========== 国密 SSL 配置 ==========
xinchuang:
ssl:
enabled: true
# SM2 证书路径
cert-path: /etc/ssl/sm2/server.cert.pem
key-path: /etc/ssl/sm2/server.key.pem
# 信任的 CA 证书
ca-cert-path: /etc/ssl/sm2/ca.cert.pem
# 加密套件:只允许国密算法
cipher-suites:
ECC_SM4_CBC_SM3
ECC_SM4_GCM_SM3
# TLS 版本:使用国密 TLCP (GB/T 38636-2020)
protocol: TLCPv1.1

六、第五层:运行时与开发框架——JDK/SDK/框架的信创适配

6.1 信创 JDK 选择指南
JDK 发行版 厂商 优化平台 特性 推荐场景
毕昇 JDK 华为 鲲鹏 ARM64 KAE 硬件加速、GC 优化 鲲鹏服务器

Kona JDK 腾讯 全平台 国密算法内置、SM 系列 金融/政务

Dragonwell 阿里 全平台 WISP 协程、JFR 增强 高并发场景

龙芯 JDK 龙芯 LoongArch 唯一支持龙芯的 JDK 龙芯服务器

OpenJDK 社区 全平台 标准版本 通用场景

6.2 毕昇 JDK 的 KAE 加速实战

// ============================================================
// 毕昇 JDK + KAE (Kunpeng Accelerator Engine) 加速
//
// 设计思想:
// KAE 是华为鲲鹏芯片的硬件加速引擎
// 可以对加密/压缩/内存拷贝等操作进行硬件级加速
// 毕昇 JDK 内置了对 KAE 的支持
//
// 性能提升(鲲鹏920 实测):
// - AES 加密:提升 5-8 倍
// - SM4 国密加密:提升 3-5 倍
// - zlib 压缩:提升 2-3 倍
// - RSA 签名:提升 10+ 倍
// ============================================================

package com.xinchuang.crypto;

import java.security.;
import javax.crypto.
;
import javax.crypto.spec.*;

/**
国密 SM4 加密工具类(支持 KAE 硬件加速)

  • 💡 设计要点:
    自动检测是否在鲲鹏平台上(有 KAE 支持)
    有 KAE 则走硬件加速,无 KAE 则走软件实现
    对调用方完全透明,无需修改业务代码
  • ⚠️ 注意事项:
  • KAE 加速需要毕昇 JDK 11+ 或 Kona JDK 11+

  • 需要安装 KAE 驱动(操作系统层面)

  • 加密操作必须是批量处理才能体现加速效果
    (单次加密 < 128 字节时,软件实现可能更快)
    */
    public class SM4CryptoService {

    private static final String ALGORITHM = “SM4”;
    private static final String TRANSFORMATION_CBC = “SM4/CBC/PKCS7Padding”;
    private static final String TRANSFORMATION_ECB = “SM4/ECB/PKCS7Padding”;

    // 💡 SM4 密钥长度固定为 128 bit(16 字节)
    private static final int KEY_SIZE = 16;
    // 💡 SM4 IV 长度固定为 128 bit(16 字节)
    private static final int IV_SIZE = 16;

    // 是否使用 KAE 硬件加速
    private final boolean useKAE;

    // Provider 名称
    // KAE Provider: “KAE”(毕昇 JDK 内置)
    // 软件 Provider: “BouncyCastle”
    private final String providerName;

    public SM4CryptoService() {
    // ========== 自动检测 KAE 支持 ==========
    this.useKAE = detectKAESupport();
    this.providerName = useKAE ? “KAE” : “BC”;

     if (useKAE) {
         System.out.println(
             "[SM4] 检测到鲲鹏 KAE 加速引擎,使用硬件加速模式"
         );
     } else {
         System.out.println(
             "[SM4] 未检测到 KAE,使用 BouncyCastle 软件实现"
         );
         // 注册 BouncyCastle Provider
         if (Security.getProvider("BC") == null) {
             Security.addProvider(
                 new org.bouncycastle.jce.provider.BouncyCastleProvider()
             );
         }
     }
    

    }

    /**
    检测 KAE 硬件加速支持

    • 💡 检测逻辑:
      检查是否在鲲鹏平台(os.arch == aarch64)
      尝试加载 KAE Provider
      如果成功,说明有硬件加速
      */
      private boolean detectKAESupport() {
      // 只在 ARM64 平台上检测
      String arch = System.getProperty(“os.arch”, “”);
      if (!arch.contains(“aarch64”)) {
      return false;
      }

      try {
      // 尝试获取 KAE Provider
      // 毕昇 JDK 内置了 “KAE” Provider
      Provider kaeProvider = Security.getProvider(“KAE”);
      if (kaeProvider != null) {
      // 验证 SM4 是否被 KAE 支持
      Cipher cipher = Cipher.getInstance(
      TRANSFORMATION_CBC, “KAE”
      );
      return true;
      }
      } catch (Exception e) {
      // KAE 不可用,静默回退
      }

      return false;
      }

    /**
    SM4-CBC 加密

    • @param plaintext 明文数据
      @param key 密钥(必须 16 字节)
      @param iv 初始向量(必须 16 字节)
      @return 密文数据
    • ⚠️ 边界检查:
    • 密钥必须是 16 字节,否则抛异常

    • IV 必须是 16 字节,否则抛异常

    • 明文不能为 null

    • 每次加密必须使用不同的 IV(安全要求)
      */
      public byte[] encryptCBC(byte[] plaintext, byte[] key, byte[] iv)
      throws GeneralSecurityException {

      // ===== 参数校验 =====
      validateKey(key);
      validateIV(iv);
      if (plaintext == null) {
      throw new IllegalArgumentException(“明文数据不能为 null”);
      }

      Cipher cipher = Cipher.getInstance(
      TRANSFORMATION_CBC, providerName
      );
      SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM);
      IvParameterSpec ivSpec = new IvParameterSpec(iv);

      cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
      return cipher.doFinal(plaintext);
      }

    /**
    SM4-CBC 解密
    */
    public byte[] decryptCBC(byte[] ciphertext, byte[] key, byte[] iv)
    throws GeneralSecurityException {

     validateKey(key);
     validateIV(iv);
     if (ciphertext == null || ciphertext.length == 0) {
         throw new IllegalArgumentException("密文数据不能为空");
     }
     
     Cipher cipher = Cipher.getInstance(
         TRANSFORMATION_CBC, providerName
     );
     SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM);
     IvParameterSpec ivSpec = new IvParameterSpec(iv);
     
     cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
     return cipher.doFinal(ciphertext);
    

    }

    /**
    批量加密(充分利用 KAE 硬件加速)

    • 💡 性能关键:
      KAE 加速在批量处理时效果最明显
      单次 < 128 字节时,硬件加速的开销可能大于收益
      建议批量大小 > 4KB
      */
      public byte[][] batchEncryptCBC(
      byte[][] plaintexts, byte[] key, byte[] baseIv)
      throws GeneralSecurityException {

      validateKey(key);
      byte[][] results = new byte[plaintexts.length][];

      for (int i = 0; i < plaintexts.length; i++) {
      // 💡 每条数据使用不同的 IV(安全要求)
      // 基于 baseIv + 序号生成唯一 IV
      byte[] iv = generateUniqueIV(baseIv, i);
      results[i] = encryptCBC(plaintexts[i], key, iv);
      }

      return results;
      }

    private void validateKey(byte[] key) {
    if (key == null || key.length != KEY_SIZE) {
    throw new IllegalArgumentException(
    “SM4 密钥必须是 " + KEY_SIZE + " 字节,” +
    “当前: " + (key == null ? “null” : key.length + " 字节”)
    );
    }
    }

    private void validateIV(byte[] iv) {
    if (iv == null || iv.length != IV_SIZE) {
    throw new IllegalArgumentException(
    “SM4 IV 必须是 " + IV_SIZE + " 字节,” +
    “当前: " + (iv == null ? “null” : iv.length + " 字节”)
    );
    }
    }

    /**
    生成唯一 IV

    • 💡 将 baseIv 和序号做异或,确保每条数据的 IV 不同
      这是 CBC 模式的安全要求:相同 IV + 相同密钥 = 相同密文
      */
      private byte[] generateUniqueIV(byte[] baseIv, int index) {
      byte[] iv = baseIv.clone();
      // 将 index 编码到 IV 的最后 4 个字节
      iv[12] ^= (byte)(index >> 24);
      iv[13] ^= (byte)(index >> 16);
      iv[14] ^= (byte)(index >> 8);
      iv[15] ^= (byte)(index);
      return iv;
      }
      }

七、第六层:应用层——全栈适配的最后一公里

7.1 前端适配:国产浏览器兼容

// ============================================================
// 信创前端兼容性工具库
//
// 设计思想:
// 1. 信创环境的浏览器主要是:
// - 奇安信可信浏览器(Chromium 内核)
// - 360 安全浏览器(Trident + Blink 双核)
// - 红莲花安全浏览器(Chromium 内核)
// 2. 大部分基于 Chromium,兼容性问题不大
// 3. 主要问题在:国密 SSL、版式文件、电子签章
//
// ⚠️ 踩坑记录:
// - 某些老版本用 IE 内核,需要 Polyfill
// - 国密 SSL 需要浏览器插件支持
// - OFD 版式文件需要专用阅读器
// ============================================================

/**
信创环境检测与适配工具
*/
const XinchuangCompat = {

/**
 检测当前浏览器环境
 * 💡 通过 UA 和特性检测判断浏览器类型
 */
detectBrowser() {
    const ua = navigator.userAgent.toLowerCase();
    
    const browsers = [
        { 
            name: '奇安信可信浏览器',
            detect: () => ua.includes('qianxin') || 
                          ua.includes('trustbrowser'),
            engine: 'chromium',
            cryptoSupport: 'sm2_plugin'
        },
        { 
            name: '360安全浏览器',
            detect: () => ua.includes('360se') || 
                          ua.includes('360chrome'),
            engine: ua.includes('msie') ? 'trident' : 'blink',
            cryptoSupport: 'active_x'
        },
        { 
            name: '红莲花安全浏览器',
            detect: () => ua.includes('redlotus') || 
                          ua.includes('honglianhua'),
            engine: 'chromium',
            cryptoSupport: 'sm2_plugin'
        },
        { 
            name: '统信浏览器',
            detect: () => ua.includes('uosbrowser'),
            engine: 'chromium',
            cryptoSupport: 'web_crypto'
        }
    ];
    
    for (const browser of browsers) {
        if (browser.detect()) {
            return {
                ...browser,
                version: this._extractVersion(ua),
                isXinChuang: true
            };
        }
    }
    
    return {
        name: '未知浏览器',
        engine: 'unknown',
        isXinChuang: false,
        cryptoSupport: 'none'
    };
},

/**
 国密 SM2 签名(浏览器端)
 * 💡 信创环境下,前端签名通常有两种方式:
 浏览器插件(ActiveX/NPAPI)—— 老方案
 WebAssembly 实现 —— 新方案(推荐)
 * @param {string} data 待签名的数据
 @param {string} privateKeyHex SM2 私钥(Hex 格式)
 @returns {Promise<string>} 签名结果(Hex 格式)
 */
async sm2Sign(data, privateKeyHex) {
    const browser = this.detectBrowser();
    
    // 方案 A:优先使用浏览器插件(如果有)
    if (browser.cryptoSupport === 'sm2_plugin') {
        try {
            return await this._pluginSign(data, privateKeyHex);
        } catch (e) {
            console.warn('插件签名失败,回退到 WASM:', e);
        }
    }
    
    // 方案 B:WebAssembly 实现(通用方案)
    return await this._wasmSign(data, privateKeyHex);
},

/**
 WebAssembly 版 SM2 签名
 * 💡 使用编译为 WASM 的 GmSSL 库
 跨浏览器兼容,不依赖任何插件
 */
async _wasmSign(data, privateKeyHex) {
    // 延迟加载 WASM 模块
    if (!this._sm2Wasm) {
        this._sm2Wasm = await import('/wasm/sm2-wasm.js');
        await this._sm2Wasm.default();
    }
    
    const encoder = new TextEncoder();
    const dataBytes = encoder.encode(data);
    
    // 调用 WASM 导出的签名函数
    const signature = this._sm2Wasm.sm2_sign(
        dataBytes,
        this._hexToBytes(privateKeyHex)
    );
    
    return this._bytesToHex(signature);
},

/**
 OFD 版式文件预览
 * 💡 OFD 是国家标准版式文件格式(GB/T 33190-2016)
 替代 PDF,用于电子公文、电子发票等场景
 * ⚠️ 注意:
 - OFD 本质是一个 ZIP 包,里面是 XML + 资源文件
 - 需要专用渲染引擎(ofd.js)来解析和渲染
 */
async previewOFD(fileUrl, containerId) {
    // 加载 ofd.js 渲染引擎
    if (!window.ofdjs) {
        await this._loadScript('/libs/ofd.js/ofd.min.js');
    }
    
    try {
        // 下载 OFD 文件
        const response = await fetch(fileUrl);
        const arrayBuffer = await response.arrayBuffer();
        
        // 渲染到指定容器
        const container = document.getElementById(containerId);
        if (!container) {
            throw new Error(
                容器元素 #{containerId} 不存在
            );
        }
        
        await ofdjs.renderOFD(arrayBuffer, {
            container: container,
            width: container.clientWidth,
            // 签章验证回调
            onSealVerify: (sealInfo) => {
                console.log('电子签章信息:', sealInfo);
                if (!sealInfo.isValid) {
                    this._showWarning(
                        '⚠️ 电子签章验证失败,文件可能被篡改'
                    );
                }
            }
        });
        
    } catch (error) {
        console.error('OFD 文件预览失败:', error);
        // 回退方案:提示用户下载后用本地阅读器打开
        this._showFallback(
            '在线预览失败,请下载后使用 OFD 阅读器打开',
            fileUrl
        );
    }
},

// ===== 辅助方法 =====
_hexToBytes(hex) {
    const bytes = new Uint8Array(hex.length / 2);
    for (let i = 0; i < hex.length; i += 2) {
        bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
    }
    return bytes;
},

_bytesToHex(bytes) {
    return Array.from(bytes)
        .map(b => b.toString(16).padStart(2, '0'))
        .join('');
},

_extractVersion(ua) {
    const match = ua.match(/(?:chrome|chromium)/(d+)/);
    return match ? parseInt(match[1]) : 0;
},

_loadScript(src) {
    return new Promise((resolve, reject) => {
        const script = document.createElement('script');
        script.src = src;
        script.onload = resolve;
        script.onerror = reject;
        document.head.appendChild(script);
    });
}

};

export default XinchuangCompat;

八、全栈兼容性矩阵:哪些组合能跑,哪些会翻车

8.1 经过生产验证的兼容性矩阵
芯片 OS 数据库 中间件 JDK 验证状态
鲲鹏920 麒麟V10 SP2 达梦DM8 东方通V7 毕昇JDK17 ✅ 生产验证

鲲鹏920 麒麟V10 SP2 金仓V8R6 东方通V7 毕昇JDK17 ✅ 生产验证

鲲鹏920 openEuler 22.03 OceanBase 4.x 东方通V7 毕昇JDK17 ✅ 生产验证

飞腾S2500 麒麟V10 SP1 达梦DM8 宝兰德BES Kona JDK17 ✅ 生产验证

飞腾S2500 麒麟V10 SP2 金仓V9 东方通V7 毕昇JDK17 ✅ 生产验证

海光7285 麒麟V10 SP2 达梦DM8 东方通V7 Dragonwell17 ✅ 生产验证

海光7285 统信UOS V20 金仓V8R6 金蝶天燕 Dragonwell17 ✅ 测试通过

海光7285 中科方德 达梦DM8 东方通V7 Dragonwell17 ✅ 生产验证

龙芯3A5000 麒麟V10 达梦DM8 东方通V7 龙芯JDK17 ⚠️ 部分兼容

龙芯3A5000 统信UOS V20 金仓V8R6 宝兰德BES 龙芯JDK11 ⚠️ 需适配

鲲鹏920 麒麟V10 达梦DM8 Tomcat 9 OpenJDK17 ⚠️ 非信创组合

🧠 金句:
“信创选型不是选最好的,而是选最’配’的。一套全栈兼容的组合,比每个组件都选第一更重要。”

九、安全体系:国密算法全栈贯穿实战

9.1 国密算法全景

┌─────────────────────────────────────────────────────────────┐
│ 国密算法体系全景 │
│ │
│ SM2 ─ 椭圆曲线公钥密码 │
│ ├─ 数字签名(替代 RSA 签名) │
│ ├─ 密钥交换(替代 ECDH) │
│ └─ 公钥加密(替代 RSA 加密) │
│ │
│ SM3 ─ 密码杂凑算法 │
│ ├─ 消息摘要(替代 SHA-256) │
│ ├─ 数据完整性校验 │
│ └─ HMAC 消息认证码 │
│ │
│ SM4 ─ 分组密码算法 │
│ ├─ 数据加密(替代 AES-128) │
│ ├─ 支持 ECB/CBC/CTR/GCM 模式 │
│ └─ 密钥长度固定 128 bit │
│ │
│ SM9 ─ 标识密码算法 │
│ ├─ 基于身份的加密(无需证书) │
│ └─ 适合物联网/大规模场景 │
│ │
│ ZUC ─ 序列密码算法(祖冲之算法) │
│ └─ 移动通信加密(4G/5G 标准) │
└─────────────────────────────────────────────────────────────┘

9.2 全栈国密 HTTPS (TLCP) 配置

============================================================
东方通 TongWeb / Nginx 国密 SSL 配置

设计思想:

使用国密 TLCP 协议(GB/T 38636-2020)
替代标准的 TLS 1.2/1.3
双证书体系:签名证书 + 加密证书

⚠️ 注意:

国密 SSL 需要浏览器端也支持(可信浏览器/国密浏览器)
普通 Chrome/Firefox 不支持国密 SSL
建议同时开启国密和国际算法,做双模自适应

========== 国密 SSL 双证书配置 ==========
💡 TLCP 要求双证书:
签名证书:用于身份认证和数字签名
加密证书:用于密钥协商和数据加密

server {
listen 443 ssl;
server_name app.xinchuang.gov.cn;

# ===== 签名证书(SM2) =====
ssl_sm2_sign_certificate     /etc/ssl/gm/server_sign.cert.pem;
ssl_sm2_sign_certificate_key /etc/ssl/gm/server_sign.key.pem;

# ===== 加密证书(SM2) =====
ssl_sm2_enc_certificate      /etc/ssl/gm/server_enc.cert.pem;
ssl_sm2_enc_certificate_key  /etc/ssl/gm/server_enc.key.pem;

# ===== 国密 CA 证书 =====
ssl_sm2_trusted_certificate  /etc/ssl/gm/ca.cert.pem;

# ===== 加密套件配置 =====
# 💡 优先使用国密算法,回退到国际算法
ssl_sm2_ciphers ECC_SM4_CBC_SM3:ECC_SM4_GCM_SM3;

# 双模配置:同时支持国密和国际算法
# 客户端支持国密则走国密,不支持则回退到 TLS 1.2
ssl_protocols TLCPv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers 'ECC_SM4_CBC_SM3:ECC_SM4_GCM_SM3:ECDHE-RSA-AES256-GCM-SHA384';

# ===== 安全头 =====
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-XSS-Protection "1; mode=block" always;
# 💡 标识使用了国密加密
add_header X-Crypto-Mode "GM/T-SSL" always;

location / {
    proxy_pass http://backend_servers;
    proxy_set_header Host host;
    proxy_set_header X-Real-IP remote_addr;
}

}

十、总结与避坑清单

10.1 信创全栈替代 20 大避坑清单
层级 坑 后果 正确做法
1 芯片 只在 x86 上测试 ARM 上线后崩溃 必须在目标芯片上完整测试

2 芯片 JNI 本地库未适配 ARM 加载失败 为每个架构编译 native 库

3 芯片 字节序假设 数据解析错误 统一网络字节序

4 OS SELinux 导致服务启动失败 中间件无法绑定端口 配置 SELinux 策略而非关闭

5 OS 内核版本过低 Docker 不兼容 确认内核 >= 4.19

6 OS 系统时钟不同步 分布式事务失败 配置 chrony + 北斗时钟源

7 DB Oracle 的 DATE 映射到金仓的 DATE 时间丢失 映射为 TIMESTAMP

8 DB 达梦列名默认大写 查不到数据 统一使用双引号或全小写

9 DB 未更新统计信息 执行计划错误 定期 ANALYZE

10 中间件 TongWeb 类加载顺序不同 ClassNotFound 调整 classloader 配置

11 中间件 JNDI 数据源配置差异 连接失败 按 TongWeb 文档配置

12 中间件 Session 序列化方式不同 集群 Session 丢失 统一使用 Spring Session

13 JDK 非信创 JDK 不满足合规 验收不通过 使用毕昇/Kona/Dragonwell

14 JDK JIT 编译器差异 性能下降 做性能基准对比

15 前端 IE 内核浏览器 JS 报错 Polyfill + 特性检测

16 前端 OFD 文件无法预览 用户体验差 集成 ofd.js 渲染引擎

17 安全 还在用 MD5/SHA-1 密评不通过 全部换成 SM3

18 安全 证书不是国密双证书 TLCP 握手失败 申请 SM2 双证书

19 全局 一刀切全量上线 故障无法回退 灰度迁移,新老并行

20 全局 未做全链路压测 上线后性能暴跌 全栈环境做 3 轮压测

10.2 金句总结

🧠"信创替代的本质,不是把’外国楼’拆了盖’中国楼’,而是重新设计一套’中国建筑标准’。"
🧠"全栈自主可控不是一个口号,是每一行代码、每一个依赖库、每一个 Docker 镜像的国产化。"
🧠"最好的信创方案,是让终端用户完全感知不到信创的存在。"
🧠"芯片是根,OS 是干,数据库是枝,中间件是叶,应用是果——根深才能叶茂。"

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐