序幕

在Kubernetes中我最喜欢的就是发现服务的方式。 为什么?

主要是因为用户代码不必处理注册,查找服务,也没有网络意外(如果您曾经尝试过基于注册表的方法,那么您就会知道我在说什么)

这篇文章将介绍如何使用Fabric8以便使用CDI在Java中注入Kubernetes服务。

Kubernetes服务

深入介绍Kubernetes Services超出了本文的范围,但是我将尝试对其进行非常简要的概述。

在Kubernetes中,应用程序打包为Docker容器。 通常,将应用程序分成多个部分是一个好主意,因此您将拥有多个Docker容器,这些容器很可能需要彼此通信。 通过将某些容器放置在同一Pod中 ,可以将某些容器并置在一起,而另一些容器则可以位于较远的位置,并且需要彼此通信的方式。 这就是服务进入画面的地方。

容器可以绑定到一个或多个端口,从而为其他容器提供一个或多个“服务”。 例如:

  • 数据库服务器。
  • 消息代理。
  • 休息服务。

问题是其他容器如何知道如何访问这些服务?

所以, Kubernetes让你“标签”每个吊舱 ,并使用这些标签来“选择” 吊舱提供一个逻辑服务。 这些标签是简单的键,值对。

这是一个示例,说明如何通过使用键和值mysql指定标签来“标记”容器。

{"apiVersion" : "v1beta3","kind" : "ReplicationController","metadata" : {"labels" : {"name" : "mysql"},"name" : "mysql"},"spec" : {"replicas" : 1,"selector" : {    "name" : "mysql"},"template" : {"metadata" : {"labels" : {"name" : "mysql"}},"spec" : {"containers" : [ {"image" : "mysql","imagePullPolicy" : "IfNotPresent","name" : "mysql","ports" : [ {"containerPort" : 3306,"name" : "mysql"} ]                  }]}}}}

下面是我们如何定义一个例子服务暴露了MySQL端口。 服务选择器正在使用我们在上面指定的键/值对,以便定义提供服务的Pod。

{"kind": "Service","apiVersion": "v1beta3","metadata": {"name": "mysql"},"spec": {"ports": [{"name": "mysql","protocol": "TCP","port": 3306,"targetPort": 3306}],"selector": {"name": "mysql"}}
}

Kubernetes将服务信息作为环境变量传递给每个容器。 对于创建的每个容器, Kubernetes将确保为容器可见的所有服务传递适当的环境变量。

对于上述示例的mysql服务,环境变量将为:

  • MYSQL_SERVICE_HOST
  • MYSQL_SERVICE_PORT

Fabric8提供了一个CDI扩展,可以通过提供Kubernetes资源注入来简化Kubernetes应用程序的开发。

Fabric8 CDI扩展入门

要使用cdi扩展,第一步是将依赖项添加到项目中。

<dependency><groupId>io.fabric8</groupId><artifactId>fabric8-cdi</artifactId><version>2.1.11</version>
</dependency>

下一步是确定要向哪个字段注入的服务,然后向其添加@ServiceName批注。

import javax.inject.Inject;
import io.fabric8.annotations.ServiceName;public class MysqlExample {private static final DB = "mydb";private static final TCP_PROTO = "tcp";private static final JDBC_PROTO = "jdbc:mysql";private final Connection connection;public MysqlExample(@Inject @ServiceName("mysql") String serivceUrl) {Class.forName("com.mysql.jdbc.Driver");return DriverManager.getConnection(toJdbcUrl(serivceUrl));}private static String toJdbcUrl(String url) {return url.replaceFirst(TCP_PROTO, JDBC_PROTO) +"/" +DB;}//More stuff
}

在上面的示例中,我们有一个类,需要通过JDBC连接到可通过Kubernetes Services进行访问的mysql数据库。

注入的serivceUrl的格式为:[tcp | udp]:// [host]:[port]。 这是一个非常好的URL,但不是正确的jdbc url。 因此,我们需要一个实用程序来进行转换。 这是toJdbcUrl的目的。

即使可以在定义服务时指定协议,但只能指定核心传输协议,例如TCP或UDP,而不能指定http,jdbc等。

@Protocol批注

必须查找并用应用程序协议替换“ tcp”或“ udp”值,这很臭,而且很快就会变旧。 为了删除该样板, Fabric8提供了@Protocol批注。 该批注允许您在注入的服务URL中选择所需的应用程序协议。 在前面的示例中为“ jdbc:mysql”。 因此,代码可能类似于:

import javax.inject.Inject;
import io.fabric8.annotations.Protocol;
import io.fabric8.annotations.ServiceName;public class MysqlExampleWithProtocol {private static final DB = "mydb";private final Connection connection;public MysqlExampleWithProtocol(@Inject @Protocol("jdbc:mysql") @ServiceName("mysql") String serivceUrl) {Class.forName("com.mysql.jdbc.Driver");return DriverManager.getConnection(serivceUrl + "/" + DB);}//More stuff
}

毫无疑问,这要干净得多。 它仍然不包含有关实际数据库的信息或通常作为JDBC Url的一部分传递的任何参数,因此这里有改进的余地。

人们可能希望本着同样的精神,可以使用@Path或@Parameter批注,但这两者都是属于配置数据的,因此不适合将其硬编码为代码。 而且,Fabric8的CDI扩展并不希望成为URL转换框架。 因此,相反,它允许您直接实例化用于访问任何给定服务的客户端并将其注入源中,从而解决了问题。

使用@Factory注释为Services创建客户端

在前面的示例中,我们看到了如何获取服务的URL并使用该URL创建JDBC连接。 任何需要JDBC连接的项目都可以复制该代码段,并且只要用户记得他需要设置实际的数据库名称,它就可以很好地工作。

如果不是复制并粘贴该代码片段就可以对其进行组件化和重用,那岂不是很棒吗? 这是工厂注释的开始。您可以使用@Factory注释任何接受服务URL作为参数并返回使用URL创建的对象的方法(例如,服务的客户端)。 因此,对于前面的示例,我们可以有一个MysqlConnectionFactory:

import java.sql.Connection;
import io.fabric8.annotations.Factory;
import io.fabric8.annotations.ServiceName;public class MysqlConnectionFactory {@Factory@ServiceNamepublic Connection createConnection(@ServiceName @Protocol("jdbc:mysql") String url) {Class.forName("com.mysql.jdbc.Driver");return DriverManager.getConnection(serivceUrl + "/" + DB); }
}

然后,可以不注入URL而直接注入连接,如下所示。

import java.sql.Connection;
import javax.inject.Inject;
import io.fabric8.annotations.ServiceName;public class MysqlExampleWithFactory {private Connection connection;public MysqlExampleWithProtocol(@Inject @ServiceName("mysql") Connection connection) {this.connection = connection;}//More stuff
}

这里会发生什么?

当CDI应用程序启动时,Fabric8扩展将接收有关所有带注释方法的事件。 它将跟踪所有可用的工厂,因此对于使用@ServiceName注释的任何非String注入点,它将创建一个在后台使用匹配的@Factory的Producer。

在上面的示例中,首先将注册MysqlConnectionFactory,并且当检测到具有@ServiceName限定符的Connection实例时,将创建委托给MysqlConnectionFactory的Producer (将遵守所有限定符)

这很棒,但是也很简单 。 为什么?

因为很少有这样的工厂仅需要该服务的URL。 在大多数情况下,需要其他配置参数,例如:

  • 认证信息
  • 连接超时
  • 更多 …。

将@Factory与@Configuration一起使用

在下一节中,我们将看到使用配置数据的工厂。 我将使用mysql jdbc示例,并添加对指定可配置凭据的支持。 但是在此之前,我要问一个反问的问题?

“如何配置容器化的应用程序?”

可能的最短答案是“使用环境变量”。

因此,在此示例中,我假设使用以下环境变量将凭据传递到需要访问mysql的容器:

  • MYSQL_USERNAME
  • MYSQL_PASSWORD

现在我们需要看看我们的@Factory如何使用它们。

我以前曾经想在CDI中使用环境变量,但是很有可能已经使用了Apache DeltaSpike 。 这个项目提供了@ConfigProperty批注,该批注允许您将环境变量注入CDI bean中(它的作用比实际更多)

import org.apache.deltaspike.core.api.config.ConfigProperty;
import javax.inject.Inject;public class MysqlConfiguration {@Inject@ConfigProperty(name = "USERNAME", defaultValue = "admin")private String username;@Inject@ConfigProperty(name = "PASSWORD", defaultValue = "admin")private String password;@Inject@ConfigProperty(name = "DATABASE_NAME", defaultValue = "mydb")private String databaseName;public String getUsername() {return username;}public String getPassword() {return password;}public String getDatabaseName() {return databaseName;}}

该bean可以与@Factory方法结合使用,以便我们可以将配置传递给工厂本身。

但是,如果我们有多个数据库服务器,配置了不同的凭据集或多个数据库怎么办? 在这种情况下,我们可以使用服务名称作为前缀,并让Fabric8确定应该为每个@Configuration实例查找哪些环境变量。

import javax.inject.Inject;
import io.fabric8.annotations.ServiceName;
import io.fabric8.annotations.Factory;
import io.fabric8.annotations.Protocol;
import io.fabric8.annotations.Configuration;public class MysqlExampleWithFactoryAndConfiguration {@Factory@ServiceNamepublic Connection createConnection(@ServiceName @Protocol("jdbc:mysql") String url, @Configuration MysqlConfiguration conf) {Class.forName("com.mysql.jdbc.Driver");return DriverManager.getConnection(serivceUrl + "/" + conf.getDatabaseName(), conf.getUsername(), conf.getPassword()); }
}

现在,我们有了一个可重用的组件,可以与在kubernetes内部运行的任何mysql数据库一起使用,并且可以完全配置。

Fabric8 CDI扩展中还有其他功能,但是由于本篇文章过长,以后的文章中将介绍它们。

敬请关注。

翻译自: https://www.javacodegeeks.com/2015/06/injecting-kubernetes-services-in-cdi-managed-beans-using-fabric8.html

使用Fabric8在CDI管理的bean中注入Kubernetes Services相关推荐

  1. php cdi_使用Fabric8在CDI管理的bean中注入Kubernetes Services

    php cdi 序幕 我在Kubernetes中最喜欢的是发现服务的方式. 为什么? 主要是因为用户代码不必处理注册,查找服务,也没有网络意外(如果您曾经尝试过基于注册表的方法,那么您就会知道我在说什 ...

  2. 单元测试 applicationinfomanager bean无法注入_你真的会用Spring吗?如何在单例Bean中注入原型Bean...

    遇到什么问题 假设单例 BeanA 需要使用原型 BeanB(BeanB 可能是 BeanA 的一个属性值).可是容器仅创建一次单例 BeanA,因此只有一次机会来设置属性 BeanB. @Scope ...

  3. 在不受Spring管理的类中注入spring 管理的对象

    前几天在做一个任务时,需要在一个普通的java类(不受Spring管理的类)中,调用 spring data jpa的某个xxxReponsitory 接口,同时需要读取properties 文件中的 ...

  4. 如何向Spring Bean 中注入java.util.Properties?

    第一种方法是使用如下面代码所示的标签: <bean id="adminUser" class="com.leon.common.Customer"> ...

  5. Spring 注解实现Bean依赖注入之@Qualifier

    三.@Qualifier:限定描述符,用于细粒度选择候选者: @Autowired默认是根据类型进行注入的,因此如果有多个类型一样的Bean候选者,则需要限定其中一个候选者,否则将抛出异常 @Qual ...

  6. 170630、springboot编程之普通类中调用spring管理的bean对象

    我们知道如果我们要在一个类使用spring提供的bean对象,我们需要把这个类注入到spring容器中,交给spring容器进行管理,但是在实际当中,我们往往会碰到在一个普通的Java类中,想直接使用 ...

  7. 【学习笔记】springBoot中获取sping管理的bean

    文章目录 一.使用场景 二.springBoot中获取sping管理的bean 2.1 生成工具类SpringContextUtil 2.2 使用工具类SpringContextUtil 2.3 注意 ...

  8. mybatis plus 事务管理器_Mybatis中的事务

    Mybatis中的事务 数据库中的事务可以保证在连续执行的多条写操作(增删改)时,这多条操作要么成功,要么全部失败,以保证数据和逻辑的完整及严谨 在使用mybatis时,无需考虑事务如何创建,如何提交 ...

  9. 怎么随时获取Spring的上下文ApplicaitonContext,和Spring管理的Bean

    BeanFactory接口 Interface BeanFactory getBean <T> T getBean(String name,Class<T> requiredT ...

最新文章

  1. 函数在实现过程内存中的压栈和出栈
  2. python --那些你应该知道的知识点
  3. java基础--相等
  4. python获取文本光标_python 文件的操作以及调整光标
  5. 我是怎么把一个项目带崩的
  6. Android开源框架源码鉴赏:Fresco
  7. 用稳压管保护单片机引脚_零基础入门单片机(2)学会控制IO引脚你就入门啦
  8. JVM之方法区Mothed Area
  9. UI网页头部设计模板素材|这么多讲究,你知道吗?
  10. 关于 try catch 捕捉不到异常
  11. 计算机分区格式转换,硬盘GPT分区与MBR分区如何转换
  12. CentOS Linux操作系统
  13. 通信管线及宽带接入工程建设中主要涉及的 设计、施工及验收规范
  14. 这个是没事的时候做出来看的一系列算数表
  15. shell 编程空格注意事项
  16. Speedoffice(word)插入表格,如何合并单元格?
  17. LDAP认证服务客户端配置
  18. 襄阳市2011年6月高一数学统考解答
  19. 【Sql Server】查询实战,实现不同班级的排行查询并且批量模拟数据进行查询测试
  20. 亚伟计算机速录测试软件,亚伟中文速录机

热门文章

  1. ssh报错java.lang.ClassCastException: com.sun.proxy.$Proxy6 cannot be cast to org.service.impl.EmpServi
  2. 2019蓝桥杯省赛---java---C---4(质数)
  3. Hibernate使用最新的MySQL8.+版本出现的问题!
  4. 16-1 Redis分布式缓存引入与保存缓存功能实现
  5. 转:Centos防火墙设置与端口开放的方法
  6. jvm(2)-OutOfMemoryError 异常(内存溢出异常)
  7. aws部署ssh_将Quarkus应用程序部署到AWS Elastic Beanstalk
  8. java类似sizeof_如何用Java编写类似C的Sizeof函数
  9. 使用枚举映射_用EnumMaps映射枚举键
  10. 多个定时器相互干扰的问题_相互问题