You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在OSGi Blueprint中使用Camel JCachePolicy搭配Caffeine缓存的问题

在OSGi Blueprint中配置Camel JCache+Caffeine缓存的类加载器问题

问题描述

我需要在OSGi Blueprint环境下,使用Camel JCache路由策略结合Caffeine缓存,将指定路由段的操作结果缓存起来。路由配置如下:

<route id="my-konfig">
    <from uri="direct:my-konfig"/>
    <policy ref="jCachePolicy">
        <toD uri="...  enrichment调用 ..."/>
        <transform>
            ... 耗时转换操作 ...
        </transform>
    </policy>
</route>

但添加以下缓存配置后,Blueprint Bundle启动失败,抛出BeanRecipe.setProperties处的NullPointerException:

<reference id="cachingProvider" interface="javax.cache.spi.CachingProvider"/>
<bean id="caffeineCacheManager" factory-ref="cachingProvider" factory-method="getCacheManager"/>
<bean id="caffeineCache" factory-ref="caffeineCacheManager" factory-method="getCache">
    <!-- 缓存过期策略配置在src/main/resources/application.conf -->
    <argument value="konfig-cache"/>
</bean>
<bean id="jCachePolicy" class="org.apache.camel.component.jcache.policy.JCachePolicy">
    <property name="cache" ref="caffeineCache"/>
    <property name="keyExpression">
        <bean class="org.apache.camel.model.language.SimpleExpression">
            <property name="expression" value="${exchangeProperty.typNr}"/>
        </bean>
    </property>
</bean>

经排查,问题根源是类加载器:缓存konfig-cache的配置存放在当前Bundle的application.conf资源文件中,但OSGi运行时的默认类加载器无法访问该文件。需要解决的核心问题是:如何指定Caffeine底层Typesafe Config使用的类加载器,使其能加载Blueprint Bundle内的配置文件?

相关依赖与配置

pom.xml依赖

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-jsonpath</artifactId>
    <version>${camel.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-jcache</artifactId>
    <version>${camel.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-caffeine</artifactId>
    <version>${camel.version}</version>
</dependency>
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>jcache</artifactId>
    <version>2.9.2</version>
</dependency>

Karaf feature.xml配置

<feature version="${camel.version}">camel-jcache</feature>
<feature version="${camel.version}">camel-caffeine</feature>
<bundle>mvn:com.github.ben-manes.caffeine/jcache/2.9.2</bundle>
<bundle>mvn:com.typesafe/config/1.4.2</bundle>

src/main/resources/application.conf

# 采用HOCON格式配置camel-caffeine
# 配置规则参考Caffeine JCache默认配置及Typesafe Config规范
caffeine.jcache {

  konfig-cache {
    key-type = java.lang.String
    value-type = java.lang.Object

    # 缓存自动淘汰策略
    policy {
      # 惰性过期:仅在访问时检查过期,未访问的过期条目会保留直到资源紧张
      lazy-expiration {
        # 条目创建后多久过期,支持时间单位或"eternal"表示永不过期
        creation = 60m
        # 条目更新后多久过期,null表示沿用创建时的配置
        update = 60m
        # 条目读取后多久过期,null表示不修改过期时间
        access = null
      }

      # 主动过期:由Caffeine定期维护清理过期条目(当前未启用)
      #eager-expiration {
      #after-write = null
      #after-access = null
      #variable = null
      #}
    }

    # 自动刷新配置(当前未启用)
    #refresh {
    #after-write = 30s
    #}

    # 缓存容量限制
    maximum {
      # 最大缓存条目数
      size = 10
    }
  }
}

解决方案

1. 基于Bundle类加载器初始化Cache组件

OSGi中默认CachingProvider使用系统类加载器,无法访问当前Bundle的资源。需要通过Blueprint获取当前Bundle的类加载器,并传入Caffeine的初始化流程:

修改Blueprint配置如下:

<!-- 引用当前Bundle的上下文 -->
<reference id="bundleContext" interface="org.osgi.framework.BundleContext"/>

<!-- 获取当前Bundle的类加载器 -->
<bean id="bundleClassLoader" factory-ref="bundleContext" factory-method="getBundle">
    <method name="getClassLoader"/>
</bean>

<!-- 使用Bundle类加载器获取CachingProvider -->
<bean id="cachingProvider" class="javax.cache.Caching" factory-method="getCachingProvider">
    <argument ref="bundleClassLoader"/>
</bean>

<!-- 用指定类加载器初始化CacheManager -->
<bean id="caffeineCacheManager" factory-ref="cachingProvider" factory-method="getCacheManager">
    <argument><null/></argument> <!-- 使用默认URI -->
    <argument><null/></argument> <!-- 使用默认配置源 -->
    <argument ref="bundleClassLoader"/> <!-- 传入Bundle类加载器 -->
</bean>

<!-- 缓存实例及JCache策略配置保持不变 -->
<bean id="caffeineCache" factory-ref="caffeineCacheManager" factory-method="getCache">
    <argument value="konfig-cache"/>
</bean>
<bean id="jCachePolicy" class="org.apache.camel.component.jcache.policy.JCachePolicy">
    <property name="cache" ref="caffeineCache"/>
    <property name="keyExpression">
        <bean class="org.apache.camel.model.language.SimpleExpression">
            <property name="expression" value="${exchangeProperty.typNr}"/>
        </bean>
    </property>
</bean>

2. 确保Bundle资源可被类加载器访问

在Bundle的MANIFEST.MF中添加以下配置,保证application.conf能被类加载器扫描到:

Bundle-ClassPath: .
Import-Package: com.typesafe.config,
 com.github.ben-manes.caffeine.jcache,
 javax.cache.spi,
 org.apache.camel.component.jcache.policy,
 org.apache.camel.model.language

3. 验证配置加载逻辑

修改后,Caffeine会通过当前Bundle的类加载器加载application.conf,正确初始化konfig-cache的配置参数,避免因配置未加载导致的NullPointerException。


内容的提问来源于stack exchange,提问作者dschulten

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:29:52