Files
contract-manager/client/src/main/java/com/ecep/contract/SpringApp.java
songqq b03b5385a5 refactor(service): 修改IEntityService泛型为VO类型并优化缓存策略
重构所有注解@CacheConfig的Service类,将IEntityService泛型从实体类改为VO类
实现实体与VO之间的转换逻辑,使用VO替代实体进行缓存以避免序列化问题
更新相关依赖组件和测试用例,确保功能完整性和系统兼容性
优化Redis缓存配置,清理旧缓存数据并验证新缓存策略有效性
2025-09-28 18:19:00 +08:00

273 lines
11 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.ecep.contract;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationHook;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import org.springframework.boot.context.metrics.buffering.StartupTimeline;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.metrics.StartupStep;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import com.ecep.contract.util.UITools;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
@SpringBootApplication(exclude = {
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration.class,
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration.class,
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.class,
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration.class
})
@EnableScheduling
@EnableAsync
@EnableCaching
public class SpringApp {
private static final Logger logger = LoggerFactory.getLogger(SpringApp.class);
public static SpringApplication application;
public static ConfigurableApplicationContext context;
public static <T> T getBean(Class<T> requiredType) throws BeansException {
return context.getBean(requiredType);
}
public static void launch(Properties properties, MessageHolder holder) {
application = new SpringApplication(SpringApp.class);
BufferingApplicationStartup startup = new BufferingApplicationStartup(2000);
application.setApplicationStartup(startup);
//
holder.debug("应用程序环境准备中...");
SpringApplication.withHook(new Hook(holder), () -> {
// 动态地注册或修改这些组件和配置
application.addBootstrapRegistryInitializer(registry -> {
//
System.out.println("registry = " + registry);
});
application.addListeners(event -> {
logger.debug("SpringApp.launch ApplicationListener, event:{}", event);
});
application.addInitializers(app -> {
logger.debug("SpringApp.launch ApplicationContextInitializer");
ConfigurableEnvironment environment = app.getEnvironment();
logger.debug("environment = {}", environment);
PropertySource<?> dynamicProperties = environment.getPropertySources().get("dynamicProperties");
if (dynamicProperties != null) {
logger.debug("dynamicProperties = {}", dynamicProperties);
}
environment.getPropertySources().addLast(new PropertiesPropertySource("dynamicProperties", properties));
// app.getBeanFactory().registerSingleton("dataSource", dataSource());
logger.debug("app = {}", app);
});
startup.start("");
context = application.run();
logger.debug("SpringApp.launch application.run().");
Duration between = Duration.between(startup.getBufferedTimeline().getStartTime(), Instant.now());
// 初始化MyProperties从properties加载配置
try {
MyProperties myProperties = context.getBean(MyProperties.class);
myProperties.loadFromProperties(properties);
holder.info("MyProperties配置加载完成");
} catch (Exception e) {
logger.error("加载MyProperties配置失败", e);
holder.error("加载MyProperties配置失败: " + e.getMessage());
}
holder.info("应用程序环境加载完成... " + between);
});
CompletableFuture.runAsync(() -> {
// 在这里调用 startup 性能分析
analyzeStartupPerformance(startup);
}, Desktop.instance.getExecutorService());
}
/**
* 分析启动性能数据并输出到日志
*/
private static void analyzeStartupPerformance(BufferingApplicationStartup startup) {
// 获取所有记录的事件
StartupTimeline timeline = startup.getBufferedTimeline();
if (timeline == null || timeline.getEvents().isEmpty()) {
logger.warn("StartupTimeline 为空或没有事件!");
return;
}
logger.info("总共有 {} 个事件", timeline.getEvents().size());
// 找出与 Bean 初始化相关的步骤
timeline.getEvents().stream()
.filter(event -> event.getStartupStep().getName().startsWith("spring.beans."))
.sorted((a, b) -> Long.compare(b.getDuration().toMillis(), a.getDuration().toMillis()))
.limit(30)
.forEach(event -> {
String name = event.getStartupStep().getName();
long duration = event.getDuration().toMillis();
logger.info("Bean 初始化阶段: {} - 耗时: {} ms", name, duration);
for (StartupStep.Tag tag : event.getStartupStep().getTags()) {
if ("beanName".equals(tag.getKey())) {
logger.info(" └── Bean 名称: {}", tag.getValue());
}
}
});
}
public static String getMessage(String code, Object[] args, Locale locale) {
return context.getMessage(code, args, locale);
}
public static void shutdown() {
System.out.println("SpringApp.shutdown");
if (logger.isDebugEnabled()) {
logger.debug("shutdown");
}
if (context != null) {
if (context.isRunning()) {
context.close();
}
}
}
public static boolean isRunning() {
return context != null && context.isRunning();
}
static class Hook implements SpringApplicationHook, SpringApplicationRunListener {
MessageHolder holder;
Hook(MessageHolder holder) {
this.holder = holder;
}
public void debug(String msg) {
holder.debug(msg);
}
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
logger.debug("Desktop.starting");
debug("Spring Application 启动中...");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {
logger.debug("Desktop.environmentPrepared");
debug("初始化 Environment 中,请稍后...");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
logger.debug("Desktop.contextPrepared");
debug("Spring Application Context 预处理中,请稍后...");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
logger.debug("Desktop.contextLoaded");
debug("Spring Application Context 初始化完毕,请稍后...");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
logger.debug("Desktop.started");
debug("Spring Application 启动完毕.");
}
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
logger.debug("Desktop.ready");
debug("Spring Application ready.");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
logger.error("Desktop.failed", exception);
holder.error("Spring Application 启动失败(" + exception.getMessage() + ").");
UITools.showExceptionAndWait("启动失败", exception);
}
@Override
public SpringApplicationRunListener getRunListener(SpringApplication springApplication) {
return this;
}
}
@EventListener
public void handleClosedEvent(ContextClosedEvent event) {
if (logger.isDebugEnabled()) {
logger.debug("handleClosedEvent={}", event);
}
Desktop.shutdown();
}
@Bean
public CacheManager cacheManager() {
// return new ConcurrentMapCacheManager("myCache");
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setAsyncCacheMode(true);
return cacheManager;
}
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule javaTimeModule = new JavaTimeModule();
// LocalDate
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));
// LocalTime
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));
// LocalDateTime
javaTimeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
javaTimeModule.addDeserializer(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
@Bean
public ScheduledExecutorService scheduledExecutorService() {
return Desktop.instance.getExecutorService();
}
}