当前位置: 首页 > news >正文

environment.resolvePlaceholders占位符解析优化

文章目录

  • 占位符解析
    • 1、原始实现:无缓存解析
    • 2、优化实现:缓存解析结果

占位符解析

  • 问题背景:在多数据源切换场景中,environment.resolvePlaceholders(value) 用于解析配置文件中的占位符(如 ${db.master})。如果频繁调用此方法,尤其是在高并发场景下,重复解析相同的占位符字符串会带来不必要的性能开销。通过对比优化前后的实现,验证缓存占位符解析结果对性能的提升。

1、原始实现:无缓存解析

以下代码每次调用时直接解析占位符:

public class OriginalDataSourceResolver {

    private Environment environment;

    public String resolve(String dataSourceId) {
        // 每次调用都解析占位符
        return environment.resolvePlaceholders(dataSourceId);
    }
}

性能问题:

  • dataSourceId 是固定值(如 ${db.master})时,每次解析相同字符串,重复计算
  • resolvePlaceholders 内部需遍历 PropertySources,解析嵌套占位符(如 ${db.${env}.url}),存在计算开销

2、优化实现:缓存解析结果

通过 ConcurrentHashMap 缓存已解析的值:

public class OptimizedDataSourceResolver {

    private Environment environment;

    private final Map<String, String> cache = new ConcurrentHashMap<>();

    public String resolve(String dataSourceId) {
        // 使用缓存避免重复解析
        return cache.computeIfAbsent(dataSourceId, environment::resolvePlaceholders);
    }
}

优化关键:

  • 相同 dataSourceId 仅解析一次,后续直接从缓存读取。

性能测试验证:JMH基准测试

测试目标:对比无缓存与有缓存的解析性能

  • 测试数据:
    • 简单占位符:${db.master}
    • 复杂占位符:${db.${env}.url}
  • 并发量:模拟 16 个线程并发调用
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Thread)
@Fork(value = 4)
@Warmup(iterations = 5, time = 5)
@Measurement(iterations = 5, time = 10)
@Threads(16)
public class PlaceholderResolveBenchmark {

    private OriginalDataSourceResolver originalResolver;

    private OptimizedDataSourceResolver optimizedResolver;

    private final String simplePlaceholder = "${db.master}";

    private final String complexPlaceholder = "${db.${env}.url}";

    @Setup(Level.Trial)
    public void setup() {
        MockEnvironment env = new MockEnvironment();
        env.setProperty("db.master", "masterDataSource");
        env.setProperty("env", "prod");
        env.setProperty("db.prod.url", "jdbc:mysql://localhost:3306/db");

        originalResolver = new OriginalDataSourceResolver();
        originalResolver.setEnvironment(env);

        optimizedResolver = new OptimizedDataSourceResolver();
        optimizedResolver.setEnvironment(env);
    }

    /**
     * 测试原始解析器-简单占位符
     * @param bh
     */
    @Benchmark
    public void testOriginalResolver_Simple(Blackhole bh) {
        String result = originalResolver.resolve(simplePlaceholder);
        bh.consume(result);
    }

    /**
     * 测试优化解析器-简单占位符
     * @param bh
     */
    @Benchmark
    public void testOptimizedResolver_Simple(Blackhole bh) {
        String result = optimizedResolver.resolve(simplePlaceholder);
        bh.consume(result);
    }

    /**
     * 测试原始解析器-复杂占位符
     * @param bh
     */
    @Benchmark
    public void testOriginalResolver_Complex(Blackhole bh) {
        String result = originalResolver.resolve(complexPlaceholder);
        bh.consume(result);
    }

    /**
     * 测试优化解析器-复杂占位符
     * @param bh
     */
    @Benchmark
    public void testOptimizedResolver_Complex(Blackhole bh) {
        String result = optimizedResolver.resolve(complexPlaceholder);
        bh.consume(result);
    }
}

测试结果及分析

  • 测试结果如下:
Benchmark                                                      Mode  Cnt       Score       Error   Units
TT.PlaceholderResolveBenchmark.testOptimizedResolver_Complex  thrpt   20  315340.801 ± 59664.044  ops/ms
TT.PlaceholderResolveBenchmark.testOptimizedResolver_Simple   thrpt   20  332918.070 ± 51588.217  ops/ms
TT.PlaceholderResolveBenchmark.testOriginalResolver_Complex   thrpt   20      18.058 ±     2.609  ops/ms
TT.PlaceholderResolveBenchmark.testOriginalResolver_Simple    thrpt   20      36.011 ±     3.894  ops/ms
  • 结论:

优化后的 OptimizedDataSourceResolver 性能提升显著,吞吐量达到原始方案的 10,000 倍,缓存策略对高频占位符解析场景有非常明显的优化效果。

相关文章:

  • 分布式事务中XA 事务 和 两阶段提交(2PC)应该如何理解?
  • 自定义日志回调函数实现第三方库日志集成:从理论到实战
  • 前端面试:px 如何转为 rem
  • mysql select distinct 和 group by 哪个效率高
  • 单一责任原则在Java设计模式中的深度解析
  • 完全二叉树节点的数量 平衡二叉树
  • 【视频】SRS将RTMP转WebRTC、HLS流;获取RTSP转其它流
  • JavaScript 运算符详解
  • 关于stac和clac的进一步细节及EFLAGS
  • 蓝桥备赛(18)- 红黑树和 set 与 map(上)
  • 每日一题力扣2697.字典序最小回文串c++
  • (每日一题) 力扣 179 最大数
  • unittest vs pytest区别
  • Proser:新增指令批次发送功能
  • 全外显子检测家系三样本联合分析+新发变异检测分析
  • 在 CentOS 7 上安装 PHP 7.3
  • SpaceClaim二次开发(3)
  • Android IdleHandler 原理解析与应用场景
  • Android 14 昼夜色切换多屏时候非主屏的Activity无法收到onConfigurationChanged
  • C语言之数据结构:理解什么是数据结构和算法(启航)
  • 做网站 毕业设计/上海网站制作公司
  • 网站制作多久/缅甸在线今日新闻
  • 做网站需要什么花费/凡科建站网站
  • 做公司网站的模板/北京网站制作设计
  • 不用下载的行情网站/百度推广网站一年多少钱
  • 化妆品公司网站源码/优化营商环境