简介:java系列技术分享(持续更新中…)
初衷:一起学习、一起进步、坚持不懈
如果文章内容有误与您的想法不一致,欢迎大家在评论区指正
希望这篇文章对你有所帮助,欢迎点赞 收藏 ⭐留言更多文章请点击
Spring Cloud
官网:https://spring.io/projects/spring-cloud
Eureka
官网:https://github.com/Netflix/eureka
Spring Cloud
是目前用于开发微服务的主流框架之一,我们都知道在微服务架构中最为基础、核心的模块,就是服务注册与发现。
Spring Cloud
封装了 Netflix
公司开发的 Eureka
模块来实现 服务注册和发现。Eureka Server
作为 服务注册中心,系统中的 其他微服务,使用 Eureka
的 客户端 连接到 Eureka Server
,并通过 心跳连接 检测服务的 存活状态。
Eureka 包含两个组件:Eureka Server
和 Eureka Client
Eureka Server
: 作为 服务注册中心,提供 服务注册和发现,提供服务注册服务,各个节点启动后,会在 EurekaServer 中进行注册,这样 EurekaServer 中的服务注册表中将会存储所有可用服务节点的信息。
Eureka Client
: 所有注册到 服务中心 的服务。是一个 Java 客户端,用于简化 Eureka Server 的交互,客户端同时也具备一个内置的、使用轮询 (round-robin) 负载算法的负载均衡器
。在应用启动后,将会向 Eureka Server 发送心跳 (默认周期为 30 秒)。
Service Provider
: 把 自身的服务 注册到 Eureka Server,从而使 服务消费方 能够找到。Service Consumer
: 从 Eureka Server
获取 服务注册列表,从而能够 消费服务。在微服务架构中往往会有一个注册中心,每个微服务都会向注册中心去注册自己的地址及端口信息
,注册中心维护着服务名称与服务实例的对应关系。首先我们注册中心服务端:eureka-server,这必须是一个独立的微服务
。下面我们来搭建搭建 eureka-server。
原始http服务调用 -存在问题:
请看下图
(纯手工绘制有点瑕疵)Eureka的作用 图解:
来自Spring Cloud官方文档 :https://spring.io/projects/spring-cloud
概述了Spring Cloud的版本与Spring Boot的版本对应关系,需要注意
最新更新可查看官方文档
父项目Pom文件
可以看到下文中:Spring Boot
的版本是2.7.1
因此根据上图Spring Cloud
的版本为:2021.0.1
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.1version>
<relativePath/>
parent>
<properties>
<java.version>1.8java.version>
<spring-cloud.version>2021.0.1spring-cloud.version>
<hutool.version>5.8.2hutool.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>${hutool.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
不引入parent也可以这样配置
<properties>
<java.version>1.8java.version>
<spring-boot.version>2.7.1spring-boot.version>
<spring-cloud.version>2021.0.1spring-cloud.version>
<hutool.version>5.8.2hutool.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>${hutool.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencyManagement>
两种都可以
spring-cloud-starter-netflix-eureka-server
依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
@EnableEurekaServer
注解server:
port: 10086
spring:
application:
name: eureka-server
main:
allow-bean-definition-overriding: true
eureka:
client:
serviceUrl:
defaultZone: http://127.0.0.1:10086/eureka/
# register-with-eureka: false # 不注册自己
# fetch-registry: false #不拉取服务
将provider-service注册到Eureka-Server中
步骤如下:
provider-service模块
(服务提供者)spring-cloud-starter-netflix-eureka-client
依赖,注意后缀是client
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
server:
port: 20086
spring:
application:
name: provider-service
main:
allow-bean-definition-overriding: true
eureka:
client:
serviceUrl:
defaultZone: http://127.0.0.1:10086/eureka/
需求
:根据订单id查询订单的同时查询对应用户信息一起返回
消费者中提供订单信息
提供者提供用户信息
数据在各自对应数据库中
消费者端
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
/**
* 消费者
*/
@Autowired
private ConsumerService consumerService;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
return consumerService.queryOrderById(orderId);
}
}
public interface ConsumerService {
/**
* 根据id查询订单并返回
*/
Order queryOrderById(Long orderId);
}
@Service
public class ConsumerServiceImpl implements ConsumerService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
/**
* 根据id查询订单并返回
*/
@Override
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
//2远程查询用户信息
String url="http://localhost:20086/provider/"+order.getUserId();
//2. 发起调用
User user = restTemplate.getForObject(url, User.class);
//3. 存入order
order.setUser(user);
// 4.返回
return order;
}
}
@Mapper
public interface OrderMapper {
@Select("select id, name, num, user_id userId, price from `order` where id = #{id}")
Order findById(Long orderId);
}
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
/**
* 没有实例化RestTemplate时,初始化RestTemplate
* @return
*/
@ConditionalOnMissingBean(RestTemplate.class)
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
提供者端
@RestController
@RequestMapping("/provider")
public class ProviderController {
@Autowired
private ProviderService providerService;
/**
* 根据id查询用户信息
*/
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id) {
return providerService.queryById(id);
}
}
public interface ProviderService {
/**
* 根据id查询用户信息
*/
User queryById(Long id);
}
@Service
public class ProviderServiceImpl implements ProviderService {
@Autowired
private UserInfoMapper userMapper;
/**
* 根据id查询用户信息
*/
@Override
public User queryById(Long id) {
return userMapper.findById(id);
}
}
@Mapper
public interface UserInfoMapper {
@Select("select * from user where id = #{id}")
User findById(@Param("id") Long id);
}
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
查看上文代码消费者端是基于全路径http://localhost:20086/provider/1 调用
//2远程查询用户信息
String url="http://localhost:20086/provider/"+order.getUserId();
存在问题:
可参考上文------Eureka的作用 图解
这是成功注册的服务
基于服务名称获取服务列表,然后对服务列表做负载均衡
服务名代替ip,端口
使用provider-service
(自己配置的服务名)代替localhost:20086
//2远程查询用户信息
String url="http://provider-service/provider/"+order.getUserId();
在服务消费者的启动类的RestTemplate
添加@LoadBalanced
负载均衡注解
负载均衡详解后续文章中更新
/**
* 没有实例化RestTemplate时,初始化RestTemplate
* @return
*/
@ConditionalOnMissingBean(RestTemplate.class)
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
消费者该如何获取服务提供者具体信息?
如果有多个服务提供者,消费者该如何选择?
消费者如何感知服务提供者健康状态?
EurekaServer: 服务端,注册中心
Provider
: 服务提供者,例如案例中的provider-service
consumer
:服务消费者,例如案例中的 consumer-service