微服务实战 本项目示例是一个图书借阅系统,本教程会更加注重于架构设计上的讲解,弱化业务功能和实现原理方面的研究。
服务的拆分
单一职责:不同微服务开发不同的业务
数据独立:每个微服务拥有自己的数据库
面向服务:将业务暴露为接口,供其他微服务使用
微服务项目搭建 构建父项目
父项目只负责依赖管理,删除无用文件
导入通用依赖
新建子模块
创建启动类
创建配置文件-application.yml
添加服务端口号
导入spring-boot-starter-web依赖
1 2 3 4 5 6 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > </dependencies >
数据库设计 在实际的应用场景中,每个微服务都有自己的数据库服务器,按照单一职责的原则,每个微服务只会操作自己的数据库。
添加索引
在父项目引入MyBatis依赖进行版本管理
1 2 3 4 5 6 7 8 9 10 <dependencyManagement > <dependencies > <dependency > <groupId > org.mybatis.spring.boot</groupId > <artifactId > mybatis-spring-boot-starter</artifactId > <version > 2.2.0</version > </dependency > </dependencies > </dependencyManagement >
在子项目中引入Mybatis依赖
1 2 3 4 <dependency > <groupId > org.mybatis.spring.boot</groupId > <artifactId > mybatis-spring-boot-starter</artifactId > </dependency >
数据源信息配置
1 2 3 4 5 6 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/cloudstudy_user username: root password: 13851176590++
公共项目创建和引入 将服务需要用到的实体类单独放入一个项目模块中,将需要实体类的项目模块引用存放共用实体的项目,以保证每个微服务的实体类信息共用。
在需要共用实体类的项目模块中引入
1 2 3 4 5 <dependency > <groupId > com.example</groupId > <artifactId > common</artifactId > <version > 0.0.1-SNAPSHOT</version > </dependency >
书籍信息查询业务
创建Dao: 1 2 3 4 5 @Mapper public interface BookMapper { @Select("select * from book_info where id = #{id}") Book getBookById (Long id) ; }
创建Service: 1 2 3 public interface BookService { Book getBookById (Long id) ; }
1 2 3 4 5 6 7 8 9 10 @Service public class BookServiceImpl implements BookService { @Resource BookMapper bookMapper; @Override public Book getBookById (Long id) { return bookMapper.getBookById(id); } }
创建Controller: 1 2 3 4 5 6 7 8 9 10 @RestController public class BookController { @Resource BookService bookService; @RequestMapping("/book/{id}") public Book getBookById (@PathVariable("id") Long id) { return bookService.getBookById(id); } }
用户信息查询业务同理
服务提供和消费 借阅业务查询业务 微服务构建的是一个分布式系统,微服务之间通过网络进行通信,可以使用服务提供者与服务消费者来描述微服务之间的调用关系。
借阅服务是一个关联性比较强的服务,需要在查询出借阅信息的基础上,获取借阅用户和借阅书籍的详细信息。根据单一职责和数据独立的原则,我们可以让一个服务作为消费者调用另一个服务即提供者来获取信息。
RestTemplate-HTTP请求工具实现远程调用 这里先使用RestTemplate作为HTTP请求工具,它提供了常见的REST请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。
注册RestTemplate 由于启动类也是配置类,我们可以直接在启动类实现RestTemplate对象的创建和注册。
1 2 3 4 5 6 7 8 9 10 11 12 13 @SpringBootApplication @MapperScan("com.test.dao") public class BorrowApplication { public static void main (String[] args) { SpringApplication.run(BorrowApplication.class, args); } @Bean public RestTemplate restTemplate () { return new RestTemplate (); } }
这里以查询用户借阅信息为例
配置文件配置mybatis 1 2 3 mybatis: mapper-locations: - classpath:mapper/*.xml
在启动类添加@MapperScan
业务处理 创建服务实体类: 1 2 3 4 5 6 @Data @AllArgsConstructor public class UserBorrowDetail { User user; List<Book> books; }
创建Dao: 1 2 3 4 @Mapper public interface BorrowMapper { List<Borrow> getBorrow (Long uid, Long bid) ; }
创建mapper.xml: 1 2 3 4 5 6 7 8 9 <mapper namespace ="com.test.dao.BorrowMapper" > <select id ="getBorrow" resultType ="com.test.entity.Borrow" > SELECT * FROM borrow_info <where > <if test ="uid != null" > uid = #{uid}</if > <if test ="bid != null" > and bid = #{bid}</if > </where > </select > </mapper >
创建Service: 1 2 3 public interface BorrowService { UserBorrowDetail getBorrowByUser (Long uid) ; }
使用RestTemplate服务远程调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Service public class BorrowServiceImpl implements BorrowService { @Resource BorrowMapper borrowMapper; @Resource RestTemplate restTemplate; @Override public UserBorrowDetail getBorrowByUser (Long uid) { List<Borrow> borrows = borrowMapper.getBorrow(uid,null ); User user = restTemplate.getForObject("http://localhost:8101/user/" + uid, User.class); List<Book> books = borrows.stream().map(borrow -> restTemplate.getForObject("http://localhost:8201/book/" + borrow.getBid(), Book.class)).collect(Collectors.toList()); return new UserBorrowDetail (user, books); } }
创建Controller: 1 2 3 4 5 6 7 8 9 10 @RestController public class BorrowController { @Resource BorrowService borrowService; @RequestMapping("/borrow/user/{uid}") public UserBorrowDetail getBorrowByUser (@PathVariable("uid") Long uid) { return borrowService.getBorrowByUser(uid); } }