2024-10-22 10:46:33 +08:00
|
|
|
|
package com.chinaweal.youfool.devops;
|
|
|
|
|
|
|
2025-08-12 14:49:55 +08:00
|
|
|
|
import com.chinaweal.youfool.devops.config.ErrorLogProperties;
|
|
|
|
|
|
import com.chinaweal.youfool.devops.util.ErrorLogUtils;
|
2024-10-22 10:46:33 +08:00
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
2025-08-12 14:49:55 +08:00
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
2025-08-12 19:26:43 +08:00
|
|
|
|
import org.springframework.beans.factory.annotation.Qualifier;
|
2024-10-22 10:46:33 +08:00
|
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
2025-08-12 19:26:43 +08:00
|
|
|
|
|
|
|
|
|
|
import javax.sql.DataSource;
|
|
|
|
|
|
import java.sql.Connection;
|
2024-10-22 10:46:33 +08:00
|
|
|
|
import org.springframework.boot.SpringApplication;
|
|
|
|
|
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
|
|
|
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
|
|
|
|
|
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
|
|
|
|
|
import org.springframework.context.ApplicationListener;
|
|
|
|
|
|
import org.springframework.context.event.ContextRefreshedEvent;
|
|
|
|
|
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
|
|
|
|
|
|
2025-08-12 14:49:55 +08:00
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
|
|
2024-10-22 10:46:33 +08:00
|
|
|
|
@SpringBootApplication(scanBasePackages = {"com.chinaweal"})
|
|
|
|
|
|
@Slf4j
|
|
|
|
|
|
@EnableScheduling
|
|
|
|
|
|
public class DevOpsApplication extends SpringBootServletInitializer implements ApplicationListener<ContextRefreshedEvent> {
|
2025-08-12 14:49:55 +08:00
|
|
|
|
@Value("${applicationName:devOps}")
|
2024-10-22 10:46:33 +08:00
|
|
|
|
private String applicationName;
|
2025-08-12 14:49:55 +08:00
|
|
|
|
@Value("${version:1.0.0}")
|
2024-10-22 10:46:33 +08:00
|
|
|
|
private String version;
|
2025-08-12 14:49:55 +08:00
|
|
|
|
@Value("${description:运维管理系统}")
|
2024-10-22 10:46:33 +08:00
|
|
|
|
private String description;
|
2025-08-12 14:49:55 +08:00
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
private ErrorLogProperties errorLogProperties;
|
2025-08-12 19:26:43 +08:00
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
@Qualifier("devopsDS")
|
|
|
|
|
|
private DataSource devopsDataSource;
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
@Qualifier("youfoolDS")
|
|
|
|
|
|
private DataSource youfoolDataSource;
|
2024-10-22 10:46:33 +08:00
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) {
|
|
|
|
|
|
return applicationBuilder.sources(DevOpsApplication.class);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onApplicationEvent(ContextRefreshedEvent event) {
|
|
|
|
|
|
if (event.getApplicationContext().getParent() == null) {
|
2025-08-12 14:49:55 +08:00
|
|
|
|
try {
|
|
|
|
|
|
log.info("========================== 程序启动成功! ==========================");
|
|
|
|
|
|
log.info("====== 程 序:{} !", applicationName);
|
|
|
|
|
|
log.info("====== 版本号:{} ", version);
|
|
|
|
|
|
log.info("====== 描 述:{} ", description);
|
|
|
|
|
|
log.info("====== 接口文档路径:/doc.html,账号:admin、密码:123456。注:如果乱码请指定VM -Dfile.encoding=UTF-8");
|
|
|
|
|
|
log.info("====== Druid Monitor路径:/druid,账号:admin、密码:123456");
|
|
|
|
|
|
|
|
|
|
|
|
// 显示错误日志配置状态
|
|
|
|
|
|
if (errorLogProperties != null) {
|
|
|
|
|
|
log.info("====== 错误日志配置:启用={}, 目录={}",
|
|
|
|
|
|
errorLogProperties.isEnabled(), errorLogProperties.getLogDirectory());
|
|
|
|
|
|
log.info("====== 错误日志类型:启动={}, 运行时={}, 数据库={}, 业务={}",
|
|
|
|
|
|
errorLogProperties.isStartupEnabled(),
|
|
|
|
|
|
errorLogProperties.isRuntimeEnabled(),
|
|
|
|
|
|
errorLogProperties.isDatabaseEnabled(),
|
|
|
|
|
|
errorLogProperties.isBusinessEnabled());
|
|
|
|
|
|
}
|
2025-08-12 19:26:43 +08:00
|
|
|
|
|
|
|
|
|
|
// 打印数据库连接信息
|
|
|
|
|
|
printDatabaseConnectionInfo();
|
|
|
|
|
|
|
2025-08-12 14:49:55 +08:00
|
|
|
|
log.info("====================================================================");
|
|
|
|
|
|
|
|
|
|
|
|
// 记录启动成功信息
|
|
|
|
|
|
ErrorLogUtils.logStartupInfo("应用启动成功 - " + applicationName + " v" + version);
|
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("启动成功回调处理异常", e);
|
|
|
|
|
|
ErrorLogUtils.saveStartupError("启动成功回调异常", e);
|
|
|
|
|
|
}
|
2024-10-22 10:46:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
2025-08-12 14:49:55 +08:00
|
|
|
|
try {
|
|
|
|
|
|
// 记录启动开始
|
|
|
|
|
|
ErrorLogUtils.logStartupInfo("开始启动应用,参数: " + Arrays.toString(args));
|
|
|
|
|
|
|
|
|
|
|
|
// 设置默认的JVM参数以解决Java模块系统兼容性问题
|
|
|
|
|
|
setJavaModuleOptions();
|
|
|
|
|
|
|
|
|
|
|
|
// 启动Spring Boot应用
|
|
|
|
|
|
SpringApplication app = new SpringApplication(DevOpsApplication.class);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加启动失败监听器
|
|
|
|
|
|
app.addListeners(event -> {
|
|
|
|
|
|
if (event instanceof org.springframework.boot.context.event.ApplicationFailedEvent) {
|
|
|
|
|
|
org.springframework.boot.context.event.ApplicationFailedEvent failedEvent =
|
|
|
|
|
|
(org.springframework.boot.context.event.ApplicationFailedEvent) event;
|
|
|
|
|
|
Throwable exception = failedEvent.getException();
|
|
|
|
|
|
|
|
|
|
|
|
log.error("应用启动失败", exception);
|
|
|
|
|
|
ErrorLogUtils.saveStartupError("应用启动失败", exception);
|
|
|
|
|
|
|
|
|
|
|
|
// 输出友好的错误信息
|
|
|
|
|
|
System.err.println("\n==================== 应用启动失败 ====================");
|
|
|
|
|
|
System.err.println("错误信息已保存到: logs/errors/startup-error-*.log");
|
|
|
|
|
|
System.err.println("详细错误信息: " + ErrorLogUtils.formatErrorInfo("启动失败", exception));
|
|
|
|
|
|
System.err.println("=================================================\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
app.run(args);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加JVM关闭钩子以确保异步日志写入器正确关闭
|
|
|
|
|
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
|
|
|
|
|
log.info("应用正在关闭,清理错误日志资源...");
|
|
|
|
|
|
ErrorLogUtils.shutdown();
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("应用启动异常", e);
|
|
|
|
|
|
ErrorLogUtils.saveStartupError("主方法启动异常", e);
|
|
|
|
|
|
|
|
|
|
|
|
// 输出友好的错误信息到控制台
|
|
|
|
|
|
System.err.println("\n==================== 应用启动异常 ====================");
|
|
|
|
|
|
System.err.println("错误信息已保存到: logs/errors/startup-error-*.log");
|
|
|
|
|
|
System.err.println("详细错误信息: " + ErrorLogUtils.formatErrorInfo("启动异常", e));
|
|
|
|
|
|
System.err.println("=================================================\n");
|
|
|
|
|
|
|
|
|
|
|
|
// 重新抛出异常以确保程序正确退出
|
|
|
|
|
|
throw new RuntimeException("应用启动失败", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 设置Java版本兼容性参数
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static void setJavaModuleOptions() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
String javaVersion = System.getProperty("java.version");
|
|
|
|
|
|
ErrorLogUtils.logStartupInfo("当前Java版本: " + javaVersion);
|
|
|
|
|
|
|
|
|
|
|
|
// 只在Java 9+版本设置模块参数
|
|
|
|
|
|
if (isJava9OrHigher()) {
|
|
|
|
|
|
String javaToolOptions = System.getProperty("JAVA_TOOL_OPTIONS", "");
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已经设置了必要的模块参数
|
|
|
|
|
|
if (!javaToolOptions.contains("--add-opens java.base/java.util=ALL-UNNAMED")) {
|
|
|
|
|
|
String newOptions = javaToolOptions +
|
|
|
|
|
|
" --add-opens java.base/java.util=ALL-UNNAMED" +
|
|
|
|
|
|
" --add-opens java.base/java.lang=ALL-UNNAMED" +
|
|
|
|
|
|
" --add-opens java.base/java.lang.reflect=ALL-UNNAMED" +
|
|
|
|
|
|
" --add-opens java.base/java.time=ALL-UNNAMED";
|
|
|
|
|
|
|
|
|
|
|
|
System.setProperty("JAVA_TOOL_OPTIONS", newOptions.trim());
|
|
|
|
|
|
ErrorLogUtils.logStartupInfo("已设置Java模块兼容性参数: " + newOptions.trim());
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ErrorLogUtils.logStartupInfo("检测到Java 8,跳过模块系统参数设置");
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.warn("检查Java版本失败", e);
|
|
|
|
|
|
ErrorLogUtils.saveStartupError("Java版本检查失败", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 检查是否为Java 9或更高版本
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static boolean isJava9OrHigher() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
String version = System.getProperty("java.version");
|
|
|
|
|
|
// Java 8: 1.8.x, Java 9+: 9.x, 10.x, 11.x, etc.
|
|
|
|
|
|
if (version.startsWith("1.8")) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 尝试解析主版本号
|
|
|
|
|
|
String[] parts = version.split("\\.");
|
|
|
|
|
|
if (parts.length > 0) {
|
|
|
|
|
|
int majorVersion = Integer.parseInt(parts[0]);
|
|
|
|
|
|
return majorVersion >= 9;
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.warn("解析Java版本失败: " + System.getProperty("java.version"), e);
|
|
|
|
|
|
}
|
|
|
|
|
|
return false; // 默认认为是Java 8
|
2024-10-22 10:46:33 +08:00
|
|
|
|
}
|
2025-08-12 19:26:43 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 打印数据库连接信息
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void printDatabaseConnectionInfo() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
log.info("========== 数据库连接信息 ==========");
|
|
|
|
|
|
|
|
|
|
|
|
// 打印devops数据源信息
|
|
|
|
|
|
try (Connection conn = devopsDataSource.getConnection()) {
|
|
|
|
|
|
String url = conn.getMetaData().getURL();
|
|
|
|
|
|
String username = conn.getMetaData().getUserName();
|
|
|
|
|
|
String databaseName = conn.getCatalog();
|
|
|
|
|
|
|
|
|
|
|
|
log.info("🔗 Devops数据源:");
|
|
|
|
|
|
log.info(" URL: {}", url);
|
|
|
|
|
|
log.info(" 用户: {}", username);
|
|
|
|
|
|
log.info(" 数据库: {}", databaseName);
|
|
|
|
|
|
|
|
|
|
|
|
ErrorLogUtils.logStartupInfo("Devops数据源连接: " + url + ", 用户: " + username + ", 数据库: " + databaseName);
|
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("❌ 获取devops数据源信息失败", e);
|
|
|
|
|
|
ErrorLogUtils.saveStartupError("获取devops数据源信息失败", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 打印youfool数据源信息
|
|
|
|
|
|
try (Connection conn = youfoolDataSource.getConnection()) {
|
|
|
|
|
|
String url = conn.getMetaData().getURL();
|
|
|
|
|
|
String username = conn.getMetaData().getUserName();
|
|
|
|
|
|
String databaseName = conn.getCatalog();
|
|
|
|
|
|
|
|
|
|
|
|
log.info("🔗 Youfool数据源:");
|
|
|
|
|
|
log.info(" URL: {}", url);
|
|
|
|
|
|
log.info(" 用户: {}", username);
|
|
|
|
|
|
log.info(" 数据库: {}", databaseName);
|
|
|
|
|
|
|
|
|
|
|
|
ErrorLogUtils.logStartupInfo("Youfool数据源连接: " + url + ", 用户: " + username + ", 数据库: " + databaseName);
|
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("❌ 获取youfool数据源信息失败", e);
|
|
|
|
|
|
ErrorLogUtils.saveStartupError("获取youfool数据源信息失败", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 测试ENGINEER表访问
|
|
|
|
|
|
try (Connection conn = devopsDataSource.getConnection()) {
|
|
|
|
|
|
// 简单测试查询
|
|
|
|
|
|
String testSql = "SELECT COUNT(*) as total FROM engineer";
|
|
|
|
|
|
try (java.sql.PreparedStatement ps = conn.prepareStatement(testSql);
|
|
|
|
|
|
java.sql.ResultSet rs = ps.executeQuery()) {
|
|
|
|
|
|
if (rs.next()) {
|
|
|
|
|
|
int total = rs.getInt("total");
|
|
|
|
|
|
log.info("✅ ENGINEER表测试: 共{}条记录", total);
|
|
|
|
|
|
ErrorLogUtils.logStartupInfo("ENGINEER表访问测试成功,共" + total + "条记录");
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("❌ ENGINEER表访问测试失败", e);
|
|
|
|
|
|
ErrorLogUtils.saveStartupError("ENGINEER表访问测试失败", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("❌ 数据库连接测试失败", e);
|
|
|
|
|
|
ErrorLogUtils.saveStartupError("数据库连接测试失败", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log.info("=====================================");
|
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("❌ 打印数据库连接信息时发生异常", e);
|
|
|
|
|
|
ErrorLogUtils.saveStartupError("打印数据库连接信息异常", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-10-22 10:46:33 +08:00
|
|
|
|
}
|