深入解析:Atlas Mapper 教程系列 (8/10):性能优化与最佳实践
2025-10-15 08:27 tlnshuju 阅读(0) 评论(0) 收藏 举报学习目标
通过本篇教程,你将学会:
- 掌握 Atlas Mapper 的性能优化技巧
- 理解内存管理和缓存策略
- 学会生产环境的监控和调优方法
- 掌握最佳实践和设计模式
概念讲解:性能优化架构
性能优化层次
性能瓶颈分析
实现步骤:性能优化详解
步骤 1:编译时优化
优化 Mapper 配置
/**
* 高性能 Mapper 配置
*/
@Mapper(
componentModel = "spring",
// 性能优化配置
unmappedTargetPolicy = ReportingPolicy.IGNORE, // 减少运行时检查
unmappedSourcePolicy = ReportingPolicy.IGNORE, // 减少运行时检查
// 代码生成优化
suppressGeneratorTimestamp = true, // 减少生成代码大小
suppressGeneratorVersionComment = true, // 减少生成代码大小
// 集合映射优化
collectionMappingStrategy = CollectionMappingStrategy.ACCESSOR_ONLY,
// 空值处理优化
nullValueMappingStrategy = NullValueMappingStrategy.RETURN_NULL,
nullValueCheckStrategy = NullValueCheckStrategy.ON_IMPLICIT_CONVERSION
)
public interface OptimizedUserMapper {
/**
* 基础映射 - 最高性能
*/
UserDto toDto(User user);
/**
* 批量映射 - 优化集合处理
*/
List<UserDto> toDtoList(List<User> users);/*** 条件映射 - 避免不必要的转换*/@Condition("user != null && user.getId() != null")UserDto toDtoIfValid(User user);/*** 浅层映射 - 避免深度递归*/@Mapping(target = "orders", ignore = true)@Mapping(target = "addresses", ignore = true)UserDto toShallowDto(User user);}
生成代码优化分析
/**
* 优化前的生成代码(示例)
*/
public class UserMapperImpl implements UserMapper {
@Override
public UserDto toDto(User user) {
if (user == null) {
return null;
}
UserDto userDto = new UserDto();
// 优化点1:直接字段访问,避免反射
userDto.setId(user.getId());
userDto.setName(user.getName());
userDto.setEmail(user.getEmail());
// 优化点2:内联类型转换,避免方法调用
if (user.getCreatedAt() != null) {
userDto.setCreatedAt(user.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
}
// 优化点3:条件检查优化
if (user.getStatus() != null) {
userDto.setStatusDesc(mapStatus(user.getStatus()));
}
return userDto;
}
// 优化点4:私有方法内联
private String mapStatus(Integer status) {
switch (status) {
case 0: return "待激活";
case 1: return "已激活";
case 2: return "已禁用";
default: return "未知";
}
}
}
步骤 2:运行时性能优化
对象池化和复用
/**
* 高性能映射服务 - 使用对象池
*/
@Service
public class HighPerformanceMappingService {
private final UserMapper userMapper;
// 对象池 - 复用 DTO 对象
private final ObjectPool<UserDto> userDtoPool;// 线程本地缓存 - 避免线程竞争private final ThreadLocal<List<UserDto>> threadLocalDtoList;public HighPerformanceMappingService(UserMapper userMapper) {this.userMapper = userMapper;// 初始化对象池this.userDtoPool = new GenericObjectPool<>(new UserDtoFactory(),createPoolConfig());// 初始化线程本地缓存this.threadLocalDtoList = ThreadLocal.withInitial(() -> new ArrayList<>(100));}/*** 高性能单对象映射*/public UserDto mapUserWithPool(User user) {if (user == null) {return null;}UserDto dto = null;try {// 从对象池获取 DTOdto = userDtoPool.borrowObject();// 重置 DTO 状态resetUserDto(dto);// 手动映射(避免框架开销)dto.setId(user.getId());dto.setName(user.getName());dto.setEmail(user.getEmail());dto.setCreatedAt(formatDateTime(user.getCreatedAt()));return dto;} catch (Exception e) {// 如果对象池出错,回退到普通映射return userMapper.toDto(user);} finally {// 注意:不要在这里归还对象,由调用方负责}}/*** 高性能批量映射*/public List<UserDto> mapUsersWithOptimization(List<User> users) {if (users == null || users.isEmpty()) {return Collections.emptyList();}// 使用线程本地列表避免重复创建List<UserDto> dtoList = threadLocalDtoList.get();dtoList.clear();// 预分配容量if (dtoList instanceof ArrayList) {((ArrayList<UserDto>) dtoList).ensureCapacity(users.size());}// 批量映射for (User user : users) {if (user != null) {UserDto dto = mapUserWithPool(user);if (dto != null) {dtoList.add(dto);}}}// 返回副本,保持线程本地列表可复用return new ArrayList<>(dtoList);}/*** 并行映射 - 适用于大数据集*/public List<UserDto> mapUsersInParallel(List<User> users) {if (users == null || users.isEmpty()) {return Collections.emptyList();}// 小数据集直接使用串行处理if (users.size() < 1000) {return userMapper.toDtoList(users);}// 大数据集使用并行流return users.parallelStream().filter(Objects::nonNull).map(userMapper::toDto).filter(Objects::nonNull).collect(Collectors.toList());}/*** 分批处理 - 控制内存使用*/public List<UserDto> mapUsersInBatches(List<User> users, int batchSize) {if (users == null || users.isEmpty()) {return Collections.emptyList();}List<UserDto> result = new ArrayList<>(users.size());for (int i = 0; i < users.size(); i += batchSize) {int endIndex = Math.min(i + batchSize, users.size());List<User> batch = users.subList(i, endIndex);List<UserDto> batchResult = userMapper.toDtoList(batch);result.addAll(batchResult);// 批次间垃圾回收提示if (i % (batchSize * 10) == 0) {System.gc(); // 仅在必要时使用}}return result;}// 辅助方法private GenericObjectPoolConfig<UserDto> createPoolConfig() {GenericObjectPoolConfig<UserDto> config = new GenericObjectPoolConfig<>();config.setMaxTotal(100); // 最大对象数config.setMaxIdle(50); // 最大空闲对象数config.setMinIdle(10); // 最小空闲对象数config.setTestOnBorrow(false); // 关闭借用时测试config.setTestOnReturn(false); // 关闭归还时测试return config;}private void resetUserDto(UserDto dto) {dto.setId(null);dto.setName(null);dto.setEmail(null);dto.setCreatedAt(null);}private String formatDateTime(LocalDateTime dateTime) {return dateTime != null ? dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) : null;}/*** 对象工厂*/private static class UserDtoFactory extends BasePooledObjectFactory<UserDto> {@Overridepublic UserDto create() {return new UserDto();}@Overridepublic PooledObject<UserDto> wrap(UserDto dto) {return new DefaultPooledObject<>(dto);}}}
缓存策略实现
/**
* 智能缓存映射服务
*/
@Service
public class CachedMappingService {
private final UserMapper userMapper;
// 多级缓存策略
private final Cache<String, UserDto> l1Cache; // L1: 本地缓存private final Cache<String, UserDto> l2Cache; // L2: 分布式缓存// 映射结果缓存private final LoadingCache<User, UserDto> mappingCache;// 批量映射缓存private final Cache<String, List<UserDto>> batchCache;public CachedMappingService(UserMapper userMapper, CacheManager cacheManager) {this.userMapper = userMapper;// 初始化本地缓存this.l1Cache = Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(Duration.ofMinutes(10)).recordStats().build();// 初始化分布式缓存this.l2Cache = cacheManager.getCache("user-mapping");// 初始化映射缓存this.mappingCache = Caffeine.newBuilder().maximumSize(500).expireAfterWrite(Duration.ofMinutes(5)).build(this::doMapping);// 初始化批量缓存this.batchCache = Caffeine.newBuilder().maximumSize(100).expireAfterWrite(Duration.ofMinutes(3)).build();}/*** 带缓存的单对象映射*/public UserDto mapUserWithCache(User user) {if (user == null || user.getId() == null) {return userMapper.toDto(user);}String cacheKey = "user:" + user.getId() + ":" + user.getUpdatedAt().toEpochSecond(ZoneOffset.UTC);// L1 缓存查找UserDto cached = l1Cache.getIfPresent(cacheKey);if (cached != null) {return cached;}// L2 缓存查找cached = l2Cache.get(cacheKey, UserDto.class);if (cached != null) {l1Cache.put(cacheKey, cached); // 回填 L1 缓存return cached;}// 执行映射UserDto dto = userMapper.toDto(user);// 写入缓存if (dto != null) {l1Cache.put(cacheKey, dto);l2Cache.put(cacheKey, dto);}return dto;}/*** 智能批量映射缓存*/public List<UserDto> mapUsersWithSmartCache(List<User> users) {if (users == null || users.isEmpty()) {return Collections.emptyList();}// 生成批量缓存键String batchKey = generateBatchKey(users);// 检查批量缓存List<UserDto> cachedResult = batchCache.getIfPresent(batchKey);if (cachedResult != null) {return cachedResult;}// 分离缓存命中和未命中的对象List<UserDto> result = new ArrayList<>(users.size());List<User> uncachedUsers = new ArrayList<>();Map<Integer, User> indexMap = new HashMap<>();for (int i = 0; i < users.size(); i++) {User user = users.get(i);if (user == null) {result.add(null);continue;}UserDto cached = mapUserWithCache(user);if (cached != null) {result.add(cached);} else {result.add(null); // 占位符uncachedUsers.add(user);indexMap.put(uncachedUsers.size() - 1, user);}}// 批量映射未缓存的对象if (!uncachedUsers.isEmpty()) {List<UserDto> uncachedResults = userMapper.toDtoList(uncachedUsers);// 填充结果并更新缓存int uncachedIndex = 0;for (int i = 0; i < result.size(); i++) {if (result.get(i) == null && uncachedIndex < uncachedResults.size()) {UserDto dto = uncachedResults.get(uncachedIndex++);result.set(i, dto);// 更新单对象缓存User user = users.get(i);if (user != null && dto != null) {String cacheKey = "user:" + user.getId() + ":" + user.getUpdatedAt().toEpochSecond(ZoneOffset.UTC);l1Cache.put(cacheKey, dto);}}}}// 缓存批量结果batchCache.put(batchKey, result);return result;}/*** 预热缓存*/@EventListener(ApplicationReadyEvent.class)public void warmUpCache() {CompletableFuture.runAsync(() -> {try {// 预加载热点数据List<User> hotUsers = loadHotUsers();mapUsersWithSmartCache(hotUsers);log.info("缓存预热完成,预加载 {} 个用户", hotUsers.size());} catch (Exception e) {log.warn("缓存预热失败", e);}});}/*** 缓存统计和监控*/@Scheduled(fixedRate = 60000) // 每分钟执行一次public void reportCacheStats() {CacheStats l1Stats = l1Cache.stats();log.info("L1缓存统计 - 命中率: {:.2f}%, 请求数: {}, 命中数: {}, 未命中数: {}, 驱逐数: {}",l1Stats.hitRate() * 100,l1Stats.requestCount(),l1Stats.hitCount(),l1Stats.missCount(),l1Stats.evictionCount());// 发送监控指标sendMetrics("cache.l1.hit_rate", l1Stats.hitRate());sendMetrics("cache.l1.request_count", l1Stats.requestCount());}// 辅助方法private UserDto doMapping(User user) {return userMapper.toDto(user);}private String generateBatchKey(List<User> users) {return users.stream().filter(Objects::nonNull).map(user -> user.getId() + ":" + user.getUpdatedAt().toEpochSecond(ZoneOffset.UTC)).collect(Collectors.joining(",", "batch:", ""));}private List<User> loadHotUsers() {// 实现热点用户加载逻辑return Collections.emptyList();}private void sendMetrics(String name, double value) {// 发送监控指标到监控系统}}
步骤 3:内存优化策略
内存使用分析和优化
/**
* 内存优化的映射服务
*/
@Service
public class MemoryOptimizedMappingService {
private final UserMapper userMapper;
// 内存监控
private final MemoryMXBean memoryBean;
private final GarbageCollectorMXBean gcBean;
// 对象大小估算器
private final ObjectSizeCalculator sizeCalculator;
public MemoryOptimizedMappingService(UserMapper userMapper) {
this.userMapper = userMapper;
this.memoryBean = ManagementFactory.getMemoryMXBean();
this.gcBean = ManagementFactory.getGarbageCollectorMXBeans().get(0);
this.sizeCalculator = new ObjectSizeCalculator();
}
/**
* 内存感知的批量映射
*/
public List<UserDto> mapUsersWithMemoryControl(List<User> users, long maxMemoryMB) {if (users == null || users.isEmpty()) {return Collections.emptyList();}long maxMemoryBytes = maxMemoryMB * 1024 * 1024;long currentMemoryUsage = getCurrentMemoryUsage();// 如果内存使用已经很高,触发 GCif (currentMemoryUsage > maxMemoryBytes * 0.8) {System.gc();currentMemoryUsage = getCurrentMemoryUsage();}// 估算单个对象的内存使用User sampleUser = users.get(0);UserDto sampleDto = userMapper.toDto(sampleUser);long singleObjectSize = sizeCalculator.calculateObjectSize(sampleDto);// 计算安全的批次大小long availableMemory = maxMemoryBytes - currentMemoryUsage;int safeBatchSize = (int) Math.min(users.size(), availableMemory / singleObjectSize / 2);if (safeBatchSize < 100) {safeBatchSize = 100; // 最小批次大小}log.info("内存控制映射 - 总对象数: {}, 批次大小: {}, 预估单对象大小: {} bytes",users.size(), safeBatchSize, singleObjectSize);// 分批处理return mapUsersInBatchesWithMemoryMonitoring(users, safeBatchSize);}/*** 带内存监控的分批映射*/private List<UserDto> mapUsersInBatchesWithMemoryMonitoring(List<User> users, int batchSize) {List<UserDto> result = new ArrayList<>();for (int i = 0; i < users.size(); i += batchSize) {int endIndex = Math.min(i + batchSize, users.size());List<User> batch = users.subList(i, endIndex);// 监控内存使用long memoryBefore = getCurrentMemoryUsage();// 执行批次映射List<UserDto> batchResult = userMapper.toDtoList(batch);result.addAll(batchResult);long memoryAfter = getCurrentMemoryUsage();long memoryUsed = memoryAfter - memoryBefore;log.debug("批次 {}-{} 完成,内存使用: {} MB", i, endIndex, memoryUsed / 1024 / 1024);// 如果内存使用过高,触发 GCif (memoryUsed > 50 * 1024 * 1024) { // 50MBSystem.gc();Thread.yield(); // 让 GC 线程有机会运行}}return result;}/*** 流式映射 - 减少内存峰值*/public Stream<UserDto> mapUsersAsStream(List<User> users) {return users.stream().filter(Objects::nonNull).map(user -> {try {return userMapper.toDto(user);} catch (Exception e) {log.warn("映射用户失败: {}", user.getId(), e);return null;}}).filter(Objects::nonNull);}/*** 懒加载映射 - 按需映射*/public Iterator<UserDto> mapUsersLazily(List<User> users) {return new Iterator<UserDto>() {private int index = 0;@Overridepublic boolean hasNext() {return index < users.size();}@Overridepublic UserDto next() {if (!hasNext()) {throw new NoSuchElementException();}User user = users.get(index++);return user != null ? userMapper.toDto(user) : null;}};}/*** 内存使用报告*/public MemoryUsageReport generateMemoryReport() {MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage();return MemoryUsageReport.builder().heapUsed(heapUsage.getUsed()).heapMax(heapUsage.getMax()).heapCommitted(heapUsage.getCommitted()).nonHeapUsed(nonHeapUsage.getUsed()).nonHeapMax(nonHeapUsage.getMax()).gcCollectionCount(gcBean.getCollectionCount()).gcCollectionTime(gcBean.getCollectionTime()).build();}// 辅助方法private long getCurrentMemoryUsage() {return memoryBean.getHeapMemoryUsage().getUsed();}/*** 内存使用报告*/@Data@Builderpublic static class MemoryUsageReport {private long heapUsed;private long heapMax;private long heapCommitted;private long nonHeapUsed;private long nonHeapMax;private long gcCollectionCount;private long gcCollectionTime;public double getHeapUsagePercentage() {return heapMax > 0 ? (double) heapUsed / heapMax * 100 : 0;}}}
示例代码:生产环境最佳实践
示例 1:性能监控和指标收集
/**
* 性能监控服务
*/
@Service
@Component
public class MappingPerformanceMonitor {
private final MeterRegistry meterRegistry;
private final Timer mappingTimer;
private final Counter mappingCounter;
private final Counter errorCounter;
private final Gauge memoryGauge;
// 性能统计
private final AtomicLong totalMappings = new AtomicLong(0);
private final AtomicLong totalErrors = new AtomicLong(0);
private final AtomicReference<Double> averageExecutionTime = new AtomicReference<>(0.0);// 性能历史记录private final CircularFifoQueue<PerformanceRecord> performanceHistory;public MappingPerformanceMonitor(MeterRegistry meterRegistry) {this.meterRegistry = meterRegistry;// 初始化指标this.mappingTimer = Timer.builder("atlas.mapper.execution.time").description("Atlas Mapper execution time").register(meterRegistry);this.mappingCounter = Counter.builder("atlas.mapper.executions").description("Atlas Mapper execution count").register(meterRegistry);this.errorCounter = Counter.builder("atlas.mapper.errors").description("Atlas Mapper error count").register(meterRegistry);this.memoryGauge = Gauge.builder("atlas.mapper.memory.usage").description("Atlas Mapper memory usage").register(meterRegistry, this, MappingPerformanceMonitor::getCurrentMemoryUsage);// 初始化性能历史this.performanceHistory = new CircularFifoQueue<>(1000);}/*** 监控映射执行*/public <T> T monitorMapping(String mapperName, String methodName, Supplier<T> mappingOperation) {Timer.Sample sample = Timer.start(meterRegistry);long startTime = System.nanoTime();try {T result = mappingOperation.get();// 记录成功指标recordSuccess(mapperName, methodName, startTime);return result;} catch (Exception e) {// 记录错误指标recordError(mapperName, methodName, e, startTime);throw e;} finally {sample.stop(mappingTimer);mappingCounter.increment();}}/*** 批量映射性能监控*/public <T> List<T> monitorBatchMapping(String mapperName, String methodName,List<?> sourceList, Supplier<List<T>> mappingOperation) {int batchSize = sourceList != null ? sourceList.size() : 0;Timer.Sample sample = Timer.start(meterRegistry);long startTime = System.nanoTime();try {List<T> result = mappingOperation.get();// 记录批量成功指标recordBatchSuccess(mapperName, methodName, batchSize, startTime);return result;} catch (Exception e) {// 记录批量错误指标recordBatchError(mapperName, methodName, batchSize, e, startTime);throw e;} finally {sample.stop(mappingTimer);mappingCounter.increment(batchSize);}}/*** 性能分析报告*/public PerformanceAnalysisReport generatePerformanceReport() {List<PerformanceRecord> recentRecords = new ArrayList<>(performanceHistory);if (recentRecords.isEmpty()) {return PerformanceAnalysisReport.empty();}// 计算统计指标DoubleSummaryStatistics timeStats = recentRecords.stream().mapToDouble(PerformanceRecord::getExecutionTimeMs).summaryStatistics();Map<String, Long> mapperUsage = recentRecords.stream().collect(Collectors.groupingBy(PerformanceRecord::getMapperName,Collectors.counting()));Map<String, Double> mapperAvgTime = recentRecords.stream().collect(Collectors.groupingBy(PerformanceRecord::getMapperName,Collectors.averagingDouble(PerformanceRecord::getExecutionTimeMs)));// 识别性能瓶颈List<String> performanceBottlenecks = identifyBottlenecks(recentRecords);return PerformanceAnalysisReport.builder().totalMappings(totalMappings.get()).totalErrors(totalErrors.get()).averageExecutionTime(timeStats.getAverage()).minExecutionTime(timeStats.getMin()).maxExecutionTime(timeStats.getMax()).mapperUsageCount(mapperUsage).mapperAverageTime(mapperAvgTime).performanceBottlenecks(performanceBottlenecks).errorRate(calculateErrorRate()).throughput(calculateThroughput()).build();}/*** 性能告警检查*/@Scheduled(fixedRate = 30000) // 每30秒检查一次public void checkPerformanceAlerts() {PerformanceAnalysisReport report = generatePerformanceReport();// 检查错误率告警if (report.getErrorRate() > 0.05) { // 错误率超过 5%sendAlert("高错误率告警", "映射错误率达到 " + String.format("%.2f%%", report.getErrorRate() * 100));}// 检查平均执行时间告警if (report.getAverageExecutionTime() > 100) { // 平均执行时间超过 100mssendAlert("性能告警", "平均映射时间达到 " + String.format("%.2f ms", report.getAverageExecutionTime()));}// 检查内存使用告警double memoryUsage = getCurrentMemoryUsage();if (memoryUsage > 0.8) { // 内存使用超过 80%sendAlert("内存告警", "内存使用率达到 " + String.format("%.2f%%", memoryUsage * 100));}}// 私有方法private void recordSuccess(String mapperName, String methodName, long startTime) {long executionTime = System.nanoTime() - startTime;double executionTimeMs = executionTime / 1_000_000.0;PerformanceRecord record = PerformanceRecord.builder().mapperName(mapperName).methodName(methodName).executionTimeMs(executionTimeMs).success(true).timestamp(Instant.now()).build();performanceHistory.add(record);totalMappings.incrementAndGet();updateAverageExecutionTime(executionTimeMs);}private void recordError(String mapperName, String methodName, Exception error, long startTime) {long executionTime = System.nanoTime() - startTime;double executionTimeMs = executionTime / 1_000_000.0;PerformanceRecord record = PerformanceRecord.builder().mapperName(mapperName).methodName(methodName).executionTimeMs(executionTimeMs).success(false).errorMessage(error.getMessage()).timestamp(Instant.now()).build();performanceHistory.add(record);totalErrors.incrementAndGet();// 记录错误指标errorCounter.increment(Tags.of("mapper", mapperName,"method", methodName,"error", error.getClass().getSimpleName()));}private void recordBatchSuccess(String mapperName, String methodName, int batchSize, long startTime) {long executionTime = System.nanoTime() - startTime;double executionTimeMs = executionTime / 1_000_000.0;PerformanceRecord record = PerformanceRecord.builder().mapperName(mapperName).methodName(methodName).executionTimeMs(executionTimeMs).batchSize(batchSize).success(true).timestamp(Instant.now()).build();performanceHistory.add(record);totalMappings.addAndGet(batchSize);updateAverageExecutionTime(executionTimeMs);// 记录批量处理指标Timer.builder("atlas.mapper.batch.execution.time").tag("mapper", mapperName).tag("method", methodName).register(meterRegistry).record(executionTime, TimeUnit.NANOSECONDS);Gauge.builder("atlas.mapper.batch.size").tag("mapper", mapperName).tag("method", methodName).register(meterRegistry, batchSize, size -> size);}private void recordBatchError(String mapperName, String methodName, int batchSize, Exception error, long startTime) {recordError(mapperName, methodName, error, startTime);// 额外记录批量错误Counter.builder("atlas.mapper.batch.errors").tag("mapper", mapperName).tag("method", methodName).tag("batch_size", String.valueOf(batchSize)).register(meterRegistry).increment();}private void updateAverageExecutionTime(double executionTimeMs) {averageExecutionTime.updateAndGet(current -> {long count = totalMappings.get();return count > 1 ? (current * (count - 1) + executionTimeMs) / count : executionTimeMs;});}private List<String> identifyBottlenecks(List<PerformanceRecord> records) {List<String> bottlenecks = new ArrayList<>();// 识别慢映射器Map<String, Double> avgTimes = records.stream().collect(Collectors.groupingBy(PerformanceRecord::getMapperName,Collectors.averagingDouble(PerformanceRecord::getExecutionTimeMs)));avgTimes.entrySet().stream().filter(entry -> entry.getValue() > 50) // 超过 50ms.forEach(entry -> bottlenecks.add("慢映射器: " + entry.getKey() + " (平均 " +String.format("%.2f ms", entry.getValue()) + ")"));return bottlenecks;}private double calculateErrorRate() {long total = totalMappings.get();long errors = totalErrors.get();return total > 0 ? (double) errors / total : 0.0;}private double calculateThroughput() {// 计算最近1分钟的吞吐量Instant oneMinuteAgo = Instant.now().minus(Duration.ofMinutes(1));long recentMappings = performanceHistory.stream().filter(record -> record.getTimestamp().isAfter(oneMinuteAgo)).mapToLong(record -> record.getBatchSize() > 0 ? record.getBatchSize() : 1).sum();return recentMappings / 60.0; // 每秒映射数}private double getCurrentMemoryUsage() {MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();return (double) heapUsage.getUsed() / heapUsage.getMax();}private void sendAlert(String title, String message) {// 实现告警发送逻辑(邮件、短信、钉钉等)log.warn("性能告警 - {}: {}", title, message);}/*** 性能记录*/@Data@Builderpublic static class PerformanceRecord {private String mapperName;private String methodName;private double executionTimeMs;private int batchSize;private boolean success;private String errorMessage;private Instant timestamp;}/*** 性能分析报告*/@Data@Builderpublic static class PerformanceAnalysisReport {private long totalMappings;private long totalErrors;private double averageExecutionTime;private double minExecutionTime;private double maxExecutionTime;private Map<String, Long> mapperUsageCount;private Map<String, Double> mapperAverageTime;private List<String> performanceBottlenecks;private double errorRate;private double throughput;public static PerformanceAnalysisReport empty() {return PerformanceAnalysisReport.builder().totalMappings(0).totalErrors(0).averageExecutionTime(0.0).minExecutionTime(0.0).maxExecutionTime(0.0).mapperUsageCount(Collections.emptyMap()).mapperAverageTime(Collections.emptyMap()).performanceBottlenecks(Collections.emptyList()).errorRate(0.0).throughput(0.0).build();}}}
示例 2:配置优化和调优
/**
* 生产环境配置优化
*/
@Configuration
@EnableConfigurationProperties(AtlasMapperOptimizationProperties.class)
public class AtlasMapperOptimizationConfiguration {
/**
* 高性能映射器配置
*/
@Bean
@Primary
public AtlasMapperConfiguration optimizedMapperConfiguration(
AtlasMapperOptimizationProperties properties) {
AtlasMapperConfiguration config = new AtlasMapperConfiguration();
// 性能优化配置
config.setUnmappedTargetPolicy(ReportingPolicy.IGNORE);
config.setSuppressGeneratorTimestamp(true);
config.setSuppressGeneratorVersionComment(true);
// 集合映射优化
config.setCollectionMappingStrategy(CollectionMappingStrategy.ACCESSOR_ONLY);
// 空值处理优化
config.setNullValueMappingStrategy(NullValueMappingStrategy.RETURN_NULL);
config.setNullValueCheckStrategy(NullValueCheckStrategy.ON_IMPLICIT_CONVERSION);
// 代码生成优化
config.setBuilderPattern(properties.isUseBuilderPattern());
config.setInjectionStrategy(InjectionStrategy.FIELD);
return config;
}
/**
* 线程池配置 - 用于并行映射
*/
@Bean("mappingExecutor")
public ThreadPoolTaskExecutor mappingExecutor(AtlasMapperOptimizationProperties properties) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数 = CPU 核心数
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
// 最大线程数 = CPU 核心数 * 2
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);
// 队列容量
executor.setQueueCapacity(properties.getThreadPoolQueueCapacity());
// 线程名前缀
executor.setThreadNamePrefix("atlas-mapper-");
// 拒绝策略:调用者运行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 线程空闲时间
executor.setKeepAliveSeconds(60);
// 允许核心线程超时
executor.setAllowCoreThreadTimeOut(true);
executor.initialize();
return executor;
}
/**
* 缓存配置
*/
@Bean
public CacheManager optimizedCacheManager(AtlasMapperOptimizationProperties properties) {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
Caffeine<Object, Object> caffeine = Caffeine.newBuilder().maximumSize(properties.getCacheMaxSize()).expireAfterWrite(Duration.ofMinutes(properties.getCacheExpireMinutes())).expireAfterAccess(Duration.ofMinutes(properties.getCacheAccessExpireMinutes())).recordStats();cacheManager.setCaffeine(caffeine);return cacheManager;}/*** 对象池配置*/@Beanpublic GenericObjectPoolConfig<Object> objectPoolConfig(AtlasMapperOptimizationProperties properties) {GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();config.setMaxTotal(properties.getObjectPoolMaxTotal());config.setMaxIdle(properties.getObjectPoolMaxIdle());config.setMinIdle(properties.getObjectPoolMinIdle());// 性能优化配置config.setTestOnBorrow(false);config.setTestOnReturn(false);config.setTestWhileIdle(true);config.setTestOnCreate(false);// 驱逐策略config.setTimeBetweenEvictionRunsMillis(Duration.ofMinutes(5).toMillis());config.setMinEvictableIdleTimeMillis(Duration.ofMinutes(10).toMillis());return config;}/*** JVM 优化建议*/@EventListener(ApplicationReadyEvent.class)public void printJvmOptimizationSuggestions() {Runtime runtime = Runtime.getRuntime();long maxMemory = runtime.maxMemory();long totalMemory = runtime.totalMemory();long freeMemory = runtime.freeMemory();log.info("=== Atlas Mapper JVM 优化建议 ===");log.info("最大内存: {} MB", maxMemory / 1024 / 1024);log.info("总内存: {} MB", totalMemory / 1024 / 1024);log.info("空闲内存: {} MB", freeMemory / 1024 / 1024);// 内存建议if (maxMemory < 1024 * 1024 * 1024) { // 小于 1GBlog.warn("建议增加堆内存大小: -Xmx2g");}// GC 建议String gcType = System.getProperty("java.vm.name");if (!gcType.contains("G1")) {log.info("建议使用 G1 垃圾收集器: -XX:+UseG1GC");}// 其他 JVM 参数建议log.info("推荐 JVM 参数:");log.info(" -XX:+UseG1GC");log.info(" -XX:MaxGCPauseMillis=200");log.info(" -XX:+UnlockExperimentalVMOptions");log.info(" -XX:+UseCGroupMemoryLimitForHeap");log.info(" -XX:+PrintGCDetails");log.info(" -XX:+PrintGCTimeStamps");log.info("================================");}}/*** 优化配置属性*/@ConfigurationProperties(prefix = "atlas.mapper.optimization")@Datapublic class AtlasMapperOptimizationProperties {/*** 是否使用建造者模式*/private boolean useBuilderPattern = false;/*** 线程池队列容量*/private int threadPoolQueueCapacity = 1000;/*** 缓存最大大小*/private long cacheMaxSize = 10000;/*** 缓存过期时间(分钟)*/private int cacheExpireMinutes = 30;/*** 缓存访问过期时间(分钟)*/private int cacheAccessExpireMinutes = 10;/*** 对象池最大总数*/private int objectPoolMaxTotal = 100;/*** 对象池最大空闲数*/private int objectPoolMaxIdle = 50;/*** 对象池最小空闲数*/private int objectPoolMinIdle = 10;/*** 是否启用性能监控*/private boolean enablePerformanceMonitoring = true;/*** 是否启用内存优化*/private boolean enableMemoryOptimization = true;/*** 批量处理阈值*/private int batchProcessingThreshold = 1000;/*** 并行处理阈值*/private int parallelProcessingThreshold = 5000;}
效果演示:性能测试和对比
性能基准测试
/**
* 性能基准测试
*/
@Component
public class MappingPerformanceBenchmark {
private final UserMapper standardMapper = Mappers.getMapper(UserMapper.class);
private final HighPerformanceMappingService optimizedService;
private final CachedMappingService cachedService;
public MappingPerformanceBenchmark(HighPerformanceMappingService optimizedService,
CachedMappingService cachedService) {
this.optimizedService = optimizedService;
this.cachedService = cachedService;
}
/**
* 单对象映射性能对比
*/
public void benchmarkSingleObjectMapping() {
User testUser = createTestUser();
int iterations = 100000;
// 标准映射
long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
UserDto dto = standardMapper.toDto(testUser);
}
long standardTime = System.nanoTime() - startTime;
// 优化映射
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
UserDto dto = optimizedService.mapUserWithPool(testUser);
}
long optimizedTime = System.nanoTime() - startTime;
// 缓存映射
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
UserDto dto = cachedService.mapUserWithCache(testUser);
}
long cachedTime = System.nanoTime() - startTime;
// 输出结果
System.out.println("=== 单对象映射性能对比 (" + iterations + " 次) ===");
System.out.println("标准映射: " + formatTime(standardTime));
System.out.println("优化映射: " + formatTime(optimizedTime) + " (提升 " +
String.format("%.1f%%", (double)(standardTime - optimizedTime) / standardTime * 100) + ")");
System.out.println("缓存映射: " + formatTime(cachedTime) + " (提升 " +
String.format("%.1f%%", (double)(standardTime - cachedTime) / standardTime * 100) + ")");
}
/**
* 批量映射性能对比
*/
public void benchmarkBatchMapping() {
List<User> testUsers = createTestUsers(10000);// 标准批量映射long startTime = System.nanoTime();List<UserDto> standardResult = standardMapper.toDtoList(testUsers);long standardTime = System.nanoTime() - startTime;// 优化批量映射startTime = System.nanoTime();List<UserDto> optimizedResult = optimizedService.mapUsersWithOptimization(testUsers);long optimizedTime = System.nanoTime() - startTime;// 并行映射startTime = System.nanoTime();List<UserDto> parallelResult = optimizedService.mapUsersInParallel(testUsers);long parallelTime = System.nanoTime() - startTime;// 缓存批量映射startTime = System.nanoTime();List<UserDto> cachedResult = cachedService.mapUsersWithSmartCache(testUsers);long cachedTime = System.nanoTime() - startTime;// 输出结果System.out.println("=== 批量映射性能对比 (" + testUsers.size() + " 个对象) ===");System.out.println("标准映射: " + formatTime(standardTime));System.out.println("优化映射: " + formatTime(optimizedTime) + " (提升 " +String.format("%.1f%%", (double)(standardTime - optimizedTime) / standardTime * 100) + ")");System.out.println("并行映射: " + formatTime(parallelTime) + " (提升 " +String.format("%.1f%%", (double)(standardTime - parallelTime) / standardTime * 100) + ")");System.out.println("缓存映射: " + formatTime(cachedTime) + " (提升 " +String.format("%.1f%%", (double)(standardTime - cachedTime) / standardTime * 100) + ")");// 验证结果一致性System.out.println("结果验证: " +(standardResult.size() == optimizedResult.size() &&optimizedResult.size() == parallelResult.size() &¶llelResult.size() == cachedResult.size() ? "✓ 通过" : "✗ 失败"));}/*** 内存使用对比*/public void benchmarkMemoryUsage() {List<User> testUsers = createTestUsers(50000);Runtime runtime = Runtime.getRuntime();// 标准映射内存使用runtime.gc();long memoryBefore = runtime.totalMemory() - runtime.freeMemory();List<UserDto> standardResult = standardMapper.toDtoList(testUsers);long memoryAfter = runtime.totalMemory() - runtime.freeMemory();long standardMemory = memoryAfter - memoryBefore;// 优化映射内存使用runtime.gc();memoryBefore = runtime.totalMemory() - runtime.freeMemory();List<UserDto> optimizedResult = optimizedService.mapUsersWithOptimization(testUsers);memoryAfter = runtime.totalMemory() - runtime.freeMemory();long optimizedMemory = memoryAfter - memoryBefore;// 输出结果System.out.println("=== 内存使用对比 (" + testUsers.size() + " 个对象) ===");System.out.println("标准映射: " + formatMemory(standardMemory));System.out.println("优化映射: " + formatMemory(optimizedMemory) + " (节省 " +String.format("%.1f%%", (double)(standardMemory - optimizedMemory) / standardMemory * 100) + ")");}// 辅助方法private User createTestUser() {User user = new User();user.setId(1L);user.setName("测试用户");user.setEmail("test@example.com");user.setCreatedAt(LocalDateTime.now());user.setUpdatedAt(LocalDateTime.now());return user;}private List<User> createTestUsers(int count) {List<User> users = new ArrayList<>(count);for (int i = 0; i < count; i++) {User user = new User();user.setId((long) i);user.setName("用户" + i);user.setEmail("user" + i + "@example.com");user.setCreatedAt(LocalDateTime.now());user.setUpdatedAt(LocalDateTime.now());users.add(user);}return users;}private String formatTime(long nanoTime) {return String.format("%.2f ms", nanoTime / 1_000_000.0);}private String formatMemory(long bytes) {return String.format("%.2f MB", bytes / 1024.0 / 1024.0);}}
运行性能测试
# 运行性能基准测试
curl -X POST http://localhost:8080/api/performance/benchmark/single
curl -X POST http://localhost:8080/api/performance/benchmark/batch
curl -X POST http://localhost:8080/api/performance/benchmark/memory
# 查看性能报告
curl http://localhost:8080/api/performance/report
# 查看缓存统计
curl http://localhost:8080/api/performance/cache-stats
# 查看内存使用
curl http://localhost:8080/api/performance/memory-usage
❓ 常见问题
Q1: 如何选择合适的批次大小?
A: 批次大小选择策略:
// 动态批次大小计算
public int calculateOptimalBatchSize(int totalSize, long availableMemory) {
// 基础批次大小
int baseBatchSize = 1000;
// 根据可用内存调整
long memoryPerObject = 1024; // 估算每个对象 1KB
int memoryBasedBatchSize = (int) (availableMemory / memoryPerObject / 2);
// 根据 CPU 核心数调整
int cpuBasedBatchSize = Runtime.getRuntime().availableProcessors() * 500;
// 取最小值作为安全批次大小
int optimalBatchSize = Math.min(baseBatchSize,
Math.min(memoryBasedBatchSize, cpuBasedBatchSize));
// 确保不超过总大小
return Math.min(optimalBatchSize, totalSize);
}
Q2: 什么时候使用并行映射?
A: 并行映射使用指南:
public boolean shouldUseParallelMapping(List<?> data) {// 数据量小于阈值,使用串行if (data.size() < 1000) {return false;}// CPU 核心数少于 2,使用串行if (Runtime.getRuntime().availableProcessors() < 2) {return false;}// 当前系统负载高,使用串行if (getCurrentCpuUsage() > 0.8) {return false;}// 映射操作复杂度高,使用并行return true;}
Q3: 如何监控映射性能?
A: 性能监控最佳实践:
// 1. 使用 AOP 进行方法级监控
@Around("@within(io.github.nemoob.atlas.mapper.Mapper)")
public Object monitorMapping(ProceedingJoinPoint joinPoint) throws Throwable {
return performanceMonitor.monitorMapping(
joinPoint.getTarget().getClass().getSimpleName(),
joinPoint.getSignature().getName(),
() -> {
try {
return joinPoint.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
);
}
// 2. 使用 Micrometer 指标
@Timed(name = "atlas.mapper.execution", description = "Atlas Mapper execution time")
public UserDto mapUser(User user) {
return userMapper.toDto(user);
}
// 3. 自定义性能收集器
public class CustomPerformanceCollector {
public void recordMappingMetrics(String mapperName, long executionTime, boolean success) {
// 发送到监控系统
}
}
Q4: 如何优化大对象映射?
A: 大对象优化策略:
// 1. 分段映射
public LargeObjectDto mapLargeObject(LargeObject obj) {
LargeObjectDto dto = new LargeObjectDto();
// 分段映射基础字段
mapBasicFields(obj, dto);
// 异步映射复杂字段
CompletableFuture.runAsync(() -> mapComplexFields(obj, dto));
return dto;
}
// 2. 懒加载映射
public class LazyMappedDto {
private Supplier<ComplexDto> complexData =Suppliers.memoize(() -> mapper.mapComplex(source.getComplexData()));public ComplexDto getComplexData() {return complexData.get();}}// 3. 流式映射public Stream<ItemDto> mapLargeCollection(List<Item> items) {return items.stream().map(mapper::toDto).filter(Objects::nonNull);}
本章小结
通过本章学习,你应该掌握了:
- 编译时优化:Mapper 配置和代码生成优化
- 运行时优化:对象池化、缓存策略和批量处理
- 内存优化:内存管理和垃圾回收优化
- 性能监控:指标收集、性能分析和告警机制
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/937233.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!相关文章
新买的笔记本电脑如何将旧笔记本数据迁移完整迁移克隆过来?买了新电脑,旧电脑大量数据如何迁移?
简单说,固态硬盘(SSD)和机械硬盘(HDD)就像两种“装东西的盒子”,区别主要在“取东西快不快”“结不结实”“贵不贵”这几点,用老百姓的话讲更直白:机械硬盘(HDD):像家里的“老式抽屉柜”,要拿东西得先拉开…
Nginx proxy_pass 末尾斜杠(/) - 详解
pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …
反射型XSS与自反型XSS深度解析
本视频深入探讨了反射型XSS和自反型XSS漏洞的区别与危害,通过实际案例演示如何识别和利用这些漏洞,并解释了为什么看似简单的漏洞却能带来高额赏金回报。反射型XSS与自反型XSS
视频概览发布时间:2025年8月12日
观看…
Markdown 是一种「用肉眼就能看懂」标记语言
Markdown 是一种「用肉眼就能看懂」的纯文本标记语言。
它的设计哲学只有一句话:让源文件本身就能读,同时让机器一键转成漂亮的 HTML/PDF/Word 等格式。
核心特点语法只占用了键盘上最常见的符号(# * _ > [] ()…
实用指南:oracle linux 10 +pg18 源码安装要点
pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …
Java 与智慧能源:分布式能源与智能电网管理
一、引言
能源是社会发展的基础动力。随着 全球能源转型、碳中和目标、可再生能源普及,传统电力系统正经历深刻变革。分布式能源、智能电网、储能与能源互联网 已成为未来能源发展的核心方向。
然而,能源系统面临的挑…
PHP 真异步 TrueAsync SAPI 与 NGINX Unit 集成
PHP "真异步" TrueAsync SAPI 与 NGINX Unit 集成
现在的 Web 开发和过去最大的区别是什么?一句话:没人再愿意等服务器响应了。
七八年前,甚至更早的时候,模块加载、组件打包、脚本解释、数据库查询——…
Qt下设置Linux系统时间
Qt下设置Linux系统时间include <sys/time.h>
bool SysTime(int nYear,int nMonth,int nDay,int nHours,int nMin,int nSecond) {
QDateTime dateTime;
dateTime.setDate(QDate(nYear, nMonth, nDay));
dateTime…
GitHub Spark引领Vibe编程与AI技术新趋势
本期节目探讨GitHub推出的Vibe编程工具Spark如何通过自然语言开发全栈应用,分析AI编码工具的数据安全问题,介绍科学推理与代码性能优化新数据集,并解读美国AI行动计划的技术战略布局。工具与应用某中心推出Vibe编程…
详细介绍:如何在 Apache 中启用 HSTS 以增强网络安全性 ?
详细介绍:如何在 Apache 中启用 HSTS 以增强网络安全性 ?pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consol…
Java 与智慧环保:生态监测与低碳治理
一、引言
环境保护是人类社会可持续发展的核心议题。随着 气候变化、环境污染、资源消耗 等问题的加剧,传统的环保手段难以满足当下高效、实时、精准的需求。智慧环保的目标是:通过信息技术、物联网、人工智能、大数…
VMware ESXi 9.0.1.0 macOS Unlocker OEM BIOS 2.7 Huawei 华为 定制版
VMware ESXi 9.0.1.0 macOS Unlocker & OEM BIOS 2.7 Huawei 华为 定制版VMware ESXi 9.0.1.0 macOS Unlocker & OEM BIOS 2.7 Huawei 华为 定制版
VMware ESXi 9.0.1.0 macOS Unlocker & OEM BIOS 2.7 标…
通过ctypesgen 快速生成ctypes 代码
通过ctypesgen 快速生成ctypes 代码ctypesgen 是一个很不错的工具,可以帮助我们快速的生成ctypes代码,方便python对于c/c++ 代码的访问,实际上有一些扩展,比如原生的以及pypdfium2-team fork 修改的
参考使用命令
…
VMware ESXi 9.0.1.0 macOS Unlocker OEM BIOS 2.7 xFusion 超聚变 定制版
VMware ESXi 9.0.1.0 macOS Unlocker & OEM BIOS 2.7 xFusion 超聚变 定制版VMware ESXi 9.0.1.0 macOS Unlocker & OEM BIOS 2.7 xFusion 超聚变 定制版
VMware ESXi 9.0.1.0 macOS Unlocker & OEM BIOS …
完整教程:从格伦的角度理解信息哲学
完整教程:从格伦的角度理解信息哲学2025-10-15 08:00
tlnshuju
阅读(0)
评论(0) 收藏
举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !im…
[AI] AI深度伪造欺诈防范
1 AI深度伪造概念
AI深度伪造欺诈现状科技进步始终伴随机遇与挑战,AI深度伪造技术便是典型代表。作为人工智能领域的前沿技术,其正以超乎想象的速度渗透进社会生活,在推动创新应用的同时,也带来了数据安全、伦理信…
[AI/AI中台] AI应用开发平台:Coze、Dify、阿里百炼、N8N、FastGPT
1 序面对越来越多的智能体平台,产品人该如何选型?本文将从功能定位、协同方式、应用场景等维度,系统梳理 Coze、Dify、百炼、N8N、Maxkb、Fastgpt 的异同,并提供一套实用的工具链搭建思路。2 概述:AI开发平台各AI…
【GitHub每日速递 251015】爆火, 20k star!小智 AI 聊天机器人多端控制+70 多个开源硬件支持,大模型应用新玩法
原文:https://mp.weixin.qq.com/s/5CtkdQwiFOPalmQQhoEsIA
TypeScript+GraphQL+React,EverShop让你快速搭建定制化电商平台!
evershop 是一个基于 TypeScript 的开源电商建站平台。简单讲,它是一个用TypeScript开发…
Voice Agent 开发者第一课:成为进阶语音 AI 玩家,你需要了解这些丨Convo AIRTE2025
想让你的语音智能体兼具前沿创新与丝滑体验?从一个 demo 到实际可落地的产品,必须掌握哪些实时互动与 AI 的核心技术栈?北京,11 月 1 日上午 ,在由 声网和 RTE 开发者社区 联合主办的 Convo AI&RTE2025 「实时…
C++内存管理的那些坑与经验
C++内存管理的那些坑与经验 🧠
C++ 的内存管理既灵活又危险。不同于 Java 的垃圾回收机制,C++ 让程序员完全掌控内存的申请与释放。
最常见的问题包括内存泄漏、悬空指针、重复释放等。例如:```cppint* p = new in…