服務拆分注意事項
單一職責:不同微服務,不要重復開發相同業務
數據獨立:不要訪問其它微服務的數據庫
面向服務:將服務暴露為接口,供其它微服務調用

簡單項目
需求:查詢訂單信息時將用戶信息也查詢
微服務分析:
- 需要兩個服務UserService(操作用戶信息)、OrderService(操作訂單信息)
- OrderService遠程調用UserService提供查詢用戶信息的方法
搭建工程
數據庫Sql語句
cloud-user數據庫中user表
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for tb_user -- ---------------------------- DROP TABLE IF EXISTS `tb_user`; CREATE TABLE `tb_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '收件人', `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `username`(`username`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of tb_user -- ---------------------------- INSERT INTO `tb_user` VALUES (1, '柳岩', '湖南省衡陽市'); INSERT INTO `tb_user` VALUES (2, '文二狗', '陝西省西安市'); INSERT INTO `tb_user` VALUES (3, '華沉魚', '湖北省十堰市'); INSERT INTO `tb_user` VALUES (4, '張必沉', '天津市'); INSERT INTO `tb_user` VALUES (5, '鄭爽爽', '遼寧省沈陽市大東區'); INSERT INTO `tb_user` VALUES (6, '范兵兵', '山東省青島市'); SET FOREIGN_KEY_CHECKS = 1;
cloud-order數據庫中order表
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for tb_order -- ---------------------------- DROP TABLE IF EXISTS `tb_order`; CREATE TABLE `tb_order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '訂單id', `user_id` bigint(20) NOT NULL COMMENT '用戶id', `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '商品名稱', `price` bigint(20) NOT NULL COMMENT '商品價格', `num` int(10) NULL DEFAULT 0 COMMENT '商品數量', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `username`(`name`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of tb_order -- ---------------------------- INSERT INTO `tb_order` VALUES (101, 1, 'Apple 蘋果 iPhone 12 ', 699900, 1); INSERT INTO `tb_order` VALUES (102, 2, '雅迪 yadea 新國標電動車', 209900, 1); INSERT INTO `tb_order` VALUES (103, 3, '駱駝(CAMEL)休閑運動鞋女', 43900, 1); INSERT INTO `tb_order` VALUES (104, 4, '小米10 雙模5G 驍龍865', 359900, 1); INSERT INTO `tb_order` VALUES (105, 5, 'OPPO Reno3 Pro 雙模5G 視頻雙防抖', 299900, 1); INSERT INTO `tb_order` VALUES (106, 6, '美的(Midea) 新能效 冷靜星II ', 544900, 1); INSERT INTO `tb_order` VALUES (107, 2, '西昊/SIHOO 人體工學電腦椅子', 79900, 1); INSERT INTO `tb_order` VALUES (108, 3, '梵班(FAMDBANN)休閑男鞋', 31900, 1); SET FOREIGN_KEY_CHECKS = 1;
創建maven項目,父工程

pom配置
使用SpringBoot,需要添加父級:SpringBoot:2.3.9.RELEASE
依賴管理
- SpringCloud:Hoxton.SR10(注意版本)
- MySql、Mybatis
<packaging>pom</packaging> <!--父級節點--> <parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.3.9.RELEASE</version> </parent> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR10</spring-cloud.version> <mysql.version>5.1.47</mysql.version> <mybatis.version>2.1.1</mybatis.version> </properties> <dependencyManagement> <dependencies> <!-- springCloud --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- mysql驅動 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.version}</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
創建子模塊user-service、order-service

項目結構如下

編寫user-service
編寫pom
添加MySQL和mybatis依賴、maven插件(打包成可直接運行的 JAR 文件)
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <build> <!--jar包名稱--> <finalName>user-service</finalName> <plugins> <!--打包成可以直接運行的 JAR 文件(使用“java -jar”命令就可以直接運行)--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
配置application.yaml(配置服務器端口、數據庫連接、mybatis、logging)
server: port: 8081 spring: datasource: url: jdbc:mysql://192.168.223.129:3306/cloud-user?useSSL=false username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver mybatis: type-aliases-package: com.marw.pojo configuration: map-underscore-to-camel-case: true logging: level: com.marw: debug pattern: dateformat: MM-dd HH:mm:ss:SSS
啟動類
@SpringBootApplication public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class,args); } }
pojo(Java Bean)
@Data public class User { private Long id; private String username; private String address; }
mapper(數據庫操作)
public interface UserMapper { @Select("select * from tb_user where id = #{id}") User findById(@Param("id") Long id); }
service(業務邏輯)
@Service public class UserService { @Autowired private UserMapper userMapper; public User queryById(Long id){ return userMapper.findById(id); } }
controller(暴露服務)
@Slf4j @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @GetMapping("/{id}") public User queryByid(@PathVariable("id") Long id) { return userService.queryById(id); } }
啟動項目
錯誤:Field userMapper in com.marw.service.UserService required a bean of type 'com.marw.mapper.UserMapper' that could not be found
原因:沒有將mapper放到spring容器中
解決:將mapper放到spring容器中
方式一:添加@Mapper注解
@Mapper public interface XxxMapper { ... ... }
方式二:通過掃描mapper所在的包
@SpringBootApplication @MapperScan("com.marw.mapper") public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class,args); } }
項目整體結構

測試

order-service和user-service類似,就不重復編寫,直接查看效果

發現user的數據為空,也就是說order服務需要調用user服務提供的方法
微服務遠程調用
遠程調用方式分析
瀏覽器通過http(http://localhost:8081/user/1)請求訪問user服務,如果order服務也能通過http(http://localhost:8081/user/1)請求訪問user服務
RestTemplate
spring提供發送http請求的工具
注冊RestTemplate
通過Bean注入(@Bean注解)將RestTemplate對象注冊到Spring容器中,就可以使用依賴注入方式(@Autowired)從Spring容器中獲取RestTemplate對象
Bean注入只能寫入Java配置類(被@Configuration注解的類)
@SpringBootApplication @MapperScan("com.marw.mapper") public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
使用RestTemplate
@Service public class OrderService { @Autowired private OrderMapper orderMapper; @Autowired private RestTemplate restTemplate; public Order queryById(Long id){ Order order = orderMapper.findById(id); String url = "http://localhost:8081/user/"+order.getUserId(); User user = restTemplate.getForObject(url, User.class); order.setUser(user); return order; } }
使用restTemplate方法getForObject還是postForObject等是根據請求方法所指定的請求方式決定的
測試
chorme的Json格式化工具下載地址:https://github.com/gildas-lormeau/JSONView-for-Chrome

