springCloud之微服务的注册发现与消费
- 代码地址
- 准备:新建一个空的maven项目用来当父项目【CloudDemo】我就是拿他当个根目录而已
- 一、项目准备:CloudDemo仅当作父项目使用【各个项目的根目录而已】
- 二、创建注册中心模块`cloud-registry` *SpringBoot项目*
- 三、注册中心的配置【yml格式】
- 四、搞定,注册中心就这么就没球了,启动`点个赞鼓励一下?`
- 五、去搞一个服务`cloud-service`【服务提供者】注册到eureka中,*SpringBoot项目*
- 六、服务提供者service的配置
- 七、依次启动
- 八、服务注册了, 提供两个接口服务用来消费(调用)
- 九、搞定,在弄个服务消费者`cloud-consume` *SpringBoot项目*
- 十、再弄个服务消费者`cloud-consume-feign` *SpringBoot项目*
- 十一、复制几个服务实现调用
- ==_本次demo知识点总结_==
- `未完待续——如果看到这里了,(●'◡'●)该去点赞了啊喂`
个人学习记录而已,没事就回来看看,给自己涨记性
不做名词解释,各种名词解释百度一堆堆
文章总结写在末尾点个赞鼓励一下?
文章有点长,目录是个好东西啊
哪里不对留言讨论,拜托描述清楚
废话连篇:凡心所向,素履所往;
代码地址
☆本文章的代码地址——需单独下载
★★项目完整代码——gitee地址:不断更新
准备:新建一个空的maven项目用来当父项目【CloudDemo】我就是拿他当个根目录而已
一、项目准备:CloudDemo仅当作父项目使用【各个项目的根目录而已】
1、删除没用的东西
2、maven配置
3、编译jdk设置
4、项目编码设置
二、创建注册中心模块cloud-registry
SpringBoot项目
注册中心选择的eureka Server 其他的依赖 个人习惯dev和lombok 然后一路下一步完成
完整项目结构:
cloud-registry
-pom.xml内容【默认最新的springCloud版本,Hoxton.SR8】
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.crazy</groupId>
<artifactId>cloud-registry</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cloud-registry</name>
<description>注册中心模块</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
项目依赖
三、注册中心的配置【yml格式】
server:
port: 8770 #端口
application:
name: Eureka-Registry #当前模块项目的服务名称
eureka:
client:
register-with-eureka: false #是否将自己注册到Eureka Server
fetch-registry: false #是否从Eureka Server获取注册信息
service-url:
defaultZone: http://localhost:${server.port}/eureka/ #当前注册中心的地址,其他的服务需要注册到这里
启动类增加Eureka的配置注解 @EnableEurekaServer
注解解释 :激活eureka的服务器配置
四、搞定,注册中心就这么就没球了,启动点个赞鼓励一下?
访问路径localhost:8770即可打开Eureka的管理界面
【直接IP:端口就可以,不用加/eureka】
后面注册进来的服务会在
Instances currently registered with Eureka展示
五、去搞一个服务cloud-service
【服务提供者】注册到eureka中,SpringBoot项目
还是新建一个moudle,依赖选择Eureka Discovery Client
pom.xml内容
添加了web依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.crazy</groupId>
<artifactId>cloud-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cloud-service</name>
<description>服务提供者,只提供接口服务</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
六、服务提供者service的配置
server:
port: 8771 #设置服务提供者的端口号
eureka:
client:
service-url:
defaultZone: http://localhost:8770/eureka/ #注册到那里的注册中心
spring:
application:
name: Eureka-Service #这个项目模块所提供服务的名称
在启动类上添加注解 @EnableEurekaClient
这里有点迷,最后的总结里面有说明
七、依次启动
先启动registry 然后再启动 service
再次打开Eureka的管理界面localhost:8770
可以发现服务提供者已经注册到注册中心了
点个赞鼓励一下?
八、服务注册了, 提供两个接口服务用来消费(调用)
给他提供两个最简单的服务接口
1、接口一返回一个字符串
2、接口二返回一个实体
启动类同级创建包,然后就是web开发的路子controller和service和mapper和pojo(moudle,entity)实体层和工具啊配置啊啥的各种包路径
package com.crazy.controller;
import com.crazy.pojo.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description 提供两个简单的服务
* @Author Crazy
* @Date 2020/10/10 14:52
* @Copyright
*/
@RestController
@RequestMapping("/test")
public class TestController {
/**
* 接口服务一
*/
@RequestMapping("/string")
public String hello(String str) {
System.out.println(">>>>>>进入/test/string>>>>>>传入的值:" + str );
//service层和impl以及mapper层略过
return "你好:" + str;
}
/**
* 接口服务二
*/
@RequestMapping("/getUser")
public User getUser() {
System.out.println(">>>>>>进入/test/getUser");
//service层和impl以及mapper层略过
User u = new User();
u.setId(1);
u.setUserName("疯疯颠颠");
u.setPassword("Crazy123");
return u;
}
}
重新启动cloud-service
测试
测试:编码也好,浏览器也好,我用的postman
九、搞定,在弄个服务消费者cloud-consume
SpringBoot项目
消费方式两种,这个模块是基于Ribbon+RestTemplate方式去消费调用服务
新建一个模块moudle【服务消费者cloud-consume】
依赖如下
项目配置文件
server:
port: 8772 #设置服务提供者的端口号
eureka:
client:
service-url:
defaultZone: http://localhost:8770/eureka/ #注册到那里的注册中心
spring:
application:
name: Eureka-Consume #这个项目模块所提供服务的名称
服务消费调用的方式有很多点个赞鼓励一下?
1、第一种直接调用 不经过注册中心
需要一个RestTemplate的客户端
源码解释为客户端负载均衡器
package com.crazy.beans;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @Description TODO
* @Author Crazy
* @Date 2020/10/10 15:35
* @Copyright
*/
@Configuration
public class Beans {
@Bean
@LoadBalanced //标记一个RestTemplate为客户端负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
controller直接调用的,没有走本模块的service以及mapper层
package com.crazy.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @Description 消费者调用服务Demo
* @Author Crazy
* @Date 2020/10/10 15:14
* @Copyright
*/
@RestController
@RequestMapping("/consume")
public class ConsumeController {
/**
* 第一种消费调用服务的方式
*/
@RequestMapping("/one")
public String helloWorld(String s) {
System.out.println("进入/consume/one>>>>>>传入的值为:" + s);
String One = new RestTemplate().getForObject("http://localhost:8771/test/string?str=" + s, String.class);
System.out.println("第一种>>>>>>:"+One);
return ">>>>>>调用返回的是:"+One;
}
}
启动cloud-consume项目
消费者也到注册中心了
测试
消费者控制台打印的信息
服务提供者控制台打印的信息
调用实体返回值
这里只在控制台打印,没有返回实体
打印信息
2、第二种消费方式【根据服务名 获取服务列表 访问某个服务的网络位置】
@Autowired
private LoadBalancerClient loadBalancerClient;
/**
* 第二种消费调用服务方式:根据服务名 获取服务列表 并访问某个服务的网络位置。
*/
@RequestMapping("/two")
public String helloTwo(String s){
System.out.println("进入/consume/two>>>>>>传入的值为:" + s);
RestTemplate restTemplate = new RestTemplate();
//获取服务信息
ServiceInstance serviceInstance = loadBalancerClient.choose("EUREKA-SERVICE");
String Two = restTemplate.getForObject("http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/test/string?str="+s,String.class);
//getForObject也可以返回实体数据 区别:直接返回请求的body里面的实体
User user = new RestTemplate().getForObject("http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/test/getUser?str=" + s, User.class);
System.out.println(">>>>>>调用返回的实体数据:" + user.toString());
return ">>>>>>调用返回的是:" + Two;
}
测试
控制台信息
3、第三种Ribbon+restTemplate注入
的方式
控制层
service层
service实现层
执行调用消费服务
service实现层代码
package com.crazy.service.impl;
import com.crazy.pojo.User;
import com.crazy.service.ConsumeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* @Description TODO
* @Author Crazy
* @Date 2020/10/10
* @Copyright
*/
@Service
public class ConsumeServiceImpl implements ConsumeService {
@Autowired
private RestTemplate rest;
@Override
public String testResult(String s) {
//restTemplate的对GET请求进行调用的两种请求方式 一
String str = rest.getForObject("http://EUREKA-SERVICE/test/string?str={1}", String.class,s);
//restTemplate的对GET请求进行调用的两种请求方式 二 上面的方式也可以响应为实体
ResponseEntity<User> forEntity = rest.getForEntity("http://EUREKA-SERVICE/test/getUser", User.class);
System.out.println(">>>>>>测试getForEntity返回值:"+forEntity.getBody());
//其他还有POST的各种API以后慢慢测试
return str;
}
}
测试
控制台打印信息
beans
也可以直接写道启动类中加载
十、再弄个服务消费者cloud-consume-feign
SpringBoot项目
第二种消费服务的方式,基于Feign去消费服务 两种消费方式区别比较写在最后
新建一个模块moudle【服务消费者cloud-consume-feign】
依赖如下
此模块项目配置文件
server:
port: 8773 #设置服务提供者的端口号
eureka:
client:
service-url:
defaultZone: http://localhost:8770/eureka/ #注册到那里的注册中心
spring:
application:
name: Eureka-Consume-Feign #这个项目模块所提供服务的名称
基于feign消费的方式,是以 HTTP 接口的形式暴露的,使用起来就像调用自己本地方式似的。
使用:
1、需要定义一抽象的个接口,不需要实现,直接定义了接口就行,简单增加一些注解
2、controller里面注入定义的Service,直接调用即可。
3、启动类增加一个注解,标记一下打开feign的客户端
启动-测试
区别?就记一下较为明显的区别吧
ribbon需要自己去构建服务的IP:端口:映射等
feign 只需要抽象方法里定义好服务名和映射路径,不需要知道服务的提供者是哪个服务端
十一、复制几个服务实现调用
注册中心现有的服务有
两个,一个服务提供者,一个服务消费者。多搞几个服务提供者玩玩?
服务层增加点东西,打印一下,每个服务的端口信息
两个都挺好用,都支持负债均衡
然后把服务多复制两个出来通过VM命令改一下端口
选中service直接复制
点击复制出来的服务Environment 分别去修改这两个复制出来的服务的端口号 -Dserver.port=8773
这里一个8773一个8774
现有的端口号
8770 注册中心
8771 服务提供者
8772 服务消费者
8773-8774是复制出来的两个服务提供者
完了之后点击-应用-OK
服务全部重启:顺序 registry-service-service01-service-02-consume 也就是一个注册中心,三个服务提供者,一个服务消费者
eureka管理界面中显示service服务有三个了,端口分别是8774-8771-8773 但是名字一样
再来测试消费的方式123,就3吧
控制台信息
three的请求,方法内部调用了两次服务,一次进了8774,一次进了8773,8773没有打印,所以页面只显示8774,多来几次
如果停掉其中一个服务节点,那么就会导致33%的请求会失败。这个问题需要熔断器来解决,或者修改注册中心的配置,剔除失效的服务节点,后面写好了再来补充
本次demo知识点总结
1、服务的注册发现与消费至少三个模块,分别为注册中心。服务提供者。服务消费者。依次按顺序启动。
2、可以对注册中心以及服务提供者分别进行负载均衡。通过配置文件修改端口即可实现。
3、服务消费者对服务的调用消费:Ribbon+RestTemplate是一种客户端负载均衡的消费服务的方式,还有一种消费方式:feign,也是基于ribbon实现需要自己创建一个接口注入到Beans,并且feign集成了ribbon,结合了eureka,默认实现了负载均衡。
4、关于注解@EnableEurekaClient 不加也可以,应该是新版cloud的特性,个人不太确定,没找到官方解释。源码注释也说是可选的。个人认为是通过配置文件生效的。
5、yml中配置的信息,注册中心指定注册中心的地址,服务提供者注册到注册中心指定的地址完成服务注册,服务消费者指定注册中心的地址用来获取服务。
6、俩个注解:@EnableDiscoveryClient和@EnableEurekaClient的效果一样,用哪个取决于用什么注册中心,如果选用的注册中心是eureka,那么就推荐@EnableEurekaClient,如果是其他的注册中心,那么推荐使用@EnableDiscoveryClient【但是这吊玩意可选的。。】
7、多个服务停止一个之后,可以通过命令向eureka发送删除指令剔除停止的服务。或者等待eureka自动检查去剔除。否则会继续请求停止的服务报错{http://localhost:8770/eureka/apps/Eureka-Service:8773}
8、两种消费服务的区别
Ribbon+RestTemplate: Ribbon是一个负载均衡客户端,可以很好的控制htt和tcp的一些行为。
Feign: Feign 采用的是基于接口的注解,使用起来就好像在调用自己本地模块的服务似的。并且Feign 整合了ribbon
未完待续——如果看到这里了,(●'◡'●)该去点赞了啊喂
有空写完其他的服务相关的再来补充,啥玩意路由啊,断路器啊,消息总线啊,服务链路啊啥的。