我试图提供一个通用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