容器化Spring Data Cassandra应用程序

我正在继续学习Docker的旅程。 在这一点上,我仍然保持简单。 这次,我将解决将Spring和Cassandra应用程序转换为使用容器而不是在主机上本地运行的问题。 更准确地说,使用Spring Data Cassandra整理应用程序。

我希望我前几天看过进行此更改。 我在Cassandra上写了很多文章,每次我必须cd到正确的目录或有启动它的快捷方式时。 我想这没什么大不了的,但是还涉及其他一些事情。 例如,删除和重新创建键空间,以便可以从头开始测试我的应用程序。 现在,我只删除容器并重新启动它。 无论如何对我来说,这是有帮助的!

卡桑德拉

这篇文章与我以前的文章《 使用Docker将现有应用程序推送到容器》稍有不同。 取而代之的是,我将更多地关注于应用程序端,并删除仅使用Docker的中间步骤,而直接跳入Docker Compose。

集装箱集装箱

我认为最好从项目的容器端开始,因为应用程序取决于Cassandra容器的配置。

我们走吧!

FROM openjdk:10-jre-slim
LABEL maintainer="Dan Newton"
ARG JAR_FILE
ADD target/${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

这里没有太多的事情。 这个Dockerfile构建了Spring应用程序映像,稍后将其放入容器中。

接下来是docker-compose文件。 这将同时构建Spring应用程序和Cassandra容器:

version: '3'
services:app:build:context: .args:JAR_FILE: /spring-data-cassandra-docker-1.0.0.jarrestart: alwayscassandra:
image: "cassandra"

同样,这里没有太多。 app容器使用Dockerfile定义的Dockerfile构建Spring应用程序。 cassandra容器而是依赖于现有的映像,适当地命名为cassandra

突出的一件事是,将restart属性设置为always 。 这是我的懒惰尝试,试图超越Cassandra启动所需的时间,而且所有容器都以docker-compose开头的事实是同时启动的。 这导致应用程序在未准备就绪的情况下尝试连接到Cassandra的情况。 不幸的是,这导致应用程序崩溃。 我希望它对内置的初始连接将有一些重试功能……但事实并非如此。

当我们遍历代码时,我们将看到如何以编程方式处理初始Cassandra连接,而不是依赖于应用程序死掉并重新启动多次。 您仍然会看到我处理连接的版本…我并不是真正的解决方案拥护者,但是我尝试的所有其他操作都使我更加痛苦。

一点代码

我说过这篇文章将把重点更多地放在应用程序代码上,但是我们不会深入研究我在该应用程序中放置的所有内容以及如何使用Cassandra。 有关此类信息,您可以查看我的较旧文章,这些文章将在最后链接。 不过,我们要做的是检查配置代码,该代码创建连接到Cassandra的bean。

首先,让我们看一下设置Cassandra集群的ClusterConfig

@Configuration
public class ClusterConfig extends AbstractClusterConfiguration {private final String keyspace;private final String hosts;ClusterConfig(@Value("${spring.data.cassandra.keyspace-name}") String keyspace,@Value("${spring.data.cassandra.contact-points}") String hosts) {this.keyspace = keyspace;this.hosts = hosts;}@Bean@Overridepublic CassandraClusterFactoryBean cluster() {RetryingCassandraClusterFactoryBean bean = new RetryingCassandraClusterFactoryBean();bean.setAddressTranslator(getAddressTranslator());bean.setAuthProvider(getAuthProvider());bean.setClusterBuilderConfigurer(getClusterBuilderConfigurer());bean.setClusterName(getClusterName());bean.setCompressionType(getCompressionType());bean.setContactPoints(getContactPoints());bean.setLoadBalancingPolicy(getLoadBalancingPolicy());bean.setMaxSchemaAgreementWaitSeconds(getMaxSchemaAgreementWaitSeconds());bean.setMetricsEnabled(getMetricsEnabled());bean.setNettyOptions(getNettyOptions());bean.setPoolingOptions(getPoolingOptions());bean.setPort(getPort());bean.setProtocolVersion(getProtocolVersion());bean.setQueryOptions(getQueryOptions());bean.setReconnectionPolicy(getReconnectionPolicy());bean.setRetryPolicy(getRetryPolicy());bean.setSpeculativeExecutionPolicy(getSpeculativeExecutionPolicy());bean.setSocketOptions(getSocketOptions());bean.setTimestampGenerator(getTimestampGenerator());bean.setKeyspaceCreations(getKeyspaceCreations());bean.setKeyspaceDrops(getKeyspaceDrops());bean.setStartupScripts(getStartupScripts());bean.setShutdownScripts(getShutdownScripts());return bean;}@Overrideprotected List getKeyspaceCreations() {final CreateKeyspaceSpecification specification =CreateKeyspaceSpecification.createKeyspace(keyspace).ifNotExists().with(KeyspaceOption.DURABLE_WRITES, true).withSimpleReplication();return List.of(specification);}@Overrideprotected String getContactPoints() {return hosts;}
}

那里并没有太多,但是如果Spring重试与Cassandra的初始连接,则将更少。 无论如何,让我们将这一部分留出几分钟,集中讨论本课程中的其他要点。

我创建ClusterConfig的最初原因是创建应用程序将使用的密钥空间。 为此, getKeyspaceCreations被覆盖。 当应用程序连接时,它将执行此方法中定义的查询以创建键空间。

如果不需要这样做,并且以其他某种方式创建了键空间,例如,作为创建Cassandra容器的一部分执行的脚本,则可以依靠Spring Boot的自动配置。 实际上,这允许整个应用程序由application.properties定义的属性进行配置,而仅此而已。 las,这本来不是。

由于我们定义了AbstractClusterConfiguration ,Spring Boot将在此区域中禁用其配置。 因此,我们需要通过重写getContactPoints方法来手动定义contactPoints (我将其命名为变量hosts )。 最初,这仅在application.properties定义。 我意识到一旦开始出现以下错误,我需要进行此更改:

All host(s) tried for query failed (tried: localhost/127.0.0.1:9042 (com.datastax.driver.core.exceptions.TransportException: [localhost/127.0.0.1:9042] Cannot connect))

在创建ClusterConfig之前,地址为cassandra而不是localhost

无需为集群配置其他任何属性,因为在这种情况下,Spring的默认值就足够了。

在这一点上,我已经提到太多application.properties了,我应该向您展示其中的内容。

spring.data.cassandra.keyspace-name=mykeyspace
spring.data.cassandra.schema-action=CREATE_IF_NOT_EXISTS
spring.data.cassandra.contact-points=cassandra

keyspace-namecontact-points已经弹出,因为它们与配置集群有关。 根据项目中的实体创建表需要schema-action 。 我们不需要在这里做任何其他事情,因为自动配置仍在该领域中工作。

contact-points值设置为cassandra的事实非常重要。 该域名源自提供给容器的名称,在本例中为cassandra 。 因此,既可以使用cassandra也可以使用容器的实际IP。 域名绝对容易,因为部署之间始终是静态的。 只是为了验证这一理论,您可以将cassandra容器的名称更改为所需的名称,只要您在application.properties中也将其更改,它仍然可以连接。

返回到ClusterConfig代码。 更确切地说,是cluster bean。 我再次粘贴了下面的代码,以便于查看:

@Configuration
public class ClusterConfig extends AbstractClusterConfiguration {// other stuff@Bean@Overridepublic CassandraClusterFactoryBean cluster() {RetryingCassandraClusterFactoryBean bean = new RetryingCassandraClusterFactoryBean();bean.setAddressTranslator(getAddressTranslator());bean.setAuthProvider(getAuthProvider());bean.setClusterBuilderConfigurer(getClusterBuilderConfigurer());bean.setClusterName(getClusterName());bean.setCompressionType(getCompressionType());bean.setContactPoints(getContactPoints());bean.setLoadBalancingPolicy(getLoadBalancingPolicy());bean.setMaxSchemaAgreementWaitSeconds(getMaxSchemaAgreementWaitSeconds());bean.setMetricsEnabled(getMetricsEnabled());bean.setNettyOptions(getNettyOptions());bean.setPoolingOptions(getPoolingOptions());bean.setPort(getPort());bean.setProtocolVersion(getProtocolVersion());bean.setQueryOptions(getQueryOptions());bean.setReconnectionPolicy(getReconnectionPolicy());bean.setRetryPolicy(getRetryPolicy());bean.setSpeculativeExecutionPolicy(getSpeculativeExecutionPolicy());bean.setSocketOptions(getSocketOptions());bean.setTimestampGenerator(getTimestampGenerator());bean.setKeyspaceCreations(getKeyspaceCreations());bean.setKeyspaceDrops(getKeyspaceDrops());bean.setStartupScripts(getStartupScripts());bean.setShutdownScripts(getShutdownScripts());return bean;}// other stuff
}

仅需要此代码才能允许在初始Cassandra连接上重试。 这很烦人,但是我无法提出另一个简单的解决方案。 如果您有更好的选择,请告诉我!

我所做的实际上很简单,但是代码本身并不是很好。 除了RetryingCassandraClusterFactoryBean (我自己的类)之外, cluster方法是AbstractClusterConfiguration重写版本的副本。 原始函数改为使用CassandraClusterFactoryBean (Spring类)。

以下是RetryingCassandraClusterFactoryBean

public class RetryingCassandraClusterFactoryBean extends CassandraClusterFactoryBean {private static final Logger LOG =LoggerFactory.getLogger(RetryingCassandraClusterFactoryBean.class);@Overridepublic void afterPropertiesSet() throws Exception {connect();}private void connect() throws Exception {try {super.afterPropertiesSet();} catch (TransportException | IllegalArgumentException | NoHostAvailableException e) {LOG.warn(e.getMessage());LOG.warn("Retrying connection in 10 seconds");sleep();connect();}}private void sleep() {try {Thread.sleep(10000);} catch (InterruptedException ignored) {}}
}

原始CassandraClusterFactoryBeanafterPropertiesSet方法采用其值,并通过最终委托给Datastax Java驱动程序来创建Cassandra集群的表示形式。 正如我在整个帖子中提到的。 如果无法建立连接,则将引发异常,如果未捕获,将导致应用程序终止。 这就是上面代码的重点。 它将afterPropertiesSet包装在为可能引发的异常指定的try-catch块中。

添加了sleep ,使Cassandra有一些时间可以真正启动。 上一次尝试失败时,尝试立即重新连接没有任何意义。

使用此代码,应用程序最终将连接到Cassandra。

在这一点上,我通常会向您显示一些毫无意义的日志,以证明该应用程序可以正常工作,但是在这种情况下,它实际上并没有带来任何好处。 当您说以下命令时,请相信我:

mvn clean install && docker-compose up

然后创建Spring应用程序映像,并旋转两个容器。

结论

我们已经看过如何将连接到Cassandra数据库的Spring应用程序放入容器中。 一个用于应用程序,另一个用于Cassandra。 应用程序映像是从项目的代码构建的,而Cassandra映像是从Docker Hub获取的。 图像名称为cassandra只是为了确保没有人忘记。 通常,将两个容器连接在一起相对简单,但是应用程序需要进行一些调整,以便在连接到另一个容器中运行的Cassandra时允许重试。 这使代码有些丑陋,但是至少可以工作……由于本文中编写的代码,现在我有了另一个不需要在自己的机器上设置的应用程序。

这篇文章中使用的代码可以在我的GitHub上找到 。

如果您认为这篇文章有帮助,可以在Twitter上@LankyDanDev关注我,以跟上我的新文章。

链接到我的Spring Data Cassandra帖子

  • Spring Data Cassandra入门
  • 使用Spring Data Cassandra分隔键空间
  • 使用单个Spring Data CassandraTemplate的多个键空间
  • 使用Spring Data Cassandra进行更复杂的建模
  • Spring Data Cassandra中的启动和关闭脚本
  • Spring Data Cassandra的反应流
  • Spring Data Cassandra中自动配置随附的管道
  • 使用Datastax Java驱动程序与Cassandra进行交互

哇,我没意识到我写了那么多Cassandra帖子。

翻译自: https://www.javacodegeeks.com/2018/09/spring-data-cassandra-application.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346078.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用React和Spring Boot构建一个简单的CRUD应用

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。 React的设计使创建交互式UI变得轻松自如。 它的状态管理非常有效,并且仅在…

使用CUBA进行开发–是Spring的重大转变吗?

阅读另一个供内部公司使用的Web项目的要求时,您(至少是我自己)通常会看到一个很普通的集合:定义明确的数据存储结构(或有时是现有的旧式DB),大量的数据输入形式,非常复杂的业务逻辑&…

java 伴随矩阵_C#计算矩阵的逆矩阵方法实例分析

本文实例讲述了C#计算矩阵的逆矩阵方法。分享给大家供大家参考。具体如下:1.代码思路1)对矩阵进行合法性检查:矩阵必须为方阵2)计算矩阵行列式的值(Determinant函数)3)只有满秩矩阵才有逆矩阵,因此如果行列式的值为0(在代码中以绝对值小于1E-…

java 代码造假_老板居然让我在Java项目中“造假”

1. 前言老板说,明天甲方要来看产品,你得造点数据,而且数据必须是“真”的,演示效果要好看一些,这样他才会买我们的产品,我好明年给你换个嫂子。一般开发接到这种过分要求都不会很乐意去做,这完全…

nginx php环境搭建_php+nginx环境配置

本篇文章的内容是PHP和nginx环境的配置,在这里分享给大家,也给有需要的朋友一个参考phpnginx环境配置1、首先需要准备的应用程序包。nginx:nginx/Windows-1.0.4php:php-5.2.16-nts-Win32-VC6-x86.zip (nginx下php是以FastCGI的方式…

javaone_旅行报告:JavaOne 2013 –重归荣耀

javaone我已经回来几天了,需要赶上过去几天一直搁置的所有事情。 对我来说,这是一年中最忙的时间。 JavaOne和OpenWorld在旧金山的整整一周。 一个非常简短的旅行报告。 年度ACED简报 你们中许多人都知道我是Oracle社区认可计划(称为“ ACE计…

php如何禁用浏览器的缓存,php如何禁止浏览器使用缓存页面

【摘要】PHP即“超文本预处理器”,是一种通用开源脚本语言。PHP是在服务器端执行的脚本语言,与C语言类似,是常用的网站编程语言。PHP独特的语法混合了C、Java、Perl以及 PHP 自创的语法。下面是php如何禁止浏览器使用缓存页面,让我…

使用Java EE和OIDC构建Java REST API

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。 Java EE允许您使用JAX-RS和JPA快速轻松地构建Java REST API。 Java EE是保护伞标准规…

通过JavaFX标注制作动画效果

在本文中,您将学习如何使用JavaFX的动画API创建标注。 您可以在https://www.youtube.com/watch?vXTHbB0LRdT4的 YouTube网站上查看这些标注的演示示例。 什么是标注? 我敢肯定,您已经看过广告或科幻电影,它们使用在图像顶部显示…

使用trackBy启动流程

仍然沿用Corda Services的趋势,我还有其他一些技巧可帮助您的CorDapp顺利工作。 这次,我们将重点关注使用trackBy从服务内部启动流以及如果您不小心可能会引起的离散问题。 这应该是一个相对简短的职位,因为我可以依靠之前的职位&#xff1a…

java+springmvc+vo,springmvc+mybatis的实例详解

前面讲到:SpringSpringMVCMyBatis深入学习及搭建(十三)——SpringMVC入门程序(二)1.需求使用springmvc和mybatis完成商品列表查询。2.整合思路springmvcmybatis的系统架构:第一步:整合dao层mybatis和spring整合,通过spring管理map…

了解为什么这个直观的工具是您团队的通用团队管理工具

每个项目管理工具都试图做同样的工具性工作:保持团队联系,按任务执行和按时完成重大计划。 但是市场变得非常拥挤,并且有充分的理由-没有平台似乎对人们需要看的东西以及应该如何显示这些信息具有正确的感觉,以便它们既可行又相关…

模型服务:流处理与使用Java,gRPC,Apache Kafka,TensorFlow的RPC / REST

机器学习/深度学习模型可以通过不同的方式进行预测。 我的首选方法是将分析模型直接部署到流处理应用程序(如Kafka Streams或KSQL )中。 您可以例如使用TensorFlow for Java API 。 这样可以实现最佳延迟和外部服务的独立性。 在我的Github项目中可以找到…

拥抱模块化Java平台:Java 10上的Apache CXF

Java 9版本终于将Project Jigsaw交付给大众已经过去了一年多的时间。 这是一段漫长的旅程,但是在那里,所以发生了什么变化? 这是一个很好的问题,答案并不明显和直接。 总的来说, 拼图项目是一种颠覆性的变化&#xff…

建立无服务器的“ Hello World”功能

无服务器 ,功能即服务(FaaS)或仅具有云功能,就可以编写将在云中运行的代码。 您可以使用多种不同的语言(例如JavaScript(Node.js),Swift,Python,Java&#xf…

oracle 10g 分区管理,Oracle 10g分区表的自动维护

Oracle 10g分区表不支持自动化管理,一般都要手动创建分区,手动删除。今天给大家带来了一个自动化管理表空间的脚本。本脚本主要由3个部分组成:sys_ConfigTable.sql、sys_pro_AddAndDropPartition.sql、sys_pro_MergeTable.sql1、sys_ConfigTa…

java实现metro风格_Metro风格的Java组合框(JMetro)–重新介绍

java实现metro风格我上一篇关于JMetro的文章–我的都市风格的Java皮肤(或外观)是关于日历选择器控件的 。 我本打算使用Tom Eugelink不错的日历选择器,但当时我了解到它是由Oracle创建并随Java 8一起提供的,因此出于时间的考虑&am…

toad查看oracle的plsql包,Oracle logminer 分析redo log(TOAD与PLSQL)

Oracle logminer 分析redo logOracle 11g r2 RAC centos 6.5设置时间格式select to_char(sysdate,yyyy-mm-dd hh24:mi:ss) date_format from dual ;查看数据库是否开启补全日志功能selectSUPPLEMENTAL_LOG_DATA_MIN,SUPPLEMENTAL_LOG_DATA_PK,SUPPLEMENTAL_LOG_DATA_UI,SUPPLEM…

Nutshell中的Java 8语言功能-第2部分

编者注:您也可以在此处检查Part-1。 嗨,朋友们,这是简明系列的Java 8语言功能的第2部分。 在这里,我们将讨论Java 8的以下功能: 接口中的静态方法 流 1.接口中的静态方法 什么是静态方法? 静态方法是属…

梯度下降法、最速下降法

梯度下降法 最优化问题是求解函数极值的问题,包括极大值和极小值。相信所有的读者对这个问题都不陌生,在初中时我们就学会了求解二次函数的极值(抛物线的顶点),高中时学习了幂函数,指数函数,对…