Connecting to Cassandra with Spring

使用 Spring 与 Apache Cassandra 时,第一个任务之一是通过 Spring IoC 容器创建 com.datastax.oss.driver.api.core.CqlSession 对象。您可以使用基于 Java 的 bean 元数据或基于 XML 的 bean 元数据来执行此操作。以下部分将对这些内容进行讨论。

One of the first tasks when using Apache Cassandra with Spring is to create a com.datastax.oss.driver.api.core.CqlSession object by using the Spring IoC container. You can do so either by using Java-based bean metadata or by using XML-based bean metadata. These are discussed in the following sections.

对于那些不熟悉如何使用基于 Java 的 bean 元数据(而不是基于 XML 的元数据)配置 Spring 容器的人,请参阅参考文档 here 中的高级介绍以及详细文档https://www.iokays.com/spring-frameworkcore.html#beans-java-instantiating-container[此处]。

For those not familiar with how to configure the Spring container using Java-based bean metadata instead of XML-based metadata, see the high-level introduction in the reference docs here as well as the detailed documentation here.

Registering a Session Instance by using Java-based Metadata

以下示例演示如何使用基于 Java 的 bean 元数据来注册 com.datastax.oss.driver.api.core.CqlSession 实例:

The following example shows how to use Java-based bean metadata to register an instance of a com.datastax.oss.driver.api.core.CqlSession:

Example 1. Registering a com.datastax.oss.driver.api.core.CqlSession object by using Java-based bean metadata
/*
 * Copyright 2020-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.cassandra.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.datastax.oss.driver.api.core.CqlSession;

// tag::class[]
@Configuration
public class AppConfig {

	/*
	 * Use the standard Cassandra driver API to create a com.datastax.oss.driver.api.core.CqlSession instance.
	 */
	public @Bean CqlSession session() {
		return CqlSession.builder().withKeyspace("mykeyspace").build();
	}
}
// end::class[]

此方法让您可以使用您可能已知的标准 com.datastax.oss.driver.api.core.CqlSession API。

This approach lets you use the standard com.datastax.oss.driver.api.core.CqlSession API that you may already know.

另一种方法是使用 Spring 的 CqlSessionFactoryBeancom.datastax.oss.driver.api.core.CqlSession 实例注册到容器。与直接实例化 com.datastax.oss.driver.api.core.CqlSession 实例相比,FactoryBean 方法还有额外的优势,即还向容器提供一个 ExceptionTranslator 实现,该实现将 Cassandra 异常转换为 Spring 可移植 DataAccessException 层次结构中的异常。https://www.iokays.com/spring-frameworkdata-access.html[Spring 的 DAO 支持功能] 中描述了此层次结构和 @Repository 的使用。

An alternative is to register an instance of com.datastax.oss.driver.api.core.CqlSession with the container by using Spring’s CqlSessionFactoryBean. As compared to instantiating a com.datastax.oss.driver.api.core.CqlSession instance directly, the FactoryBean approach has the added advantage of also providing the container with an ExceptionTranslator implementation that translates Cassandra exceptions to exceptions in Spring’s portable DataAccessException hierarchy. This hierarchy and the use of @Repository is described in Spring’s DAO support features.

以下示例显示了基于 Java 的工厂类用法:

The following example shows Java-based factory class usage:

Example 2. Registering a com.datastax.oss.driver.api.core.CqlSession object by using Spring’s CqlSessionFactoryBean:
/*
 * Copyright 2020-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.cassandra.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.CqlSessionFactoryBean;

// tag::class[]
@Configuration
public class FactoryBeanAppConfig {

	/*
	 * Factory bean that creates the com.datastax.oss.driver.api.core.CqlSession instance
	 */
	@Bean
	public CqlSessionFactoryBean session() {

		CqlSessionFactoryBean session = new CqlSessionFactoryBean();
		session.setContactPoints("localhost");
		session.setKeyspaceName("mykeyspace");

		return session;
	}
}
// end::class[]

对对象映射和仓库支持使用 CassandraTemplate 需要一个 CassandraTemplateCassandraMappingContextCassandraConverter 以及启用的仓库支持。

Using CassandraTemplate with object mapping and repository support requires a CassandraTemplate, CassandraMappingContext, CassandraConverter, and enabling repository support.

以下示例显示了向对象映射注册组件以及启用仓库支持的方法:

The following example shows how to register components to configure object mapping and repository support:

Example 3. Registering components to configure object mapping and repository support
/*
 * Copyright 2020-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.cassandra.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.SessionFactory;
import org.springframework.data.cassandra.config.CqlSessionFactoryBean;
import org.springframework.data.cassandra.config.SchemaAction;
import org.springframework.data.cassandra.config.SessionFactoryFactoryBean;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.data.cassandra.core.convert.CassandraConverter;
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;

import com.datastax.oss.driver.api.core.CqlSession;

// tag::class[]
@Configuration
@EnableCassandraRepositories(basePackages = { "org.springframework.data.cassandra.example" })
public class CassandraConfig {

	@Bean
	public CqlSessionFactoryBean session() {

		CqlSessionFactoryBean session = new CqlSessionFactoryBean();
		session.setContactPoints("localhost");
		session.setKeyspaceName("mykeyspace");

		return session;
	}

	@Bean
	public SessionFactoryFactoryBean sessionFactory(CqlSession session, CassandraConverter converter) {

		SessionFactoryFactoryBean sessionFactory = new SessionFactoryFactoryBean();
		sessionFactory.setSession(session);
		sessionFactory.setConverter(converter);
		sessionFactory.setSchemaAction(SchemaAction.NONE);

		return sessionFactory;
	}

	@Bean
	public CassandraMappingContext mappingContext() {
		return new CassandraMappingContext();
	}

	@Bean
	public CassandraConverter converter(CqlSession cqlSession, CassandraMappingContext mappingContext) {

		MappingCassandraConverter cassandraConverter = new MappingCassandraConverter(mappingContext);
		cassandraConverter.setUserTypeResolver(new SimpleUserTypeResolver(cqlSession));

		return cassandraConverter;
	}

	@Bean
	public CassandraOperations cassandraTemplate(SessionFactory sessionFactory, CassandraConverter converter) {
		return new CassandraTemplate(sessionFactory, converter);
	}
}
// end::class[]

创建注册 Spring Data for Apache Cassandra 组件的配置类可能是一项艰巨的挑战,因此 Spring Data for Apache Cassandra 提供了一个预建的配置支持类。从 AbstractCassandraConfiguration 扩展的类注册 Spring Data for Apache Cassandra 用 Bean。AbstractCassandraConfiguration 让你能提供各种配置选项,例如初始实体、默认查询选项、池选项、套接字选项等等。AbstractCassandraConfiguration 还支持你根据初始实体(如果有此类实体)生成模式。从 AbstractCassandraConfiguration 扩展要求你至少通过实现 getKeyspaceName 方法提供键空间名称。以下示例显示了如何使用 AbstractCassandraConfiguration 注册 Bean:

Creating configuration classes that register Spring Data for Apache Cassandra components can be an exhausting challenge, so Spring Data for Apache Cassandra comes with a pre-built configuration support class. Classes that extend from AbstractCassandraConfiguration register beans for Spring Data for Apache Cassandra use. AbstractCassandraConfiguration lets you provide various configuration options, such as initial entities, default query options, pooling options, socket options, and many more. AbstractCassandraConfiguration also supports you with schema generation based on initial entities, if any are provided. Extending from AbstractCassandraConfiguration requires you to at least provide the keyspace name by implementing the getKeyspaceName method. The following example shows how to register beans by using AbstractCassandraConfiguration:

Example 4. Registering Spring Data for Apache Cassandra beans by using AbstractCassandraConfiguration
/*
 * Copyright 2020-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.cassandra.example;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.AbstractCassandraConfiguration;

// tag::class[]
@Configuration
public class CassandraConfiguration extends AbstractCassandraConfiguration {

	/*
	 * Provide a contact point to the configuration.
	 */
	@Override
	public String getContactPoints() {
		return "localhost";
	}

	/*
	 * Provide a keyspace name to the configuration.
	 */
	@Override
	public String getKeyspaceName() {
		return "mykeyspace";
	}
}
// end::class[]

Abstract…Configuration 类为从应用程序中使用 Cassandra 连接所有必需的 Bean。此配置假设一个 CqlSession 并通过 SessionFactory 将其连接到诸如 CqlTemplate 的相关组件。如果你想自定义 CqlSession 的创建,那么你可以提供一个 SessionBuilderConfigurer 函数来自定义 CqlSessionBuilder。这很有用,例如为 Astra 提供一个 Cloud 连接包。

Abstract…Configuration classes wire all the necessary beans for using Cassandra from your application. The configuration assumes a single CqlSession and wires it through SessionFactory into the related components such as CqlTemplate. If you want to customize the creation of the CqlSession, then you can provide a SessionBuilderConfigurer function to customize CqlSessionBuilder. This is useful to provide e.g. a Cloud Connection Bundle for Astra.

Example 5. Connecting to Astra through AbstractCassandraConfiguration
/*
 * Copyright 2020-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.cassandra.example;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.AbstractCassandraConfiguration;

// tag::class[]
@Configuration
public class CustomizedCassandraConfiguration extends AbstractCassandraConfiguration {

	/*
	 * Customize the CqlSession through CqlSessionBuilder.
	 */
	@Override
	protected SessionBuilderConfigurer getSessionBuilderConfigurer() {

		Path connectBundlePath = …;

		return builder -> builder
				.withCloudSecureConnectBundle(Path.of(connectBundlePath));
	}

	/*
	 * Provide a keyspace name to the configuration.
	 */
	@Override
	public String getKeyspaceName() {
		return "mykeyspace";
	}

}
// end::class[]

XML Configuration

此部分介绍如何使用 XML 配置 Spring Data Cassandra。

This section describes how to configure Spring Data Cassandra with XML.

虽然我们仍支持命名空间配置,但我们通常建议使用 Java-based Configuration

While we still support Namespace Configuration, we generally recommend using cassandra.cassandra-java-config.

Externalizing Connection Properties

要 externalize 连接属性,你应该先创建一个属性文件,其中包含连接到 Cassandra 所需的信息。contactpointskeyspace 是必需字段。

To externalize connection properties, you should first create a properties file that contains the information needed to connect to Cassandra. contactpoints and keyspace are the required fields.

以下示例显示了名为 cassandra.properties 的属性文件:

The following example shows our properties file, called cassandra.properties:

cassandra.contactpoints=10.1.55.80:9042,10.1.55.81:9042
cassandra.keyspace=showcase

在接下来的两个示例中,我们使用 Spring 将这些属性加载到 Spring 环境。

In the next two examples, we use Spring to load these properties into the Spring context.

Registering a Session Instance by using XML-based Metadata

虽然你可以使用 Spring 的传统 <beans/> XML 命名空间来向容器注册 com.datastax.oss.driver.api.core.CqlSession 的实例,但 XML 可能非常冗长,因为它很通用。XML 命名空间是配置常用对象(例如 CqlSession 实例)的更佳选择。cassandra 命名空间让你可以创建一个 CqlSession 实例。

While you can use Spring’s traditional <beans/> XML namespace to register an instance of com.datastax.oss.driver.api.core.CqlSession with the container, the XML can be quite verbose, because it is general purpose. XML namespaces are a better alternative to configuring commonly used objects, such as the CqlSession instance. The cassandra namespace let you create a CqlSession instance.

以下示例显示了如何配置 cassandra 命名空间:

The following example shows how to configure the cassandra namespace:

Example 6. XML schema to configure Cassandra by using the cassandra namespace
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:cassandra="http://www.springframework.org/schema/data/cassandra"
  xsi:schemaLocation="
    http://www.springframework.org/schema/data/cassandra
    https://www.springframework.org/schema/data/cassandra/spring-cassandra.xsd
    http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd">

  <!-- Default bean name is 'cassandraSession' -->
  <cassandra:session contact-points="localhost" port="9042">
    <cassandra:keyspace action="CREATE_DROP" name="mykeyspace" />
  </cassandra:session>

  <cassandra:session-factory>
    <cassandra:script
            location="classpath:/org/springframework/data/cassandra/config/schema.cql"/>
  </cassandra:session-factory>
</beans>

更高级的 Cassandra 配置的 XML 配置元素如下所示。这些元素都使用默认 Bean 名称来保持配置代码的简洁和可读性。

The XML configuration elements for more advanced Cassandra configuration are shown below. These elements all use default bean names to keep the configuration code clean and readable.

尽管前面的示例展示了使用 Spring 配置连接 Cassandra 是多么容易,但还有许多其他选项。基本上,DataStax Java Driver 中的任何可用的选项在 Spring Data for Apache Cassandra 配置中也可用。这包括但不限于认证、负载平衡策略、重试策略和池选项。所有 Spring Data for Apache Cassandra 方法名称和 XML 元素的命名与 Driver 上的配置选项完全相同(或尽可能接近),以便对任何现有的 Driver 配置进行映射应该是直接的。以下示例展示了如何使用 XML 配置 Spring Data 组件

While the preceding example shows how easy it is to configure Spring to connect to Cassandra, there are many other options. Basically, any option available with the DataStax Java Driver is also available in the Spring Data for Apache Cassandra configuration. This includes but is not limited to authentication, load-balancing policies, retry policies, and pooling options. All of the Spring Data for Apache Cassandra method names and XML elements are named exactly (or as close as possible) like the configuration options on the driver so that mapping any existing driver configuration should be straight forward. The following example shows how to configure Spring Data components by using XML

Example 7. Configuring Spring Data components by using XML
<!-- Loads the properties into the Spring Context and uses them to fill
in placeholders in the bean definitions -->
<context:property-placeholder location="classpath:cassandra.properties" />

<!-- REQUIRED: The Cassandra Session -->
<cassandra:session contact-points="${cassandra.contactpoints}" keyspace-name="${cassandra.keyspace}" />

<!-- REQUIRED: The default Cassandra mapping context used by `CassandraConverter` -->
<cassandra:mapping>
  <cassandra:user-type-resolver keyspace-name="${cassandra.keyspace}" />
</cassandra:mapping>

<!-- REQUIRED: The default Cassandra converter used by `CassandraTemplate` -->
<cassandra:converter />

<!-- REQUIRED: The Cassandra template is the foundation of all Spring
Data Cassandra -->
<cassandra:template id="cassandraTemplate" />

<!-- OPTIONAL: If you use Spring Data for Apache Cassandra repositories, add
your base packages to scan here -->
<cassandra:repositories base-package="org.spring.cassandra.example.repo" />