我想在 OSGi 蓝图中为咖啡因缓存应用 camel-jcache 路由策略。
当我向蓝图中添加缓存配置时,如下所示:
<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">
<!-- see src/main/resources/application.conf for cache expiration policy -->
<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>
然后蓝图包无法在
NullPointerException
处以 BeanRecipe.setProperties
开头。
我能够将其追溯到类加载器问题。我要求一个名为
konfig-cache
的缓存,但该缓存的配置位于捆绑资源中的文件 application.conf 中(Typesafe Config 中自定义配置的默认位置)。 OSGi 运行时无法使用默认类加载器加载该文件。
如何定义 Caffeine 底层 Typesafe Config 应该使用的类加载器来在 Blueprint 包的资源中定位配置文件?
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</g
<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:
# Configuration for camel-caffeine in HOCON format
# see https://github.com/lightbend/config/blob/master/HOCON.md#hocon-human-optimized-config-object-notation
# see https://github.com/lightbend/config#standard-behavior
# see https://github.com/ben-manes/caffeine/blob/master/jcache/src/main/resources/reference.conf
# see example https://github.com/ben-manes/caffeine/blob/master/jcache/src/test/resources/application.conf
caffeine.jcache {
konfig-cache {
key-type = java.lang.String
value-type = java.lang.Object
# The eviction policy for automatically removing entries from the cache
policy {
# The expiration threshold before lazily evicting an entry. This single threshold is reset on
# every operation where a duration is specified. As expected by the specification, if an entry
# expires but is not accessed and no resource constraints force eviction, then the expired
# entry remains in place.
lazy-expiration {
# The duration before a newly created entry is considered expired. If set to 0 then the
# entry is considered to be already expired and will not be added to the cache. May be
# a time duration or "eternal" to indicate no expiration.
creation = 60m
# The duration before a updated entry is considered expired. If set to 0 then the entry is
# considered immediately expired. May be a time duration, null to indicate no change, or
# "eternal" to indicate no expiration.
update = 60m
# The duration before a read of an entry is considered expired. If set to 0 then the entry
# is considered immediately expired. May be a time duration, null to indicate no change, or
# "eternal" to indicate no expiration.
access = null
}
# The expiration thresholds before eagerly evicting an entry. These settings correspond to the
# expiration supported natively by Caffeine where expired entries are collected during
# maintenance operations.
#eager-expiration {
# Specifies that each entry should be automatically removed from the cache once a fixed
# duration has elapsed after the entry's creation, or the most recent replacement of its
# value. This setting cannot be combined with the variable configuration.
#after-write = null
# Specifies that each entry should be automatically removed from the cache once a fixed
# duration has elapsed after the entry's creation, the most recent replacement of its value,
# or its last read. Access time is reset by all cache read and write operation. This setting
# cannot be combined with the variable configuration.
#after-access = null
# The expiry class to use when calculating the expiration time of cache entries. This
# setting cannot be combined with after-write or after-access configurations.
#variable = null
}
# The threshold before an entry is eligible to be automatically refreshed when the first stale
# request for an entry occurs. This setting is honored only when combined with the
# read-through configuration.
#refresh {
# Specifies that active entries are eligible for automatic refresh once a fixed duration has
# elapsed after the entry's creation or the most recent replacement of its value.
#after-write = 30s
#}
# The maximum bounding of the cache based upon its logical size
maximum {
# The maximum number of entries that can be held by the cache. This setting cannot be
# combined with the weight configuration.
size = 10
}
}
}
CaffeineCachingProvider 允许将类加载器传递给
CachingProvider.getCacheManager(URI uri, ClassLoader classLoader)
。
预期的 URI 只是 CaffeineCachingProvider 的 FQCN。
现在是类加载器。在 OSGi 蓝图中,我们可以确定蓝图包的类加载器并将其传递给
getCacheManager
。蓝图规范定义了许多具有预定义参考名称的环境管理器,其中包括蓝图包本身,其名称为blueprintBundle
。
因为无论如何我们都在使用 Camel,所以我们可以使用 Camel 的 BundleDelegatingClassLoader 来简化对包的类加载器的访问:
<bean id="caffeineCacheManager" factory-ref="cachingProvider" factory-method="getCacheManager">
<argument value="com.github.benmanes.caffeine.jcache.spi.CaffeineCachingProvider"/>
<argument>
<bean class="org.apache.camel.core.osgi.utils.BundleDelegatingClassLoader">
<argument ref="blueprintBundle"/>
</bean>
</argument>
</bean>