在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
相关产品推荐
相关产品推荐

