使用自动装配注释的空指针异常 - Gemfire Listerner
Null pointer exception using Autowired annotation - Gemfire Listerner
我已经将所有的 Cassandra 移动到单个 class。当我尝试在 gemfire 缓存侦听器中创建 CassandraOperations 实例时得到空指针 exception.Can 请协助我解决此错误
我没有收到任何使用 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)
在上面的 code/configuration 中不明显的是您如何使用 Spring 配置特定于应用程序的 GemFire CacheListener
(Data GemFire).
我看到您使用 Spring 的 @Component
立体类型注释对您的应用程序 CacheListener
进行了注释,但这没有任何帮助.
您是否在使用 Spring 的 Classpath component scanning functionality, or perhaps Spring's Annotation-based container configuration 支持?如果你使用后者,你知道你仍然必须在配置(JavaConfig 或 XML)中显式定义你的应用程序 CacheListener
,对吗?
每当你在 @Autowired
component/collaborator 字段上遇到 NullPointerException
来注入依赖时,尤其是在使用 Spring 的 @Autowired
注释的 @Autowired annotation, it is good indication you have a configuration problem, particularly since the @Autowired
annotation implies that the "dependency" (e.g. CassandraOperations
) is "required" (unless you explicitly set the required 属性为 false,而你没有; required
默认为 true).
因此,如果 CacheListener
组件在扫描中被拾取并且无法注入(自动连接)依赖项,因为没有指定类型的(其他)bean(例如 CassandraOperations
) 是在 Spring 应用程序上下文(它是)中定义的,然后 Spring 将在评估时抛出异常你的配置 class(es).
尽管如此,即使您的 CassandraConfig
class 也必须使用 Spring 的 @Configuration
注释或使用@Component
使用 Spring 类路径组件扫描或基于注释的容器配置时的注释。或者,如果两者都不使用,则必须在 Spring 应用程序上下文中明确定义为 bean。
注意:命名约定(即 CacheListener
)不是很好,因为它与 GemFire 自己的 CacheListener 界面冲突。最好将您的应用程序特定 extension/implementation 称为“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,显示 GemFire 本机配置 Spring (Data GemFire) 配置,XML vs. JavaConfig vs. 注释等
终于...
从技术上讲,最好使用附加到区域的 GemFire CacheWriter,而不是 CacheListener
,因为您正在做的(在创建缓存时更新 Cassandra)是CacheWriter
.
的预期目的
当然,CacheListener
被称为"after" create vs. the CacheWriter
which is "before" create。但是,我会说在更新 "cache" 来反映数据源。这尤其适用于主数据源中存在可能导致更新失败的约束的情况。如果无法更新主数据源,您不希望更新缓存。
A 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. See the GemFire User Guide for more details. In particular, see here, here and here.
此外,如果您只是将 GemFire 用作主要在 Cassandra 中管理的状态的缓存,那么您也可以将 Spring's Cache Abstraction, for which Spring Data GemFire positions GemFire 视为抽象中的 "provider"。
不确定你的 GemFire to Cassandra UC 是关于什么的,但值得深思。
希望对您有所帮助!
-约翰
我已经将所有的 Cassandra 移动到单个 class。当我尝试在 gemfire 缓存侦听器中创建 CassandraOperations 实例时得到空指针 exception.Can 请协助我解决此错误
我没有收到任何使用 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)
在上面的 code/configuration 中不明显的是您如何使用 Spring 配置特定于应用程序的 GemFire CacheListener
(Data GemFire).
我看到您使用 Spring 的 @Component
立体类型注释对您的应用程序 CacheListener
进行了注释,但这没有任何帮助.
您是否在使用 Spring 的 Classpath component scanning functionality, or perhaps Spring's Annotation-based container configuration 支持?如果你使用后者,你知道你仍然必须在配置(JavaConfig 或 XML)中显式定义你的应用程序 CacheListener
,对吗?
每当你在 @Autowired
component/collaborator 字段上遇到 NullPointerException
来注入依赖时,尤其是在使用 Spring 的 @Autowired
注释的 @Autowired annotation, it is good indication you have a configuration problem, particularly since the @Autowired
annotation implies that the "dependency" (e.g. CassandraOperations
) is "required" (unless you explicitly set the required 属性为 false,而你没有; required
默认为 true).
因此,如果 CacheListener
组件在扫描中被拾取并且无法注入(自动连接)依赖项,因为没有指定类型的(其他)bean(例如 CassandraOperations
) 是在 Spring 应用程序上下文(它是)中定义的,然后 Spring 将在评估时抛出异常你的配置 class(es).
尽管如此,即使您的 CassandraConfig
class 也必须使用 Spring 的 @Configuration
注释或使用@Component
使用 Spring 类路径组件扫描或基于注释的容器配置时的注释。或者,如果两者都不使用,则必须在 Spring 应用程序上下文中明确定义为 bean。
注意:命名约定(即 CacheListener
)不是很好,因为它与 GemFire 自己的 CacheListener 界面冲突。最好将您的应用程序特定 extension/implementation 称为“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,显示 GemFire 本机配置 Spring (Data GemFire) 配置,XML vs. JavaConfig vs. 注释等
终于...
从技术上讲,最好使用附加到区域的 GemFire CacheWriter,而不是 CacheListener
,因为您正在做的(在创建缓存时更新 Cassandra)是CacheWriter
.
当然,CacheListener
被称为"after" create vs. the CacheWriter
which is "before" create。但是,我会说在更新 "cache" 来反映数据源。这尤其适用于主数据源中存在可能导致更新失败的约束的情况。如果无法更新主数据源,您不希望更新缓存。
A 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. See the GemFire User Guide for more details. In particular, see here, here and here.
此外,如果您只是将 GemFire 用作主要在 Cassandra 中管理的状态的缓存,那么您也可以将 Spring's Cache Abstraction, for which Spring Data GemFire positions GemFire 视为抽象中的 "provider"。
不确定你的 GemFire to Cassandra UC 是关于什么的,但值得深思。
希望对您有所帮助!
-约翰