容器化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,一经查实,立即删除!

相关文章

最快的 java 图像_ImageJ 1.53 世界上最快的Java图像处理程序

ImageJ 1.53 世界上最快的Java图像处理程序 已通过小编安装运行测试 100%可以使用。ImageJ 1.53 是世界上最快的纯Java图像处理程序。它可以在0.1秒内过滤2048x2048图像。每秒可以处理4000万像素的图片。ImageJ支持处理8位灰度或索引颜色,16位无符号整数&#xff0c…

java字节码提取if语句_终于找到了!有了它你就可以读懂字节码了!

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼0x80 ior 将栈顶两int型数值作“按位或”并将结果压入栈顶0x81 lor 将栈顶两long型数值作“按位或”并将结果压入栈顶0x82 ixor 将栈顶两int型数值作“按位异或”并将结果压入栈顶0x83 lxor 将栈顶两long型数值作“按位异或”并将结…

maven设置代理服务器_使用Maven设置您的应用服务器

maven设置代理服务器在许多情况下,无需事先设置应用程序就无法部署应用程序。 在JBoss AS 7.x中,您可能需要配置例如数据库连接。 或者,您必须配置一个安全领域。 也许您还想调整SLSB池…在任何情况下,团队中的所有开发人员都必须…

java编程中的di是什么_java-在Spring IoC / DI中使用@Component注释对接口...

在Spring类中,通常使用Component注释接口,特别是对于某些Spring构造型注释:package org.springframework.stereotype;...Componentpublic interface Service {...}要么 :package org.springframework.boot.test.context;...Componentpublic interface Te…

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

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

java初始化该字符串值_java字符串数组初始化和赋值

//一维数组String[] str new String[5]; //创建一个长度为5的String(字符串)型的一维数组String[] str new String[]{“”,””,””,””,””};String[] str {“”,””,””,””,””};String数组初始化区别首先应该明白java数组里面存的是对象的引用,所以必…

java 无法找到ant_Java-Ant需要tools.jar并且无法找到我

Java-Ant需要tools.jar并且无法找到我我将一个Java程序的开发环境放在一起,并且在第一次尝试使用Ant构建脚本后,出现了以下错误:Unable to locate tools.jar. Expected to find it in /usr/lib/jvm/java-6-openjdk/lib/tools.jar虽然通往jdk的…

js实现日历框上一日下一日_一日三项令人兴奋的Lucene功能

js实现日历框上一日下一日昨天是富有成效的一天:突然,Lucene有了三个令人兴奋的新功能。 表达式模块 昨天提交的第一个功能是新的expressions模块 。 这使您可以使用任意String表达式定义用于排序的动态字段。 内置了对JavaScript解析的支持&#xff0c…

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

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

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

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

apache camel_探索Apache Camel Core –文件组件

apache camel文件轮询器是解决常见IT问题的非常有用的机制。 Camel的内置file组件非常灵活,并且有许多选项可用于配置。 让我们在这里介绍一些常用用法。 轮询目录以输入文件 这是一条典型的骆驼Route用于每秒轮询一次目录以查找输入文件。 import org.slf4j.*; i…

java list 遍历 remove_JAVA中LISt遍历时如何remove元素?

import java。util。*;  public class object {  public static void main(String[] args) {  String str1 new String("abcde");  String str2 new String("abcde");  String str3 new String("abcde");  String str4 new Stri…

Java使用者的延期执行

在前面的博客文章(“ 延迟执行Java的供应商 “),我引用礁HORSTMANN的陈述书中‘ 的Java SE8为真的很急关于lambda表达式’,‘所有的lambda表达式的点被推迟执行 。’ Horstmann在最后一年为Dobb博士的杂志写了一篇名为“ Java 8中…

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是保护伞标准规…

php 长微博程序,长微博生成工具PHP源码 根据文字生成长微博图片 - substr_count

PHP substr_count() 函数定义和用法substr_count() 函数计算子串在字符串中出现的次数。语法substr_count(string,substring,start,length)...] rtrim($matches[3],\"/);//获取图片的id$parent_dir_num substr_count( $matches[3], ../);$relative_dirname …

php 加密类,php加密类

这篇文章的主要内容是介绍了关于php加密类 ,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下namespace app\index\controller;class Crypt{private $key "";public function __construct($key null){if (!is_null($…