[TOC]
通过上一篇文章理解了微服务后我们通过一个简单的电影购票场景来实现微服务。
如图: 这个场景当中,用户微服务是一个服务提供者,电影微服务是一个服务消费者,之前我们也说到,每个微服务从开发,测试,构建,部署,都应当独立运行,即每个微服务是单独的子项目。下面来实现这个场景。
一、编写服务提供者 新建一个Spring Boot (版本1.5.9.RELEASE) 项目,不知道如何在IDEA中新建的可以看这篇>>传送门::Spring Boot 入门知识
添加依赖 项目使用H2作为数据库,使用jpa作为持久层框架。Spring Boot环境中H2数据库的基本配置可参考这篇>>传送门:Spring Boot环境下的 H2数据库基本配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-jpa</artifactId > </dependency > <dependency > <groupId > com.h2database</groupId > <artifactId > h2</artifactId > </dependency > </dependencies > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > Edgware.RELEASE</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement >
配置 application.yml 文件配置如下 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 server: port: 8000 spring: jpa: generate-ddl: false show-sql: true hibernate: ddl_auto: none h2: console: path: /h2-console enabled: true settings: web-allow-others: true datasource: platform: h2 schema: classpath:schema.sql data: classpath:data.sql
spring.h2.console.path 指定了h2控制台的路径,可以通过localhost:8000/h2-console 去访问H2的控制台。 spring.datasource.schema 与 datasource.data 会在每次启动项目时都会被执行
schema.sql
1 2 drop table user if exists ;create table user (id bigint generated by default as identity , username varchar (40 ), name varchar (20 ), age int (3 ), balance decimal (10 ,2 ), primary key (id));
data.sql
1 2 3 insert into user (id, username, name, age, balance) values (1 , 'account1' , '张三' , 20 , 100.00 );insert into user (id, username, name, age, balance) values (2 , 'account2' , '李四' , 28 , 180.00 );insert into user (id, username, name, age, balance) values (3 , 'account3' , '王一' , 32 , 280.00 );
pojo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Entity @JsonIgnoreProperties(value={"hibernateLazyInitializer","handler"}) public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column private String username; @Column private String name; @Column private Integer age; @Column private BigDecimal balance; }
报错 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer 如果在运行时报以上错误,则需要添加注释:@JsonIgnoreProperties(value={“hibernateLazyInitializer”,”handler”})
这是因为 hibernate会给每个被管理的对象加上hibernateLazyInitializer属性,jsonplugin通过java的反射机制将pojo转换成json,会把hibernateLazyInitializer也拿出来操作,但是hibernateLazyInitializer无法由反射得到,就会抛异常了。
Dao 1 2 3 @Repository public interface UserRepository extends JpaRepository <User,Long>{}
Controller 1 2 3 4 5 6 7 8 9 10 11 @RestController public class UserController { @Autowired private UserRepository userRepository; @GetMapping("/{id}") public User findById (@PathVariable Long id) { User findOne = this .userRepository.getOne(id); return findOne; } }
@GetMapping() 等同于 @RequestMapping(method = {RequestMethod.GET})
测试 运行项目,访问测试
二、编写服务消费者 消费者作为服务调用方,这里只使用最简单的方式来实现。
添加依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > Edgware.RELEASE</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement >
配置 application.yml
1 2 3 4 server: port: 8011 user: userServiceUrl: http://localhost:8000/
user.userServiceUrl :把调用地址写入配置文件
pojo 这里与上面的服务提供者相同
RestTemplate 实例化RestTemplate 在启动类中添加以下方法:
1 2 3 4 @Bean public RestTemplate restTemplate () { return new RestTemplate (); }
Controller 1 2 3 4 5 6 7 8 9 10 11 12 @RestController public class UserController { @Autowired private RestTemplate restTemplate; @Value("${user.userServiceUrl}") private String userServiceUrl; @GetMapping("/user/{id}") public User findById (@PathVariable Long id) { return this .restTemplate.getForObject(this .userServiceUrl + id,User.class); } }
这里使用 restTemplate 来调用服务 @Value(“${user.userServiceUrl}”) 从配置文件中取user.userServiceUrl值
测试 启动项目进行测试
三、总结 至此,一个简单的微服务完成!是不是觉得与我们平时写接口是差不多的,平时我们是在整个系统内部,各个功能模块之间进行接口调用,微服务则是把这些模块单独出来成为一个子系统,每个子系统提供接口给其它系统调用。在整个电影购票系统中 使用单一职责原则:两个微服务只关注整个系统中单独,有界限的一部分。 满足服务自治原则:每个微服务具备独立的业务能力,依赖与运行环境。 使用了轻量级通信机制:消费者中使用了Rest 进行服务调用 微服务粒度:两个微服务都有明确的功能划分。
当然微服务不只是这么简单,还应该包括安全性,高可用性等,还需要集成其它的组件,后面会边学习边作记录。