Code Is Only Differentiator
源码:https://github.com/shuxingliu/microservices
一、生成项目文件(设置开发环境)
SpringCloud是Spring Boot的子集,我们可以使用Spring Boot预先配置网页(http://start.spring.io)来选择构建工具(Maven、Gradle)、项目元元数据(组名称、工件名称)。如果我们需要更多选择,我们需要点击"Switch to Full Version",在全部版本里,我们可以编辑更多的项目元数据信息(依赖项、打包格式、Java版本等),并选择安全、Web服务器、关系型/非关系型数据库、云服务的注册/配置/路由/发现、微服务的熔断等依赖项。我们要感谢Pivotol为我们提供了Spring Boot这么好的起点,大大简化了JavaWeb应用的开发。
本节示例中,我们使用Maven来作为构建工具,工件命名为booking car,是一个开发打车微服务的演示项目,打包格式为jar,使用Java最新版本Java1.8,包的名称设为:com.accenture.j2c.bookingcar,如下图所示。
在页面下面的依赖项,我们选择了Web、Eureka Server等依赖项。
选择依赖项后,界面显示如下:
点击Generate Project后,项目文件会打包成“项目名+zip”格式并自动下载到本地
我们使用NetBeans作为IDE,从项目zip文件导入刚才的项目
在导入项目的过程中,如果本地Maven库里没有声明的依赖项,NetBeans会给我们提示,我们点击“Resolve”即可,NetBeans会自动下载缺失的依赖项到本地Maven库里。
项目文件导入后,我们发现项目中已经有下列文件:
我们可以看到项目的包名为com.accenture.j2c.bookingcar
其中,main程序位于BookingcarApplication.java内,main调用了Spring Boot的SpringApplication.run()方法来启动应用程序。
二、EurekaClient的实现
为了能使微服务自动在Eureka服务器上注册,bookingcar应用要声明为Eureka Client。通过以下的两个步骤声明即可。
1. 导入包:org.springframework.cloud.netflix.eureka.EnableEurekaClient;
2. 添加注解:@EnableEurekaClient
三、实体、值对象的实现
在上一节的分析中,我们也可以发现,聚合中的实体、值对象位于战术建模的最底层,聚合、服务、存储库都依赖于实体、值对象。领域事务的实现过于复杂,我们在本次演示里暂不涉及,以后可以单独开辟一个单独的章节将领域事件的实现。
我们把实体放到包com.accenture.j2c.bookingcar.domain.entity里,把值对象放到包:com.accenture.j2c.bookingcar.domain.vo里
各个实体类的实现:
1. 抽象类Entity的实现
对于所有实体,ID和name都是常见的,因此,我们可以如下定义抽象类Entity作为实体的抽象。
Entity实现代码如下所示:
2. Order聚合的实现
Order是打车管理系统中的核心聚合,Order实体会作为Order聚合的聚合根。对Order的描述放到OrderVO里。User及Driver的实现同Order类似,不再累述。
OrderVO的实现:
Order实体的实现:
四、存储库类的实现
在本示例中,对于每一类实体,包括用户、司机、订单等,在某个时段里都会存在多个实例。比如,我们会有很多的用户,张三、李四、王二麻子,有很多的司机,有很多的订单。对于每一类实体,我们需要有个统一的接口来保存并引用这些实体。比如,对于用户实体,我们应该有一个用户存储库,用来存储所有的用户,管理用户的增、删、改、查。对于司机、订单也是类似,也需要分别有一个存储库来对应。
我们需要三个存储库:UserRepository,DriverRepository, OrderRepository。
开始时,我们首先创建两个抽象:ReadOnlyRepository和Repository。ReadOnlyRepository用于提供只读操作的抽象,例如get,getall等。而Repository用于执行所有类型的操作,包括增、删、改、查。
1. ReadOnlyRepository的实现如下:
2. Repository在ReadOnlyRepository基础上进行扩展,提供增加、删除、更新等操作接口,实现如下:
3. UserRepository、DriverRepository、OrderRepository接口在Repository接口上扩展,UserRepository、DriverRepository增加了containsName以及findByName两个操作,OrderRepository还添加了findByUserId接口,通过用户Id找到对应订单。
仅以OrderRepository为例展示实现代码:
4. 仓储库的实现
在Spring框架中,使用@Repository注解来定义实现存储库的bean。另外,我们把演示数据直接放到内存中,代替实际的数据库操作。
本次例程里,实现了用户和订单的仓储库。仅以订单的仓储库实现为例:
五、领域服务类的实现
领域服务定义了CRUD和一些界面操作。
我们抽象出ReadOnlyBaseService基类和BaseService基类,以及DomainService接口
1. ReadOnlyBaseService的实现如下:
2. BaseService继承于ReadOnlyBaseService,实现如下:
3. 在Spring框架中,使用@Repository注解来定义实现领域服务的bean。对订单操作的领域服务实现如下:
六、REST控制器类的实现
微服务最终会提供Restful接口给外面的程序调用。在微服务实现中,REST控制器是必不可少的。REST控制器用来处理HTTP请求,有四个常用的注解。
@RestController:类级注解,表明该类是REST控制器,用来处理HTTP请求,即表明该类可以提供Restful接口。
@RequestMapping:1)类级别,将URI映射到类上;2)方法级别:将路径映射到不同的方法。从这儿可以看出,一个微服务可以通过@RequestMapping注解映射不同的接口。
@RequestParam和PathVariable用来传递HTTP请求的参数。在someUrl/{param=value}中的param可以通过@RequestParam将HTTP请求的参数和方法的参数绑定,而someUrl/{paramId}的paramId可通过@Pathvariable注解绑定它传过来的值到方法的参数上。
本例程中,为了更好地演示,除了实现了上节里设计的使用用户Id查找订单的微服务接口外,还实现了使用订单Id查询订单、使用用户id查找用户,使用用户名字查找用户等接口。这四个接口的端点如下:
使用用户Id查找订单:http://.../v1/order?userid={userid}
使用订单id查询订单:http://.../v1/order/{id}
使用用户id查找用户:http://.../v1/user/{id}
使用用户名称查找用户:http://.../v1/user?name={name}
我们使用了两个控制器类UserController和OrderController来实现上面的四个接口端点
1. UserController的实现如下:
2. OrderController的实现如下:
七. 应用属性的配置
要使微服务自动注册到Eureka
Server里,我们要配置应用的属性。
应用属性的文件名称为application.properties,在项目中的路径如下:
本实现中,配置如下:
spring.application.name=bookingcar-lsx
spring.freemarker.enabled=false
spring.thymeleaf.cache=false
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
server.port=2227
八、测试REST API
1. 按照系列文章中第一部分的描述,启动Eureka Server
2. 选择bookingcar项目,右键弹出快捷菜单
3. 在Run Maven的窗口里,Goals输入"spring-boot:run"
4. Bookingcar应用启动后,刷新Eureka Server的界面,我们会发现bookingcar的微服务已经在“Instances currently registered with Eureka"下
5. 点击微服务后面的链接,我们会进入微服务的入口,输入不同的请求参数,我们可以观察到不同的反馈。
1) http://cpx-bkdhx46cy4h.dir.svc.accenture.com:2227/v1/user/1
查找id为1的用户,结果如下:
2) http://cpx-bkdhx46cy4h.dir.svc.accenture.com:2227/v1/user?name=2
查找用户名为2的用户,结果如下:
3)http://cpx-bkdhx46cy4h.dir.svc.accenture.com:2227/v1/order/2
查找id为2的订单,结果如下:
4) http://cpx-bkdhx46cy4h.dir.svc.accenture.com:2227/v1/order?userid=1
查找用户id为1的订单集合,结果如下:
利用Spring Cloud实现微服务(三)- 业务领域驱动微服务设计