SpringCloud01
单体架构:简单方便,高度耦合,扩展性差,适合小型项目。
分布式架构:松耦合,扩展性好,但架构复杂,难度大,适合大型互联网项目。
-
微服务是一种良好的分布式架构方案
①优点:拆分粒度更小、服务更独立、耦合度更低
②缺点:架构非常复杂,运维、监控、部署难度提高
-
SpringCloud是微服务架构的一站式解决方案,集成了各种优秀微服务功能组件,并基于SpringBoot实现了这些组件的自动装配,从而提供了良好的开箱即用体验。另外,SpringCloud底层是依赖于SpringBoot的。
服务拆分
微服务拆分原则:
- 不同微服务,不要重复开发相同业务
- 微服务数据独立,不要访问其它微服务的数据库
- 微服务可以将自己的业务暴露为接口,供其它微服务调用
示例结构如下:
cloud-demo:父工程,管理依赖
- order-service:订单微服务,负责订单相关业务
- user-service:用户微服务,负责用户相关业务
要求:
- 订单微服务和用户微服务都必须有各自的数据库,相互独立
- 订单服务和用户服务都对外暴露Restful的接口
- 订单服务如果需要查询用户信息,只能调用用户服务的Restful接口,不能查询用户数据库
1.导入Sql语句
首先,将课前资料提供的cloud-order.sql
和cloud-user.sql
导入到mysql中:
mysql> select * from cluster_order.tb_order;
+-----+---------+-----------------------------------------+--------+------+
| id | user_id | name | price | num |
+-----+---------+-----------------------------------------+--------+------+
| 101 | 1 | Apple 苹果 iPhone 12 | 699900 | 1 |
| 102 | 2 | 雅迪 yadea 新国标电动车 | 209900 | 1 |
| 103 | 3 | 骆驼(CAMEL)休闲运动鞋女 | 43900 | 1 |
| 104 | 4 | 小米10 双模5G 骁龙865 | 359900 | 1 |
| 105 | 5 | OPPO Reno3 Pro 双模5G 视频双防抖 | 299900 | 1 |
| 106 | 6 | 美的(Midea) 新能效 冷静星II | 544900 | 1 |
| 107 | 2 | 西昊/SIHOO 人体工学电脑椅子 | 79900 | 1 |
| 108 | 3 | 梵班(FAMDBANN)休闲男鞋 | 31900 | 1 |
+-----+---------+-----------------------------------------+--------+------+
mysql> select * from cluster_user.tb_user;
+----+-----------+-----------------------------+
| id | username | address |
+----+-----------+-----------------------------+
| 1 | 柳岩 | 湖南省衡阳市 |
| 2 | 文二狗 | 陕西省西安市 |
| 3 | 华沉鱼 | 湖北省十堰市 |
| 4 | 张必沉 | 天津市 |
| 5 | 郑爽爽 | 辽宁省沈阳市大东区 |
| 6 | 范兵兵 | 山东省青岛市 |
+----+-----------+-----------------------------+
cloud-order表中持有cloud-user表中的id字段。
2.导入demo工程
用IDEA导入资料提供的Demo:
\cloud-demo\cloud-demo\user-service\src\main\resources\application.yml
[root@test cloud-demo]# tree user-service
user-service
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── cn
│ │ └── itcast
│ │ └── user
│ │ ├── mapper
│ │ │ └── UserMapper.java
│ │ ├── pojo
│ │ │ └── User.java
│ │ ├── service
│ │ │ └── UserService.java
│ │ ├── UserApplication.java
│ │ └── web
│ │ └── UserController.java
│ └── resources
│ └── application.yml
└── test
└── java
user-service
[root@test cloud-demo]# cat user-service/src/main/resources/application.yml
server:
port: 8081 //服务端口
spring:
datasource:
//数据库信息,需要链接的数据库cloud_user,账户,密码
url: jdbc:mysql://192.168.1.17:3306/cloud_user?useSSL=false
username: admin
password: 123456
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
[root@test cloud-demo]# cat user-service/src/main/java/cn/itcast/user/web/UserController.java
...
@Slf4j
@RestController
@RequestMapping("/user") //接口
public class UserController {
@Autowired
private UserService userService;
/**
* 路径: /user/110
*
* @param id 用户id
* @return 用户
*/
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id) {
// 根据id查询cluster_user并返回符合id的信息,规则由userService.queryById定义
return userService.queryById(id);
}
}
访问接口localhost:8081/user/1
返回数据库里id是1的信息 | 1 | 柳岩 | 湖南省衡阳市
order-service
[root@test cloud-demo]# cat order-service/src/main/resources/application.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://192.168.1.17:3306/cloud_order?useSSL=false
username: admin
password: 123456
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
[root@test cloud-demo]# cat order-service/src/main/java/cn/itcast/order/web/OrderController.java
...
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单cluser_order并返回
return orderService.queryOrderById(orderId);
}
}
访问接口localhost:8080/order/101
返回数据库里id是101的信息 | 101 | 1 | Apple 苹果 iPhone 12 | 699900 | 1 |
3.实现远程调用案例
在order-service中 向user-service发起一个http的请求,调用http://localhost:8081/user/{userId}这个接口。大概的步骤是这样的:
- 注册一个RestTemplate的实例到Spring容器
- 修改order-service服务中的OrderService类中的queryOrderById方法,根据Order对象中的userId查询User
- 将查询的User填充到Order对象,一起返回
4.注册RestTemplate
[root@test cloud-demo]# tree order-service/
order-service/
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── cn
│ │ └── itcast
│ │ └── order
│ │ ├── mapper
│ │ │ └── OrderMapper.java
│ │ ├── OrderApplication.java
│ │ ├── pojo
│ │ │ ├── Order.java
│ │ │ └── User.java
│ │ ├── service
│ │ │ └── OrderService.java
│ │ └── web
│ │ └── OrderController.java
│ └── resources
│ └── application.yml
└── test
└── java
[root@test cloud-demo]# cat order-service/src/main/java/cn/itcast/order/pojo/Order.java
package cn.itcast.order.pojo;
import lombok.Data;
@Data
public class Order {
private Long id;
private Long price;
private String name;
private Integer num;
private Long userId; //加入了返回的userid项
private User user;
首先,我们在order-service服务中的OrderApplication启动类中,注册RestTemplate实例:
[root@test cloud-demo]# cat order-service/src/main/java/cn/itcast/order/OrderApplication.java
...
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
/**
* Bean创建RestTemplate实例并注入Spring容器
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
/* @Bean
public IRule randomRule() {
return new RandomRule();
}*/
}
OrderController.java里的 return orderService.queryOrderById(orderId) 定义了查询指向OrderService
因此修改order-service服务中的cn.itcast.order.service包下的OrderService类中的queryOrderById方法:
[root@test cloud-demo]# cat order-service/src/main/java/cn/itcast/order/service/OrderService.java
...
@Service
public class OrderService {
...
/*@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.利用RestTemplate发起http请求,查询用户
String url = "http://localhost:8081/user/" + order.getUserId();
// 2.2.发送http请求,实现远程调用
User user = restTemplate.getForObject(url, User.class);
// 3.封装user到Order
order.setUser(user);
// 4.返回
return order;
}*/
}
访问端口时,便能获得需要调用的信息了
但是 String url = “http://localhost:8081/user/” + order.getUserId(); 是硬编码并不利于服务的维护,以及应对调用多实例的服务。比如user-service部署了多个实例。这些问题都需要利用SpringCloud中的注册中心来解决,其中最常用的注册中心就是Eureka以及nacos。