我試圖提供一個通用javax.cache
兼容適配器類javax.cache.configuration.FactoryBuilder
檢索工廠,然後由ignite
實例化緩存。所描述的問題可能會使用Apache Ignite,但是,我相信它不一定與Ignite相關,但更多的是泛型和閉包在Java中的工作方式。工廠從泛型高速緩存適配器類指針使用FactoryBuilder
Ignite CacheStoreAdapter
接口繼承自javax.cache.CacheLoader
和javax.cache.CacheWriter
,我提供了一個適配器實現。該實現需要緩存鍵和值的兩個(通用)類型以及值類引用,以便能夠實例化適配器中的值。請參閱下面的部分課程MyCacheAdapter
。
public class MyCacheAdapter<K,V extends StorableModel> extends CacheStoreAdapter<K,V> implements LifecycleAware {
private final Class<V> valueClazz;
public MyCacheAdapter(Class<V> valueClass) {
this.valueClazz = valueClass;
}
@Override
public V load(K key) throws CacheLoaderException {
// load from database
return valueClazz.newInstance(); // dummy instantiation
}
@Override
public void write(Cache.Entry<? extends K, ? extends V> entry) throws CacheWriterException {
// write to database
}
}
現在,當我明確聲明的適配器,並將其提供給FactoryBuilder
一切正常......
public class MyPersonAdapter extends MyCacheAdapter<String,Person> {
public MyPersonAdapter() {
super(Person.class);
}
}
...當緩存我的服務啓動被實例化。
// run init cache (on 1st node only)
public <K,V extends StorableModel> void init() {
CacheConfiguration cacheConfiguration = new CacheConfiguration<K,V>();
cacheConfiguration.setCacheStoreFactory(FactoryBuilder.factoryOf(MyPersonAdapter.class));
// add node filter to prevent other nodes from failing on cache distribution
cacheConfiguration.setNodeFilter((node) -> { // exclude 2nd node });
ignite.getOrCreateCache(cacheConfiguration);
}
到目前爲止的工作實例!現在我不想明確聲明MyPersonAdapter
(還有幾十個),而是讓我的初學者根據提供的類型和鍵/值類來處理適配器細節。所以,我可以提供我自己的工廠......
public static class AdapterFactory<K,V extends StorableModel> implements Factory<CacheStore<? super K, ? super V>> {
private final Class<V> valueClass;
public AdapterFactory(Class<V> valueClass) {
this.valueClass = valueClass;
}
@Override public CacheStore<? super K, ? super V> create() {
return new MyCacheAdapter<K,V>(valueClass);
}
}
...,然後在高速緩存初始化像這樣使用:
// run init cache (on 1st node only)
public <K,V extends StorableModel> void init(Class<V> valueClass) {
CacheConfiguration cacheConfiguration = new CacheConfiguration<K,V>();
cacheConfiguration.setCacheStoreFactory(new AdapterFactory<K,V>(valueClass));
// add node filter to prevent other nodes from failing on cache distribution
cacheConfiguration.setNodeFilter((node) -> { // exclude 2nd node });
ignite.getOrCreateCache(cacheConfiguration);
}
但是,這將引發我java.lang.ClassNotFoundException
對我的第二個值類因爲該類不在第二個節點的類路徑中,所以點燃節點。我絕對不想提供那個類,我在問自己,第一個實現有什麼不同。我知道工廠在需要的時候確實創建了一個實例(當緩存分發到另一個節點時),它必須知道它沒有的值類。所以我嘗試了另一個實現來接近第一個(工作)的實現。相反,提供我自己的工廠,我想我有明確的適配器初始化嵌套類前右聲明:
public <K,V extends StorableModel> void init(Class<V> valueClass) {
class DynamicAdapter extends MyCacheAdapter<K,V> {
public DynamicAdapter() {
super(valueClass);
}
}
CacheConfiguration cacheConfiguration = new CacheConfiguration<K,V>();
cacheConfiguration.setCacheStoreFactory(FactoryBuilder.factoryOf(DynamicAdapter.class));
// add node filter to prevent other nodes from failing on cache distribution
cacheConfiguration.setNodeFilter((node) -> { // exclude 2nd node });
ignite.getOrCreateCache(cacheConfiguration);
}
這再次引發了我的InstationException
因爲類是超出範圍的工廠,我猜。
java.lang.RuntimeException: Failed to create an instance of DynamicAdapter
Caused by: java.lang.InstantiationException: DynamicAdapter
Caused by: java.lang.NoSuchMethodException: DynamicAdapter.<init>()
所以,我想知道如果有一種方法來實現我的目標沒有一個自定義的工廠和類分佈跨越服務(這是沒辦法),但仍然有一些動態適配器聲明。
UPDATE
堆棧跟蹤的InstantiationException
上課時由靜態方法返回
private static <X,Y extends StorableModel> Class getAdapterClass(Class<Y> valueClass) {
class MyClass extends MongoIgniteCacheAdapter<X,Y> {
MyClass() {
super(valueClass);
}
}
return MyClass.class;
}
// run init cache (on 1st node only)
public <K,V extends StorableModel> void init() {
CacheConfiguration cacheConfiguration = new CacheConfiguration<K,V>();
cacheConfiguration.setCacheStoreFactory(FactoryBuilder.factoryOf(getAdapterClass(valueClass)));
// add node filter to prevent other nodes from failing on cache distribution
cacheConfiguration.setNodeFilter((node) -> { // exclude 2nd node });
ignite.getOrCreateCache(cacheConfiguration);
}
// output
class org.apache.ignite.IgniteCheckedException: Failed to create an instance of IgniteServiceStarter$1MyClass
at org.apache.ignite.internal.util.IgniteUtils.cast(IgniteUtils.java:7242)
at org.apache.ignite.internal.util.future.GridFutureAdapter.resolve(GridFutureAdapter.java:258)
at org.apache.ignite.internal.util.future.GridFutureAdapter.get0(GridFutureAdapter.java:206)
at org.apache.ignite.internal.util.future.GridFutureAdapter.get(GridFutureAdapter.java:158)
at org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager$ExchangeWorker.body(GridCachePartitionExchangeManager.java:1812)
at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:110)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException: Failed to create an instance of IgniteServiceStarter$1MyClass
at javax.cache.configuration.FactoryBuilder$ClassFactory.create(FactoryBuilder.java:134)
at org.apache.ignite.internal.processors.cache.GridCacheProcessor.createCache(GridCacheProcessor.java:1458)
at org.apache.ignite.internal.processors.cache.GridCacheProcessor.prepareCacheStart(GridCacheProcessor.java:1931)
at org.apache.ignite.internal.processors.cache.GridCacheProcessor.prepareCacheStart(GridCacheProcessor.java:1833)
at org.apache.ignite.internal.processors.cache.CacheAffinitySharedManager.onCacheChangeRequest(CacheAffinitySharedManager.java:379)
at org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture.onCacheChangeRequest(GridDhtPartitionsExchangeFuture.java:688)
at org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture.init(GridDhtPartitionsExchangeFuture.java:529)
at org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager$ExchangeWorker.body(GridCachePartitionExchangeManager.java:1806)
... 2 more
Caused by: java.lang.InstantiationException: IgniteServiceStarter$1MyClass
at java.lang.Class.newInstance(Class.java:427)
at javax.cache.configuration.FactoryBuilder$ClassFactory.create(FactoryBuilder.java:132)
... 9 more
Caused by: java.lang.NoSuchMethodException: IgniteServiceStarter$1MyClass.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 10 more
您應該發佈'ClassNotFoundException'的堆棧跟蹤。 – Radiodef