Spring-Boot 和 Netflix OSS - 微服务探索

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 63w+ 字,讲解图 2808+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2200+ 小伙伴加入学习 ,欢迎点击围观

老实说,我仍然需要说服微服务。

我可以看出,与单体应用程序相比,它们是一个令人信服的论据,但我认为我需要了解它们面临的一些挑战——第一个想到的是如何有效地定义微服务边界——因为它在我看来,我曾经使用过的很多应用程序都是单一的 ,因为 这些界限非常模糊。

无论如何,我想做一些技术方面的事情,所以决定开始使用 微服务架构模式 构建应用程序,而 Spring Boot 似乎是一个不错的起点。

这是一项正在进行的工作,我正在继续研究应用程序的不同方面,目前实际编写的代码很少(部分原因是 Spring-Boot 提供的简单性)。所有 代码都在 GitHub 中保持最新 ,因此请随时查看。

已经有很多很棒的博客介绍了这方面的内容,所以不会重复他们的工作,下面的文章对 Netflix OSS 和 Spring 集成进行了精彩的介绍,值得一读:


(图片来自: Building Microservices with Spring-Cloud and Netflix OSS



入门:服务注册中心 - Eureka

需要做的第一件事是中央服务注册中心以允许服务发现——这不是微服务的新概念,而是 SOA 使用的一种方法。开箱即用,Spring-Boot 提供了与 Netflix 的 OSS 应用程序 Eureka 的 集成,后者提供了这一点。我选择为我的注册表创建一个专用应用程序( 代码可以在这里看到 ),它真的很简单,只需将相关依赖项添加到 build.gradle 文件,将 @EnableEurekaServer 注释添加到我们的应用程序配置,然后一个简单的配置文件定义服务器端口/名称等并完成!您可以在该项目中运行 gradle assemble 来构建 JAR 文件,然后运行 ​​java -jar [the new JAR file] 并且应用程序将启动 - 然后您应该能够转到 http://localhost:1111 并且您将看到 Eureka 仪表板(当然没有注册微服务)。

我的第一个微服务

所以,我启动并运行了 Eureka,但它看起来很孤独,没有注册服务。

Spring 中的微服务也非常简单——实际上,它只是一个简单的 Web 应用程序,在其自己的进程中运行,具有有限的域——因此使用单个控制器/端点启动一个 Spring Boot MVC RESTful webapp 就足够了我是一个微服务(即使只是一条推文也可以)。

因此,我们可以创建新的微服务来做任何我们喜欢的事情,在我的例子中,我创建了一个 QuoteService(该应用程序正在慢慢演变为保险引擎)。仅仅拥有独立的应用程序并没有多大帮助,所以我们需要添加一些配置来告诉服务向我们的 Eureka 服务器注册——这将使我们的新微服务可以被其他想要使用它的服务发现。

同样,这非常简单:我们需要告诉我们的应用程序它应该尝试向 Eureka 注册,我们应该添加配置来这样做:


 @EnableAutoConfiguration
@EnableDiscoveryClient
@SpringBootApplication
class QuoteServiceApplication {

static void main(String[] args) { System.setProperty("spring.config.name", "quote-service"); SpringApplication.run QuoteServiceApplication, args } }


 @EnableAutoConfiguration
@EnableDiscoveryClient
@SpringBootApplication
class QuoteServiceApplication {

static void main(String[] args) {
System.setProperty("spring.config.name", "quote-service");
SpringApplication.run QuoteServiceApplication, args
    }
}

你可以看到我们只是在 java 中注释我们的应用程序配置,然后添加一些属性来定义 Eureka 服务器的托管位置,基本上就是这样。

现在,如果我们构建项目 JAR 并再次启动(并且我们的 Eureka 服务注册表仍在运行),那么在 30 秒左右之后,您应该会看到 Quote-Service 已注册并可以使用。

到下一个..

现在,我们有一个微服务,我们有一个注册表可以让它被发现,但仍然 - 只有一个微服务是相当孤独的。所以接下来我创建了另一个虚拟 RESTful 微服务,这次称为 ProductService,它遵循与第一个相同的模式。

一旦启动,Eureka 仪表板开始看起来对注册的两个服务更满意 - 显而易见的下一个挑战是两者之间的无缝交互:将服务拆分到它们自己的进程中是很好的,但如果可以的话就没有意义了'不容易整合它们。我看待它的方式是在阅读服务(或使用微服务的应用程序)的应用程序代码时,它应该看起来就像一个带有服务类的普通应用程序——不应该大肆宣传我的服务类实际上得到了通过 HTTP/AMQP 从专用微服务获取数据,而不是以传统方式直接从数据库获取数据。

因此,仍然只是删除端点,我更新了我的 QuoteService 端点以调用我的 ProductService,然后将该响应插入到我返回的 JSON 响应中:


 @EnableAutoConfiguration
@EnableDiscoveryClient
@SpringBootApplication
class QuoteServiceApplication {

static void main(String[] args) { System.setProperty("spring.config.name", "quote-service"); SpringApplication.run QuoteServiceApplication, args } }

如您所见,从这一点来看,它可能是普通单体应用程序中的标准控制器,我们只是在自动装配的 ProductService 类上调用一个方法并返回它。

所以真正有趣的部分在 ProductService 类中——目前这不是一个真正优雅的抽象类,是的,所以仍然有一些样板,但这样做的好处是可以清楚地说明正在发生的事情:


 @EnableAutoConfiguration
@EnableDiscoveryClient
@SpringBootApplication
class QuoteServiceApplication {

static void main(String[] args) { System.setProperty("spring.config.name", "quote-service"); SpringApplication.run QuoteServiceApplication, args } }

如您所见,它只是对 Product 微服务进行 REST 调用并返回转换为 Map 的响应 - 但真正好的部分是服务 url 只是服务名称(在本例中为“PRODUCT-SERVICE” ,它被注入到类中)并且 RestTemplate 带有 Spring-Cloud 的 @LoadBalanced 注释,微服务将在 Eureka 中查找(如果有多个 PRODUCT-SERVICE 正在运行,则负载平衡)。

所以我们的设置现在开始成形——我们有两个微服务,都在 Eureka 上注册,并且能够以一种相当干净、松散耦合的方式相互交互。

不要逼我,因为我已经接近边缘了..

随着您的微服务开始激增,您将获得不同级别的服务粒度,毫无疑问,您不会只想将所有微服务公开为公共 API。一种选择是创建一个 RESTful 应用程序并定义您想要公开的命名良好的端点,然后使用上述标准集成来集成它。

幸运的是,有一种更简单的方法——Netflix 提供了一个名为 Zuul 的库,可以简单地配置它以将 URL 模式映射到给定的定义服务名称(并再次在 Eureka 服务注册表中查找)。与 Eureka 非常相似,这非常容易设置,只需要一个注解和再次配置:


 @EnableAutoConfiguration
@EnableDiscoveryClient
@SpringBootApplication
class QuoteServiceApplication {

static void main(String[] args) { System.setProperty("spring.config.name", "quote-service"); SpringApplication.run QuoteServiceApplication, args } }


 @EnableAutoConfiguration
@EnableDiscoveryClient
@SpringBootApplication
class QuoteServiceApplication {

static void main(String[] args) {
System.setProperty("spring.config.name", "quote-service");
SpringApplication.run QuoteServiceApplication, args
    }
}

如您所见,我们只是根据 URL 模式定义服务名称。

现在,一旦所有应用程序都已启动并运行,并且微服务已在 Eureka 上注册,那么您就有了一个 API 接口来开始与服务交互(而不是必须访问其指定端口上的每个服务等)。

结论

这就是我所知道的——我将 QuoteService 连接到 MongoDB,以便所有数据都保存在那里(并添加了一个获取报价端点,它从 mongo 获取相同的数据)并开始使用 JPA 连接产品服务。到目前为止,一切都很愉快,而且事情比我刚开始时更有意义——但仍然有几个问题:

  • 似乎在不同的项目中仍然存在重复的服务名称 - 例如 ProductService 名称(“产品服务” - 不区分大小写)在整个过程中激增 - 服务本身定义它,QuoteService 需要知道服务的名称,Zuul 边缘服务器需要知道名称等。我想这是不可避免的,因为这些是内在的依赖关系,但仍然看起来有点不稳定。
  • 感觉服务类可以被分解——我们的 ProductService 类允许与产品微服务进行 HTTP REST 交互,可能需要在所有需要使用产品微服务的应用程序/微服务中重复使用

相关文章