![微服务分布式架构基础与实战:基于Spring Boot + Spring Cloud](https://wfqqreader-1252317822.image.myqcloud.com/cover/390/31186390/b_31186390.jpg)
1.3 【实例】微服务工程Hello World
1.3.1 实例背景
本书采用Eclipse配合Maven进行编程,JDK采用1.8版本,如果使用Idea、STS等相应开发工具,并无任何区别。STS是专门为Spring Boot制作的开发工具,全称为Spring Tool Suite,其中含有各种Spring Boot模板,在引入模板时,会自动生成pom.xml中所需要依赖的文件,但是本书使用Eclipse进行开发。STS基于Eclipse并进行了一定程度的封装,因此其快捷键、代码提示等功能和Eclipse无任何区别。
建议Spring Boot的版本在2.0.0上,因为有一些新特性可以使用。
本实例将创建boot_01工程,首先使用Maven插件集成Spring Boot微服务依赖,再通过@RestController注解编写REST风格的HTTP接口输出Hello World字符串。
1.3.2 创建Maven Project
在Eclipse工具下进行编程,Spring Boot通常在Maven工具的辅助下创建,因为Spring Boot内部所继承的依赖Jar包太多,Maven能够一次性将Spring Boot所有需要的依赖Jar包下载完成。
因为微服务工程只使用Spring Boot而并非Spring Boot下的一个模块,所以创建的是Maven Project,而不是Maven Module。表1-2所示为Maven工程类型及其含义。
表1-2 Maven工程类型及其含义
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_20_1.jpg?sign=1739358566-9xDG6sc2MrA5NjjkUDhgbhujNlW2PmcE-0-b09993827580c1e5a0bad5e048844496)
1.3.3 使用空Maven Project模板
模板的最大优点是能自动生成pom.xml文件。例如,当需要引入MySQL的驱动包对数据库增删改查时,STS创建工程可进行选择和引入。
如图1-1所示,创建Maven Project工程后选中Create a simple project(skip archetype selection)复选框,即不使用Maven模板。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_21_1.jpg?sign=1739358566-DIuQ1bc31yXcChXjbGumBrFKJJ1KiRiZ-0-1d4062d145be6235358ddedde46b338c)
图1-1
1.3.4 编辑Maven坐标定位及工程名
Maven的一个核心作用是对管理工程的依赖,同时引入所需要的各种Jar包等。为了能自动化地解析任何一个Java构件,Maven必须将依赖Jar包或其他资源进行唯一标识,标识即Maven坐标。Maven坐标是对工程依赖的基础。拥有其他工程的Maven坐标才能引用其他工程,或被其他工程所引用。Maven坐标的作用好像Maven世界中的身份证一样。
Maven坐标通过Group Id、Artifact Id、Version、Packaging、Name、Decription等元素来定义,如同坐标轴中的X轴、Y轴一样。
Group Id:定义当前Maven工程隶属的实际项目。图1-2中建立的Jar文件默认将处于C:\Users\Administrator\.m2\repository\org\zfx\boot文件夹中,在Maven世界里别人依赖此工程,也会处于$Maven_Home\.m2\repository\org\zfx\boot文件夹中。通常命名会表明该工程处于各项目中的哪个位置,以方便理解。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_22_1.jpg?sign=1739358566-C1rx7qSKEN7yfzwFNexCmo85xvXZskht-0-1b697e70be567bee053419bd1a3943d9)
图1-2
Artifact Id:定义Group Id位置下实际工程的名字,推荐与工程名保持一致,Maven生成的构件其文件名都会以Artifact Id作为开头。
Version:定义当前Maven工程所在的版本,因为作为名字后缀存储,所以建议尽量简短,方便后续对其进行维护。
Packaging:定义Maven的打包方式,通常为Jar文件或War文件。若不对其进行定义,则默认为Jar文件。
Decription:对Maven工程进行描述的内容,通常不会使用。
图1-2所示为输入该工程的Maven坐标等基本信息。
1.3.5 检查Maven目录结构
好的目录结构方便开发人员编写程序,也将为程序在未来使用过程中的维护工作打下良好的基础。
Maven目录结构是业界公认的最佳目录结构,为开发者提供了缺省的标准目录模板,Eclipse中Maven目录结构如图1-3所示。Idea的Maven目录结构与Eclipse的Maven目录结构略有不同。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_22_2.jpg?sign=1739358566-P1rchfb9228ROC0omMNxCQEKkDlneHMf-0-7a08561cd890e010dc6d6f0ae62351b7)
图1-3
Maven目录结构释义如表1-3所示。
表1-3 Maven目录结构释义
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_23_1.jpg?sign=1739358566-3cGsqeMigc7UFuJFc6LW58BxXYJIl71B-0-5d9ec759c713d3874626bc65eea96508)
1.3.6 编写Pom文件
pom.xml文件是Maven插件用来引入相关依赖Jar包的管理文件。其中,pom.xml内的<parent>标签代表该工程继承父类Maven工程的坐标,并且将会集成父类Maven下所有相关依赖,类似于Java的extend。<dependencies>标签下引入其他相关Maven工程坐标。
pom.xml文件代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_23_2.jpg?sign=1739358566-EDfIXOpNirDmoDyQMBBdEIme0XFRjknm-0-115e7c364e03787a08536d062e4dfe5d)
更新Pom文件前要了解当前计算机上是否含有JDK1.8版本,JDK1.7或以下版本需尝试使用spring-boot-starter-parent,版本为1.5.3.RELEASE。而JDK1.7使用Spring Boot 2.0以上版本会报Pom文件相关编译错误。具体可查询Spring.io网站信息。
编写本书时Spring Boot最高版本为2.0.x。
1.若无法从parent里进行继承
若工程有其他的包需要继承,则直接在pom.xml文件中对Spring Boot进行引入,即不使用<parent></parent>标签,pom.xml文件部分代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_24_2.jpg?sign=1739358566-7BTuyE7oTj9Mi1JtASXSVBPDik5NyMK0-0-8ce7c4630725d84231c6786fc5d1e55a)
注意,如果没有编写<dependencyManagement></dependencyManagement>标签进行定义,经常会报错。Spring Boot官方文档同样编写了该标签。
2.保存pom.xml文件会报错误
在Maven工程的pom.xml文件被更改并保存的情况下,工程会报如下错误:
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_25_1.jpg?sign=1739358566-KcH1j6JlfchcLMcVH6sHYwTxMD6n8Q8m-0-45a041716f0ba167a83cc25c7feaf977)
工程报错效果如图1-4所示。该错误是未更新Maven工程依赖的报错,原因是虽然进行了依赖但并未导入Maven相关依赖包。此时需要对Maven工程进行Update操作。
1.3.7 Spring Boot依赖包的导入
Maven Update Project是指Maven进行了一系列跟自身配置有关的操作,如更新SVN、更新工程关联、编译工程、构建发布、下载Jar包、下载Jar doc文件等。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_25_2.jpg?sign=1739358566-ddxyhaOhqt298YdTrE2cj6q8mQyzfYEB-0-0be46a007b7bcc119107d29611777438)
图1-4
如图1-5所示,选择Update Project更新Maven工程依赖,可解决图1.4中在编写完pom.xml相关依赖并保存时未更新Maven工程的错误。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_25_3.jpg?sign=1739358566-JBk1iuSSu3qQxsskSEyOJJCWdyzcVsLO-0-8c7a2942ad814aea7ddc93fbcd85ba2c)
图1-5
图1-6中Maven Update导入文件依赖包的选项释义如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_26_1.jpg?sign=1739358566-miPQm3hTG8hIEcY0w8m3q26acBxWPkWL-0-ef3acb99984ad5fad022d373096688e6)
图1-6
Offline:启动离线模式,即不会通过Maven镜像地址下载资源,而重新检查自身仓库内的资源,内网开发的公司若没有自身的Maven镜像,则经常会使用离线模式。
Force Update of Snapshots/Releases:强制更新模式,在Update dependencies更新依赖下,强制更新模式代表无论此时所有依赖包是否处于正常依赖状态,都会重新到Maven仓库中进行检查,并重新把该包导入工程中。若工程在导入包后仍然发生错误,有些包没有被正常导入,则需要启动强制更新模式进行强制重新导入。
如果编写了一个zfx_common-1.0.jar包,已经导入工程中,但是编程人员手动在本地仓库中删除了该依赖包,并置入一个更新后的zfx_common-1.0.jar依赖包(但两个版本拥有相同的名称和版本号),就需要启动离线模式加强制更新模式,离线模式加强制更新模式会在自身的工程中删除原有zfx_common-1.0.jar包,并依赖更新后的同版本号的zfx_common-1.0.jar依赖包。
Update project configuration from pom.xml:根据pom.xml的配置文件更新工程。
Refresh workspace resources from local filesystem:从本地仓库系统刷新工作区资源。若仓库中含有该依赖包,则从仓库中进行获取;若仓库中没有该依赖包,则会通过Maven镜像地址进行下载。镜像地址在$Maven_HOME/config/setting.xml文件中配置。
Clean projects:重新编译工程。
1.3.8 编写Spring Boot启动类
Spring Boot微服务工程都是JavaSE工程,因此需要main方法来启动并加载Spring容器等相关操作。启动核心代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_27_1.jpg?sign=1739358566-vUJBHfLCKteVzLoL31sOXfJQxDt1judr-0-732599090881b7bf6dc6c214a48b06ef)
和
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_27_2.jpg?sign=1739358566-oh8IUGfSfCjePtGhUIHRpd1vktLie28i-0-3ba314b11f19083aae2b334adbdd0ee7)
上述两种都是Spring Boot微服务的启动核心代码。启动类Application-Main.java代码如下(启动类名称可自行定义)。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_27_3.jpg?sign=1739358566-CGRTFikBsMP6ZbKYFlPsJjwCbbXgLIkB-0-5832138d55239e3ca9669813999092b5)
1.3.9 编写Spring Boot接口
在boot_01工程中创建HelloWorld.java类,在HelloWorld.java类中编写REST风格的HTTP接口代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_27_4.jpg?sign=1739358566-QVfuKM713nV8JYgTVnNjX3OsFXVwKZOl-0-893564ec3f7f87aa38c3106a528775c9)
@RestController注解相当于@Controller注解和@ResponseBody注解的集成注解,@RestController注解可直接返回json格式字符串,不需要新增其他代码。
@RequestMapping("/")是springMVC的注解,映射路径给外部进行访问。若该工程中含有相同的@RequestMapping路径,则会发生启动报错异常。
1.3.10 当前项目结构
ApplicationMain放置在com.zfx文件夹中,而其他文件则放置在com.zfx.xxx中,原因是Spring Boot的@SpringBootApplication只能扫描com.zfx的下级文件夹。
若某个@Component组件类注解放置在com.zfx同级文件夹下,则无法被@SpringBoot-Application注解扫描到,也无法被注册到Spring的Application容器内。当前项目结构如图1-7所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_28_1.jpg?sign=1739358566-z94ppV1ynvBA5b9AUmYd5CRpuYnmVlxS-0-cb4fe8a480bbf1faae6ce2b599d29701)
图1-7
1.3.11 启动工程
因为Spring Boot将Tomcat集成到自身上的框架,所以通过main命令可启动。
启动项目时直接在ApplicationMain.java类中运行Run As→Java Application命令即可,如图1-8所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_28_2.jpg?sign=1739358566-3Nu42mLmEFZe0POpQQf6dGMBJmmbB7y1-0-ce60881366400c883a6e0c51cd8f1b6e)
图1-8
1.3.12 Spring Boot初始化启动后
根据日志最后看到部分启动信息如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_29_1.jpg?sign=1739358566-3MbN5W5J7f3LyuDbzltyMCjnNQTTUF7B-0-38615dba8d07c1c6fbb9b6dd75651757)
Spring Boot内嵌Tomcat默认加载端口号为8080。
Spring Boot默认不需要输入工程名。如果有特殊需要,可在配置文件中增加自定义工程名配置。如果@RequestMapping写成@RequestMapping("HelloWorld"),访问的路径为localhost:8080/HelloWorld,后续对工程使用Spring Cloud进行控制时可以用增加工程名的方式来区分不同的微服务。
启动工程后,输入localhost:8080调用工程中的相关接口,执行结果如图1-9所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_29_2.jpg?sign=1739358566-3VyHoPV40iXNAfVXwkg1CfjSIlM0TDLZ-0-b5fe45276b765b2dfc902806e52b6675)
图1-9
如果访问localhost:8080/XXX,会报找不到接口的错误。这是因为Spring Boot不像Tomcat自带了一个欢迎页面。找不到相关接口报错提示如图1-10所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_29_3.jpg?sign=1739358566-Fg8vPCAPfnReNYsMHAsKAyE3jbTn2aDf-0-38a437a2cb8d6302ea43bdafd7630d36)
图1-10
注意,HTTP-404错误只在前台报错,后台正常打印日志且不输出“错误”信息,错误日志如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_29_4.jpg?sign=1739358566-6WqMYZjtgAHeAW8EbvmE2kN9Ja0ZJQ60-0-5fc40c6e4b03e17042d64d35ecb464bc)
1.3.13 实例易错点
1.缺少启动注解错误
SpringContext容器没有启动成功的报错信息如下,通常是因为缺少@EnableAuto-Configuration注解所引起的,此时应检查main方法的类是否含有@EnableAutoConfiguration注解或@SpringBootApplication注解修饰。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_30_1.jpg?sign=1739358566-wmsypV7r4rLP6SizVvrQq9JVK4pAFO6S-0-85db419c832b2eedd00b2a35453f08db)
2.@RequestMapping路径重复错误
@RequestMapping路径重复错误是初学者常见错误之一,错误日志如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_30_2.jpg?sign=1739358566-a3jTWBbMLYtqE8Jr2rUmFRmwN5OsFDD1-0-c636890189dadb862642fbfbe724b93d)
通常说明@RequestMapping("")在映射路径时,如果某一个路径相同,重复了一次或以上,需要修改成不同的路径名。
注意,下述代码使用@PathVariable注解用来获取URL路径上携带参数的信息,虽然@RequestMapping(/HelloWorld/{id})注解中的花括号内使用了不同的命名方式,但由于URL路径重复,所以@RequestMapping注解无法正常识别并获取URL路径与其携带的参数,无法正确将URL映射到Java接口中去,因此会引发多个相同路径的错误异常。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_30_3.jpg?sign=1739358566-75CcQKfvwxFqLxcyKlquIU6qogfmpiH4-0-8f14c4108ec7ae98fd7a77edac086b8c)
以上方法并不会报启动错误。部分启动日志如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_30_4.jpg?sign=1739358566-t0pgEo98K6uP7N1bMfTpWs2s3xAAlJ8R-0-67ab015ae9f81e9a5869c1d5f60d6400)
多个相同路径的错误在运行后调用会报以下错误,找不到相对应的接口函数如图1-11所示。因此应当避免出现多个相同位置的@PathVariable,让维护人员混淆或模糊的写法。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_31_1.jpg?sign=1739358566-XhqjuYL6MIxsqiKWTbNWV1Fg2GzZ44ct-0-4191c3a64d08ac956dd7216df4ce4372)
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_31_2.jpg?sign=1739358566-JNqkwi3gylH6bAXV03GJCtEzz3dpsEzW-0-dd01dc80932e497e0b292174bb8828e9)
图1-11