使用Autowired注释的空指针异常 - Gemfire Listerner

时间:2017-05-05 16:19:08

标签: spring spring-data-cassandra gemfire spring-data-gemfire

我把所有的卡桑德拉都变成了单班。当我尝试在gemfire缓存监听器中创建CassandraOperations实例时,获取空指针异常。可以请你帮我解决这个错误

我没有收到任何使用spring和cassandra的空指针异常,但是在与gemfire集成时获取。

@Component  
public class CacheListener<K, V> extends CacheListenerAdapter<K, V> implements Declarable {

@Autowired
private CassandraOperations cassandraOperations;

@Override
public void init(Properties props) {

}

public void afterCreate(EntryEvent e) {
    cassandraOperations.insert(e.getNewValue());

}

@Override
public void close() {
}

}



public class CassandraConfig {
@Autowired
private Environment environment;
private static final Logger LOGGER = LoggerFactory.getLogger(CassandraConfig.class);
@Bean
public CassandraClusterFactoryBean cluster() {
    CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
    cluster.setContactPoints(environment.getProperty("cassandra.contactpoints"));
    cluster.setPort(Integer.parseInt(environment.getProperty("cassandra.port")));
    return cluster;
}
@Bean
public CassandraMappingContext mappingContext() {
    BasicCassandraMappingContext mappingContext = new BasicCassandraMappingContext(); 
    mappingContext.setUserTypeResolver(new SimpleUserTypeResolver(cluster().getObject(), environment.getProperty("cassandra.keyspace"))); return mappingContext;
}
@Bean
public CassandraConverter converter() {
    return new MappingCassandraConverter(mappingContext());
}
@Bean
public CassandraSessionFactoryBean session() throws Exception {
    CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
    session.setCluster(cluster().getObject());
    session.setKeyspaceName(environment.getProperty("cassandra.keyspace"));
    session.setConverter(converter());
    session.setSchemaAction(SchemaAction.NONE);
    return session;
}
@Bean
public CassandraOperations cassandraTemplate() throws Exception {
    return new CassandraTemplate(session().getObject());
}
}

异常

[error 2017/05/05 11:16:04.874 CDT <http-nio-7878-exec-1> tid=0x5b] Exception occurred in CacheListener
java.lang.NullPointerException
    at CacheListener.afterCreate(CacheListener.java:27)
    at com.gemstone.gemfire.internal.cache.EnumListenerEvent$AFTER_CREATE.dispatchEvent(EnumListenerEvent.java:97)
    at com.gemstone.gemfire.internal.cache.LocalRegion.dispatchEvent(LocalRegion.java:8897)
    at com.gemstone.gemfire.internal.cache.LocalRegion.dispatchListenerEvent(LocalRegion.java:7376)
    at com.gemstone.gemfire.internal.cache.LocalRegion.invokePutCallbacks(LocalRegion.java:6158)
    at com.gemstone.gemfire.internal.cache.EntryEventImpl.invokeCallbacks(EntryEventImpl.java:1919)
    at com.gemstone.gemfire.internal.cache.ProxyRegionMap$ProxyRegionEntry.dispatchListenerEvents(ProxyRegionMap.java:548)
    at com.gemstone.gemfire.internal.cache.LocalRegion.basicPutPart2(LocalRegion.java:6012)
    at com.gemstone.gemfire.internal.cache.ProxyRegionMap.basicPut(ProxyRegionMap.java:232)
    at com.gemstone.gemfire.internal.cache.LocalRegion.virtualPut(LocalRegion.java:5824)
    at com.gemstone.gemfire.internal.cache.LocalRegionDataView.putEntry(LocalRegionDataView.java:118)
    at com.gemstone.gemfire.internal.cache.LocalRegion.basicPut(LocalRegion.java:5214)
    at com.gemstone.gemfire.internal.cache.LocalRegion.validatedPut(LocalRegion.java:1597)
    at com.gemstone.gemfire.internal.cache.LocalRegion.put(LocalRegion.java:1580)
    at com.gemstone.gemfire.internal.cache.AbstractRegion.put(AbstractRegion.java:327)
    at org.springframework.data.gemfire.GemfireTemplate.put(GemfireTemplate.java:189)
    at org.springframework.data.gemfire.repository.support.SimpleGemfireRepository.save(SimpleGemfireRepository.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)

1 个答案:

答案 0 :(得分:-1)

上面的代码/配置中没有明显的是您如何使用 Spring Data GemFire )配置特定于应用程序的GemFire CacheListener。< / p>

我看到您使用 Spring的 CacheListener立体声类型注释对您的应用@Component进行了注释,但如果没有帮助,这样做无效。

您使用的是 Spring的 Classpath component scanning功能,还是 Spring的 Annotation-based container configuration支持?如果你使用的是后者,你知道你还必须在config(JavaConfig或XML)中明确定义你的应用程序CacheListener,对吗?

每当您在NullPointerException组件/协作者字段上遇到@Autowired以注入依赖项时,尤其是在使用 Spring @Autowired注释时,这是一个很好的指示你有一个配置问题,特别是因为@Autowired注释意味着“依赖”(例如CassandraOperations)是“ required ”(除非你明确设置required } @Autowired注释的属性为 false ,您没有; required默认为 true )。

因此,如果在扫描中拾取了CacheListener组件并且无法注入依赖项(自动连线),因为没有指定类型的(其他)bean(例如CassandraOperations)在 Spring 应用程序上下文(它是)中定义,然后 Spring 会在评估您的配置类时抛出异常。

虽然使用 Spring时,即使你的CassandraConfig类也必须使用 Spring的 @Configuration注释或使用@Component注释进行注释类路径组件扫描或基于注释的容器配置。或者,如果不使用它,则必须在 Spring 应用程序上下文中明确定义为bean。

注意:命名约定(即CacheListener)不是很好,因为它与GemFire自己的CacheListener接口冲突。最好是调用特定于应用程序的扩展/实现,“GemFireToCassandraCacheListener

举例来说......

import ...;

@Configuration
class GemFireConfiguration {

  @Bean
  CacheFactoryBean gemfireCache() {
    return new CacheFactoryBean();
  }

  @Bean("CassandraCache")
  PartitionedRegionFactoryBean cassandraCacheRegion() {
    PartitionedRegionFactoryBean cassandraCacheRegion = 
      new PartitionedRegionFactoryBean();

    cassandraCacheRegion.setCache(gemfireCache());
    cassandraCacheRegion.setClose(false);
    cassandraCacheRegion.setCacheListeners(
      new CacheListener[] { gemfireToCassandraCacheListener() });

    return cassandraCacheRegion;
  }

  @Bean
  GemFireToCassandraCacheListener gemfireToCassandraCacheListener() {
    return new GemFireToCassandraCacheListener();
  }
}

import ...;

@Configuration
class CassandraConfig {

  // what you have above
}

我有很多GemFire配置示例here,它显示了带有 Spring(Data GemFire)配置的GemFire本机配置,XML与JavaConfig与注释等等。

...最后

从技术上讲,使用附加到Region的GemFire CacheWriter而不是CacheListener可能更好,因为你正在做的事情(在缓存创建时更新Cassandra)是预期的目的一个CacheWriter

当然,CacheListener称为"after" create,而CacheWriter称为"before" create。但是,我会说在更新“缓存”以反映数据源之前,更新“主要”数据源(或“事实来源”)总是更好。这尤其适用于主数据源中存在可能导致更新失败的约束。如果主数据源不能更新,则不希望更新缓存。

CacheWriter的配置类似于CacheListener,如此......

  @Bean("CassandraCache")
  PartitionedRegionFactoryBean cassandraCacheRegion() {
    PartitionedRegionFactoryBean cassandraCacheRegion = 
      new PartitionedRegionFactoryBean();

    cassandraCacheRegion.setCache(gemfireCache());
    cassandraCacheRegion.setClose(false);
    cassandraCacheRegion.setCacheWriter(gemfireToCassandraCacheWriter());

    return cassandraCacheRegion;
  }

  @Bean
  GemFireToCassandraCacheWriter gemfireToCassandraCacheWriter(
      CassandraOperations cassandraOperations) {

    return new GemFireToCassandraCacheWriter(cassandraOperations);
  }

GemFireToCassandraCacheWriter定义为......

class GemFireToCassandraCacheWriter extends CacheWriterAdapter {

  private CassandraOperations cassandraOperations;

  // Using constructor injection is better than field injection
  GemFireToCassandraCacheWriter(CassandraOperations cassandraOperations) {
    this.cassandraOperations = cassandraOperations;
  }

  public void beforeCreate(EntryEvent<?, ?> event) {
    cassandraOperations.insert(event.getNewValue());
  }
}

注意:一个地区只能有1 CacheWriter。仅供参考,CacheWriter在功能上与CacheLoader相对应。有关详细信息,请参阅GemFire User Guide。请特别注意hereherehere

此外,如果您只是将GemFire用作主要在Cassandra中管理的状态的缓存,那么您可能还会考虑Spring's Cache Abstraction,其中 Spring Data GemFire {{3}作为抽象中的“提供者”。

不确定你的Cassandra UC的GemFire是什么,但值得深思。

希望这有帮助!

-John