Java微服务开发指南 -- 使用Spring Boot构建微服务

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 使用Spring Boot构建微服务     Spring Boot是一个广泛用来构建Java微服务的框架,它基于Spring依赖注入框架来进行工作。Spring Boot允许开发人员使用更少的配置来构建微服务,同时框架本身能够尽可能的减少开发人员的冲突,它和我们后面要介绍的两个框架类似,它通过以.

使用Spring Boot构建微服务

    Spring Boot是一个广泛用来构建Java微服务的框架,它基于Spring依赖注入框架来进行工作。Spring Boot允许开发人员使用更少的配置来构建微服务,同时框架本身能够尽可能的减少开发人员的冲突,它和我们后面要介绍的两个框架类似,它通过以下几个方面帮助开发人员:

  • 自动化配置,一般情况下都有默认配置
  • 提供一组流行的starter依赖,方便开发人员使用
  • 简化应用打包
  • 提升应用运行时的内省性(例如:Metrics与环境信息)

简化的配置

    Spring以噩梦般的配置而闻名,虽然框架本身相比其他组件模型(EJB 1.x 和 2.x)简单了不少,但是它也带来了自己的配置模式。也就是说,如果想要正确的使用Spring,你需要深入了解如何进行XML配置、了解JdbcTemplateJmsTemplate以及BeanFactory生命周期、了解Servlet监听器,你以为掌握了这些就可以开始开发了吗?实际上问题远没有结束,如果你要用Spring MVC编写一个简单的hello world,你还需要了解DispatcherServlet和一堆Model-View-Controller相关的类型。

    Spring Boot目标就是消除掉这些与业务无关的配置和概念,通过简单的注解,你就能够完成这些工作,当然如果你想继续想以前一样使用Spring,它也不会拦着你。

Starter依赖

    Spring广泛使用着,包括了大型企业应用,在应用中,用户将会使用到不同的技术组件,包括:JDBC数据源、消息队列、文件系统以及应用缓存等。开发人员需要在需要这些功能时,停下来,仔细分析一下自己究竟需要什么?需要的内容属于哪个依赖(“哦,我需要JPA依赖”),然后花费大量的时间在依赖组织和排除上。

    Spring Boot提供了功能域(一批jar包依赖)的依赖,它让开发人员声明需要的功能,而不用去关系究竟如何处理依赖关系。这些starter可以允许开发人员直接使用这些功能:

  • JPA持久化
  • NoSQL数据库支持,例如:MongoDB、Cassandra或者CouchBase
  • Redis缓存
  • Tomcat、Jetty或者Undertow的Servlet引擎
  • JTA事务

    通过直接添加一个starter,能够让开发人员获得这个特性相关的一组依赖,而这些依赖的组合已经被验证,省却了开发人员的不少时间。

应用打包

    Spring Boot是一组jar包和符合其约定的配置的构建块,因此它不会运行在现有的应用服务器中,而使用Spring Boot的大多数开发人员更喜欢的是直接运行的这种自包含的jar包。这意味着Spring Boot将所有的依赖和应用程序代码都包装到一个自包含的jar中,而这些jar包运行在一个平面的类加载器中。简单的类加载体系使得开发人员更容易理解应用程序的启动、依赖关系和日志输出,但更重要的是,它有助于减少应用从构建到生产环境的步骤数量。这意味着开发人员不必将打包好的应用放置到应用服务器中,而是直接运行这个standalone的应用,如果你需要servlet,那么完全可以将其打包在应用内,使其为你服务。

    没错,一个简单的java -jar <name.jar>就可以启动你的应用了!Spring Boot、Dropwizard和WildFly Swarm都遵循将所有内容打包成可执行的jar模式。但是传统的应用服务器包含的管理能力,怎么在这种模式下实现呢?

为生产环境而准备

    Spring Boot推出了一个叫做actuator的模块,它可以实现应用的指标统计。例如:我们可以收集日志、查看指标、生成执行线程dump、显示环境变量、了解gc以及显示BeanFactory中配置的bean。可以通过HTTP或者JMX暴露这些信息或者进行日志输出。借助Spring Boot,我们可以利用Spring框架的功能、减少配置并快速开发应用并上线。

    说了这么多,让我们看看怎么使用它。

开始使用

我们接下来使用Spring Boot的命令行工具(CLI)来创建第一个Spring Boot程序(CLI底层使用了Spring Initializer)。你也可以使用自己喜欢的方式,比如使用集成了Spring Initializer的IDE,或者直接访问web来创建一个工程。

Spring Boot CLI 的安装方式,可以参考 这里

Homebrew下:
brew tap pivotal/tap
brew install springboot

    一旦你安装了Spring Boot CLI,你可以这样检查一下。

$ spring --version
Spring CLI v1.5.4.RELEASE

    如果你能看到版本的输出,恭喜你,安装成功了。接下来,在你希望创建工程的目录下运行命令:spring init --build maven --groupId com.murdock.examples --version 1.0 --java-version 1.8 --dependencies web --name hola-springboot hola-springboot

在microservices-camp下运行。

    运行该命令后,将会在当前目录下创建一个hola-springboot目录,同时该目录下包含了一个完整的Spring Boot程序,简单的介绍一下这个命令中包含的内容。

  • --build
    使用的构建工具,示例中是:maven
  • --groupId
    maven坐标中的组Id,也就是代码的包名,如果你想改包名,只有在IDE中修改
  • --version
    maven坐标中的version
  • --java-version
    Java版本
  • --dependencies
    这是一个有趣的参数,我们可以指定某种开发类型的依赖。比如:web就是指当前项目使用Spring MVC框架,默认基于内嵌的Tomcat(Jetty和Undertow作为可选)。其他的依赖或者starter,比如:jpasecuritycassandra

    进入到hola-springboot目录中, 执行命令:mvn spring-boot:run,如果程序启动,没有报错,你就能看到如下的日志:

2017-06-18 10:46:51.070  INFO 3397 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2017-06-18 10:46:51.081  INFO 3397 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0
2017-06-18 10:46:51.253  INFO 3397 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-06-18 10:46:51.262  INFO 3397 --- [           main] c.m.e.h.HolaSpringbootApplication        : Started HolaSpringbootApplication in 13.988 seconds (JVM running for 17.985)

    恭喜你!你快速的创建了一个Spring Boot应用,并且启动了它,你甚至可以访问http://localhost:8080,你会看到如下内容


chapter2-1.png

    可以看到返回了默认的出错页面,到目前为止,它除了这个什么也做不了。接下来,我们就添加一些特性,比如:REST访问,做一个helloworld式的应用。

后续实践内容与原文有不同,在操作性上要比原文具备更好的实践性。

你好,世界

    现在我们拥有了一个可以运行的Spring Boot应用,让我们为它添加一些简单的功能。首先,我们想做的是,让应用暴露一个位置是api/holaV1HTTP/REST端点,访问它将返回 Hola Spring Boot @ X,而其中的 X 是运行应用的本机IP。

    在编写代码前,先将hola-springboot导入到IDE中,在com.murdock.examples.holaspringboot包下面建立一个类,名称为HolaRestControllerV1

public class HolaRestControllerV1 {

    public String hola() throws UnknownHostException {
        String hostname = null;
        try {
            hostname = InetAddress.getLocalHost()
                    .getHostAddress();
        } catch (UnknownHostException e) {
            hostname = "unknown";
        }
        return "Hola Spring Boot @ " + hostname;
    }
}

    可以看到方法hola()返回了我们需要的内容,一个简单的字符串。

添加HTTP端点

    到现在为止,我们只是创建了一个名为HolaRestControllerV1POJO,你可以写一些单元测试去做验证,而让它暴露HTTP端点,则需要增加一些内容。

@RestController
@RequestMapping("/api")
public class HolaRestControllerV1 {

    @RequestMapping(method = RequestMethod.GET, value = "/holaV1", produces = "text/plain")
    public String hola() throws UnknownHostException {
        String hostname = null;
        try {
            hostname = InetAddress.getLocalHost()
                    .getHostAddress();
        } catch (UnknownHostException e) {
            hostname = "unknown";
        }
        return "Hola Spring Boot @ " + hostname;
    }
}
  • @RestController
    这个注解告知Spring,该类是一个用于暴露HTTP端点的控制器(可以暴露GET、PUT和POST等基于HTTP协议的功能)
  • @RequestMapping
    用于映射HTTP URI到对应的类或者方法

    通过添加这两个注解,我们就可以使得原有的类具备了暴露HTTP端点的能力。针对上面的代码,比如@RequestMapping("/api")代表着HolaRestControllerV1接受来自/api路径的请求,当添加@RequestMapping(method = RequestMethod.GET, value = "/holaV1", produces = "text/plain")时,表示告知Spring在/holaV1(其实是/api/holaV1)暴露HTTP GET端点,该端点接受的类型是text/plain。Spring Boot将会使用内置的Tomcat运行,当然你也可以切换到Jetty或者Undertow

    我们在hola-springboot目录下,执行mvn clean package spring-boot:run,然后使用浏览器访问http://localhost:8080/api/holaV1,如果一切正常,我们可以看到如下内容。


chapter2-2.png

    现在这些返回内容是写死的,如果我们想个应用增加一些环境相关的配置,如何做呢?比如:可以替代 Hola 这个词,比如使用 Guten Tag 德语,我们把这个应用部署给德国人用,我们需要一个将外部属性注入给应用的途径。

外部配置

    Spring Boot可以很容易使用诸如:properties文件、命令行参数和系统环境变量等作为外部的配置来源。我们甚至可以将这些配置属性通过Spring Context绑定到类型实例上,例如:如果想将helloapp.*属性绑定到HolaRestController,可以在类型上声明@ConfigurationProperties(prefix="helloapp"),Spring Boot会自动尝试将比如helloapp.foo或者helloapp.bar等这些属性值绑定到类型实例的foobar等字段上。

    在Spring Initializer CLI创建的工程中,已经有了一个application.properties,我们就可以在这个文件中定义新属性,比如:helloapp.saying

$ more src/main/resources/application.properties
helloapp.saying=Guten Tag aus

    创建一个新的控制器HolaRestControllerV2

@RestController
@RequestMapping("/api")
@ConfigurationProperties(prefix = "helloapp")
public class HolaRestControllerV2 {

    private String saying;

    @RequestMapping(method = RequestMethod.GET, value = "/holaV2", produces = "text/plain")
    public String hola() throws UnknownHostException {
        String hostname = null;
        try {
            hostname = InetAddress.getLocalHost()
                    .getHostAddress();
        } catch (UnknownHostException e) {
            hostname = "unknown";
        }
        return saying + " @ " + hostname;
    }

    public String getSaying() {
        return saying;
    }

    public void setSaying(String saying) {
        this.saying = saying;
    }
}

    停止之前运行的应用,然后在hola-springboot目录下,继续使用mvn clean package spring-boot:run来编译工程,运行这个应用,然后使用浏览器访问http://localhost:8080/api/holaV2,你会看到如下内容。


chapter2-3.png

    我们现在通过更改外部配置文件来使应用适应部署的环境,比如:调用服务的url、数据库url和密码以及消息队列配置,这些都适合作为配置。但是也要把握度,不是所有的内容都适合放置在配置中,比如:应用在任何环境下都应该具备相同的超时、线程池、重试等配置。

暴露应用的Metrics和信息

    一个Spring Boot应用搭建起来了,紧接着就是将其部署到生产环境,我们怎样监控它呢?当我们想知道它运行的怎么样,我们该怎么办呢?除非我们让应用向外暴露出Metrics,否则应用就会像黑盒子一样。Spring Boot专门提供了一个starter -- actuator来完成这个工作。

    让我们看看如何启用actuator,启用的过程非常简单。在hola-springboot/pom.xml中依赖:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

    然后在hola-springboot/src/main/resources/application.properties中增加一个配置(安全原因):

$ more src/main/resources/application.properties
management.security.enabled=false

    随后,结束当前应用,在hola-springboot下运行:mvn clean package spring-boot:run重新编译工程,启动项目。

    我们可以通过浏览器访问几次http://localhost:8080/api/holaV1以及http://localhost:8080/api/holaV2,然后访问一下:http://localhost:8080/metrics,可以看到如下内容。


chapter2-4.png

    类似这样的URL还有许多:

    暴露出这些运行时信息,使得开发人员在忙于业务开发的同时,更轻松获取到系统信息。

怎样在maven之外运行

    到现在为止,我们还是以开发者视角使用maven来构建这个简单的工程。如果我们需要将它部署到其他环境,比如:开发、测试或者生产环境,需要怎么做呢?

    幸运的是,使用Spring Boot,我们可以轻松的发布和构建,Spring Boot推荐单一、可执行的jar,而在这个jar中包括了所有的依赖,这些依赖的jar都会放置在应用的类路径下。在hola-springboot下,运行mvn clean package,然后可以通过java -jar来运行。

$ mvn clean package
$ java -jar target/hola-springboot-1.0.jar

    就是这样,我们可以启动这个应用,后续接下来介绍的DropwizardWildFly Swarm都使用类似的方式进行。

调用其他服务

    在微服务环境下,每个服务都有提供功能的义务并服务好它的调用者。就像我们在第一章中谈的,因为网络的不确定性,构建分布式系统十分的困难,本章主要讨论一个服务怎样调用到后台的服务。

在第五章中,将会讨论服务的柔性、适应性交互和调用

    接下来将扩展hola-springboot项目,完成服务的调用,但在此之前,我们先要搭建一个后台服务,完成类似下图的交互。


chapter2-5.png

后台服务的构建,将采用forge + WildFly的方式进行,比原文中写一个Servlet部署到Jetty显得更好
关于forge的安装,在mac下:brew install jboss-forge

    通过以下方式,可以在microservices-camp下创建一个具备持久化能力的REST服务,它可以自由的部署到WildFly中。

    使用forge构建完成之后,可以将其导入到IDE中,如果观察BookEndpoint这个类型,你会发现涉及到CRUD以及分页查询等逻辑已经完全具备了。


chapter2-11.png

    通过上述命令,我们可以构建出一个hola-backend.war的应用,下面我们将其部署到WildFly中。WildFly的使用可以通过下载到本地运行,但是由于涉及到两个进程的交互,本文采用Docker的方式进行部署,读者可以自行准备环境。

笔者准备了WildFly镜像,可以简单的运行起来
执行:sudo docker run --name wildfly -it -p 9990:9990 -p 8080:8080 weipeng2k/wildfly-admin,可以启动一个WildFly,HTTP端口在8080,应用管理端口在9990
管理员账号笔者已经构建在镜像中:admin/Admin#hello1234

    登录到WildFly后台,通过管理界面,部署hola-backend.war


chapter2-6.png

    可以看到后台的更新日志,从中可以了解到应用部署正常。


chapter2-7.png

    使用这种方式的好处在于开发阶段如果有新的包生成直接进行上传就好,如果想整体销毁,直接停止删除容器即可,不会弄坏WildFly。下面使用chrome插件Postman构建Book数据,然后测试是否可用。

    新增数据测试。


chapter2-8.png

    查询数据测试。


chapter2-9.png

    看来后台服务应用hola-backend工作正常,当然可以通过WildFly的管理界面查询运行时信息,这点和Spring Boot的actuator很像,但是产品化的体验做的更好些。

    接下来在hola-springboot项目中新建BookRestController,使用RestTemplate来完成后端服务的交互。

@RestController
@RequestMapping("/api")
@ConfigurationProperties(prefix = "books")
public class BookRestController {

    private RestTemplate template = new RestTemplate();

    private String backendHost;

    private int backendPort;

    @RequestMapping(value = "/books/{bookId}",
            method = RequestMethod.GET, produces = "text/plain")
    public String greeting(@PathVariable("bookId") Long bookId) {
        String backendServiceUrl = String.format("http://%s:%d/hola-backend/rest/books/{bookId}", backendHost, backendPort);
        Map object = template.getForObject(backendServiceUrl, Map.class, bookId);
        return object.toString();
    }

    public String getBackendHost() {
        return backendHost;
    }

    public void setBackendHost(String backendHost) {
        this.backendHost = backendHost;
    }

    public int getBackendPort() {
        return backendPort;
    }

    public void setBackendPort(int backendPort) {
        this.backendPort = backendPort;
    }
}

    可以看到BookRestController将后端的host与port放在了配置中,而前缀是books,那么也就需要在application.properties中增加这些配置。

$ more src/main/resources/application.properties
books.backendHost=192.168.0.125
books.backendPort=8080

    接下来,打开浏览器访问:http://localhost:8080/api/books/1,它将访问hola-springboot,而hola-springboot将会调用hola-backend,最终由hola-springboot输出结果。


chapter2-10.png

小结

    通过本章的内容,我们学习了Spring Boot的基本知识,了解它与传统的WAREAR不同的部署方式,以及如何使用外部资源来完成配置,并通过actuator暴露了Metrics,使用RestTemplate调用了另一个服务。如果你想了解跟多内容,可以参考下面的链接。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
4天前
|
负载均衡 测试技术 持续交付
高效后端开发实践:构建可扩展的微服务架构
在当今快速发展的互联网时代,后端开发扮演着至关重要的角色。本文将重点探讨如何构建可扩展的微服务架构,以及在后端开发中提高效率的一些实践方法。通过合理的架构设计和技术选型,我们可以更好地应对日益复杂的业务需求,实现高效可靠的后端系统。
|
7天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【2月更文挑战第30天】 随着Kotlin成为开发Android应用的首选语言,开发者社区对于其性能表现持续关注。本文通过深入分析与基准测试,探讨Kotlin与Java在Android平台上的性能差异,揭示两种语言在编译效率、运行时性能和内存消耗方面的具体表现,并提供优化建议。我们的目标是为Android开发者提供科学依据,帮助他们在项目实践中做出明智的编程语言选择。
|
4天前
|
监控 持续交付 API
构建高效可扩展的微服务架构
在当今快速迭代和竞争激烈的软件市场中,构建一个高效、可扩展且易于维护的后端系统变得尤为重要。微服务架构作为一种流行的分布式系统设计方式,允许开发者将应用程序划分为一系列小型、自治的服务,每个服务负责执行特定的业务功能。本文将探讨如何利用现代技术栈搭建一个符合这些要求的微服务架构,并讨论其潜在的挑战与解决方案。我们将涵盖服务划分策略、容器化、服务发现、API网关、持续集成/持续部署(CI/CD)以及监控和日志管理等关键主题,以帮助读者构建出既可靠又灵活的后端系统。
|
6天前
|
监控 Kubernetes 持续交付
构建高效可扩展的微服务架构:后端开发实践指南
在数字化转型的浪潮中,企业对软件系统的要求日益提高,追求快速响应市场变化、持续交付价值成为核心竞争力。微服务架构以其灵活性、模块化和独立部署的特点,成为解决复杂系统问题的有效途径。本文将深入探讨如何构建一个高效且可扩展的微服务架构,涵盖关键设计原则、技术选型及实践案例,为后端开发者提供一条清晰的指导路线,帮助其在不断变化的技术环境中保持竞争力。
115 3
|
8天前
|
存储 JSON 监控
构建高效微服务架构:后端开发的新趋势
【2月更文挑战第29天】在软件开发的世界中,微服务架构已经成为一种流行且有效的方式来组织和部署应用程序。这种架构模式通过将大型、复杂的应用拆分成一系列小型、自治的服务来提供灵活性和可扩展性。本文将探讨微服务的核心概念,包括其定义、优势、挑战以及如何在现代后端开发中实施微服务架构。我们将通过具体案例分析微服务的实施策略,并讨论如何克服常见的技术障碍,以实现一个高效、可维护的系统。
|
4天前
|
消息中间件 敏捷开发 运维
构建高效可靠的微服务架构:策略与实践
随着现代软件开发的复杂性增加,微服务架构逐渐成为企业解决大型应用系统分解、敏捷开发和持续部署问题的有效手段。本文深入探讨了构建一个高效且可靠的微服务架构的关键策略,包括服务的合理划分、通信机制的选择、数据一致性保障以及容错处理。通过分析这些策略在具体案例中的应用,我们旨在为开发者提供一套可行的微服务设计及实施指南。
115 6
|
4天前
|
监控 数据管理 API
构建高效微服务架构:后端开发的新趋势
在现代软件开发领域,随着业务需求的不断复杂化以及敏捷迭代的加速,传统的单体应用架构逐渐暴露出其局限性。微服务架构作为一种新的解决方案,以其高度模块化、独立部署和可扩展性,正成为后端开发领域的新趋势。本文将探讨微服务架构的核心概念,分析其优势与面临的挑战,并提供实施高效微服务的策略和最佳实践,帮助读者理解如何利用这一架构模式提升系统的可靠性、灵活性和可维护性。
126 5
|
7天前
|
人工智能 运维 监控
构建高性能微服务架构:现代后端开发的挑战与策略构建高效自动化运维系统的关键策略
【2月更文挑战第30天】 随着企业应用的复杂性增加,传统的单体应用架构已经难以满足快速迭代和高可用性的需求。微服务架构作为解决方案,以其服务的细粒度、独立性和弹性而受到青睐。本文将深入探讨如何构建一个高性能的微服务系统,包括关键的设计原则、常用的技术栈选择以及性能优化的最佳实践。我们将分析微服务在处理分布式事务、数据一致性以及服务发现等方面的挑战,并提出相应的解决策略。通过实例分析和案例研究,我们的目标是为后端开发人员提供一套实用的指南,帮助他们构建出既能快速响应市场变化,又能保持高效率和稳定性的微服务系统。 【2月更文挑战第30天】随着信息技术的飞速发展,企业对于信息系统的稳定性和效率要求
|
8天前
|
消息中间件 监控 开发者
构建高效微服务架构:后端开发的新趋势
【2月更文挑战第30天】 在现代软件开发领域,微服务架构已成为实现可扩展、灵活且容错的系统的首选设计。本文深入探讨了构建高效微服务架构的关键步骤和最佳实践,涵盖了从服务划分到部署管理的全过程。我们不仅将分析微服务的优势与挑战,还将提供具体的技术建议和解决方案,以帮助后端开发者有效地构建和优化其系统结构。
|
1天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
在开发高性能的Android应用时,选择合适的编程语言至关重要。近年来,Kotlin因其简洁性和功能性受到开发者的青睐,但其性能是否与传统的Java相比有所不足?本文通过对比分析Kotlin与Java在Android平台上的运行效率,揭示二者在编译速度、运行时性能及资源消耗方面的具体差异,并探讨在实际项目中如何做出最佳选择。
12 4

相关产品

  • 微服务引擎
  • 服务网格