springcloud各个组件搭配使用演示
springcloud各个组件使用demo
Eureka服务注册中心
创建三个eureka服务注册中心,分别为:
eureka-server1
spring:application:name: eureka-server1
server:port: 8001eureka:client:service-url:defaultZone: http://localhost:8002/eureka/,http://localhost:8003/eureka/fetch-registry: trueregister-with-eureka: true
eureka-server2
server:port: 8002
spring:application:name: eureka-server2
eureka:client:service-url:defaultZone: http://localhost:8001/eureka/,http://localhost:8003/eureka/register-with-eureka: truefetch-registry: true
eureka-server3
server:port: 8003
spring:application:name: eureka-server3
eureka:client:service-url:defaultZone: http://localhost:8001/eureka/,http://localhost:8002/eureka/fetch-registry: trueregister-with-eureka: true
三个服务注册中心的pom.xml内容一样, 都如下:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-microservice-parent</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>eureka-server3</artifactId><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency></dependencies></project>
其中父pom.xml文件内容如下:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>springboot-microservice-parent</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>eureka-server1</module><module>eureka-server2</module><module>eureka-server3</module><module>goods</module><module>goods2</module><module>ribbon-client</module></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version><relativePath/></parent><dependencyManagement><dependencies><!--根据springboot的版本指定springCloud的版本--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>2020.0.6</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement></project>
eureka-server1、eureka-server2、eureka-server3入口代码相同,都如下:
入口类的类名不同,其他都相同:
EurekaServer1Application.java
EurekaServer2Application.java
EurekaServer3Application.java
package com.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication
@EnableEurekaServer
public class EurekaServer1Application {public static void main(String[] args) {SpringApplication.run(EurekaServer1Application.class, args);}
}
代码结构图
Eureka客户端
① goods微服务(扮演eureka客户端角色)
application.yaml
server:port: 9001
spring:application:name: goods-server
eureka:client:service-url:defaultZone: http://localhost:8001/eureka/,http://localhost:8002/eureka/,http://localhost:8003/eureka/
pom.xml
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-microservice-parent</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>goods</artifactId><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-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><fork>true</fork></configuration></plugin></plugins></build></project>
入口文件
GoodsApplication.java
package com.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;@SpringBootApplication
@EnableEurekaClient
public class GoodsApplication {public static void main(String[] args) {SpringApplication.run(GoodsApplication.class, args);}
}
测试控制器类: GetGoodsController.java
package com.example.controller;import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/goods")
public class GetGoodsController {@Value("${server.port}")private int port;@RequestMapping("/getOne")public String getOneGoods() {return "返回一条数据"+String.valueOf(port);}
}
②goods2微服务(扮演eureka客户端角色), 同goods微服务完全一样
goods2和goods的监听端口不同,其他都一样
goods2的
application.yaml
如下:server:port: 9002 spring:application:name: goods-server eureka:client:service-url:defaultZone: http://localhost:8001/eureka/,http://localhost:8002/eureka/,http://localhost:8003/eureka/
启动eureka-server1
eureka-server2
eureka-server3
服务端, 再启动goods
goods2
客户端后, 访问 http://localhost:8001, http://localhost:80012, http://localhost:8003 如下:
可以看到, 各个微服务都已经注册到注册中心了; 其中的微服务RIBBON-SERVER是后面要演示的负载均衡调用组件
负载均衡调用组件 Ribbon
pom.xml
一定要避开一个坑: Ribbon组件和Eureka-client不要同时引入
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-microservice-parent</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>ribbon-client</artifactId><dependencies><!-- eureka-client 已经集成了loadbalanced了,不需要在引入ribbon了,否则引起会冲突,但是启动的时候也不报这个冲突的错误,这里一定要避开这个坑!!!,否则后面调试让你头大,报错一直找不到微服务GOODS-SERVER实例 --><!--<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId><version>2.2.4.RELEASE</version></dependency>--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><fork>true</fork></configuration></plugin></plugins></build></project>
application.yaml
server:port: 10001
spring:application:name: ribbon-server
eureka:client:service-url:defaultZone: http://localhost:8001/eureka/,http://localhost:8002/eureka/,http://localhost:8003/eureka/
微服务入口文件RibbonClientApplication.java
入口类上不要再标注@RibbonClient注解了
package com.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;@SpringBootApplication
@EnableEurekaClient
// @RibbonClient(name = "GOODS-SERVER") //eureka-client组件已经引入了loadbalance了, 不需要在导入ribbon组件了
public class RibbonClientApplication {public static void main(String[] args) {SpringApplication.run(RibbonClientApplication.class, args);}
}
配置文件MyRestTemplate.java
package com.example.config;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;@Configuration
public class MyRestTemplate {@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}
控制器BalanceRequest.java
package com.example.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.List;/* 测试 ribbon负载均衡远程调用*/
@RestController
@RequestMapping("/ribbon")
public class BalanceRequest {@Autowiredprivate DiscoveryClient discoveryClient;@Autowiredprivate LoadBalancerClient loadBalancerClient;@Autowiredprivate RestTemplate restTemplate;//根据类型,会导入我们自己定义的MyRestTemplate类@RequestMapping("getGoods")public String getGoods() {//方式一:// RestTemplate restTemplate = new RestTemplate();// String forObject = restTemplate.getForObject("http://localhost:9001/goods/getOne", String.class);// System.out.println(forObject);// return forObject;//方式二//getServices()获取所有注册在注册中心的服务// List<String> services = discoveryClient.getServices();// for (String service : services) {// System.out.println(service);// }//获取某个服务id下的所有信息// List<ServiceInstance> instances = discoveryClient.getInstances("GOODS-SERVER");// for (ServiceInstance instance : instances) {// System.out.println(instance.getHost());// System.out.println(instance.getPort());// // System.out.println(instance.getMetadata());// System.out.println(instance.isSecure());// System.out.println(instance.getUri().toString());// System.out.println(instance.getServiceId());// System.out.println(instance.getScheme());// }// RestTemplate restTemplate = new RestTemplate();// // String forObject = restTemplate.getForObject(instances.get(0).getUri() + "/goods/getOne", String.class);// String forObject = restTemplate.getForObject(instances.get(1).getUri() + "/goods/getOne", String.class);// return forObject;//方式三: 坑!! 一直报错: loadBalancerClient.choose("goods-server")返回null, 原因就是同时导入了ribbon依赖,又有eureka-client依赖; eureka-client包中已经有了ribbon核心组件中的loadbalanced了,不需要再导入ribbon了// System.out.println("");// System.out.println(loadBalancerClient);// System.out.println(loadBalancerClient.choose("goods-server"));// System.out.println(loadBalancerClient.choose("GOODS-SERVER"));// System.out.println("");//// ServiceInstance choose = loadBalancerClient.choose("GOODS-SERVER");// ServiceInstance choose2 = loadBalancerClient.choose("goods-server");//// System.out.println("++++++++++++++++++++++");// System.out.println(choose);// System.out.println(choose2);// System.out.println(choose.getUri().toString());// System.out.println(choose.getHost());// System.out.println(choose.getPort());// System.out.println("++++++++++++++++++++++");// ServiceInstance choose = loadBalancerClient.choose("GOODS-SERVER");// RestTemplate restTemplate = new RestTemplate();// String forObject = restTemplate.getForObject(choose.getUri() + "/goods/getOne", String.class);// System.out.println(forObject);// return forObject;//方式四://如果不清楚eureka-client已经内置导入了loadbalance了,而再次导入Ribbon组件的话,将一直报错:找不到服务...: No instances available for GOODS-SERVER,坑!!!String forObject = restTemplate.getForObject("http://goods-server/goods/getOne", String.class);System.out.println(forObject);return forObject;}
}
代码接口图如下:
postman测试结果如下:
默认轮询的方式展示返回结果
第一次请求返回9001 | 再次请求返回9002 |
---|---|
![]() |
![]() |
OpenFeign远程调用组件
openFeign的详细使用, 参考: https://blog.csdn.net/zyb18507175502/article/details/126682187
这里使用 OpenFeign远程调用goods
微服务
pom.xml内容如下
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-microservice-parent</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>feign-client</artifactId><dependencies><!--feign代替RestTemplate进行远程调用--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies></project>
application.yaml内容如下
server:port: 11001
spring:application:name: feignclient-server
eureka:client:service-url:defaultZone: http://localhost:8001/eureka/,http://localhost:8002/eureka/,http://localhost:8003/eureka/
FeignClientApplication.java
package com.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableDiscoveryClient //当服务注册中心不限于eureka, 如consul,nacos等, 任何的服务注册中心都可以使用该注解标注客户端,范围更广
// @EnableEurekaClient//只能是Eureka作为服务注册中心时,使用该注解标注为客户端,范围较局限
@EnableFeignClients // 表明需要使用feign进行远程调用
public class FeignClientApplication {public static void main(String[] args) {SpringApplication.run(FeignClientApplication.class, args);}
}
MyFeignClient.java
package com.example.client;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;@FeignClient("GOODS-SERVER")
public interface MyFeignClient {//直接将goods或者goods2项目中的 getOneGoods()方法粘贴过来,去掉方法体就行//将goods微服务的类上的路径和方法上的路径合并后的最终路径写在这里@RequestMapping("/goods/getOne")String getOneGoods();
}
FeignClientGetGoodsController.java
package com.example.controller;import com.example.client.MyFeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/* 使用feignClient 代替RestTemplate进行远程调用*/
@RestController
@RequestMapping("/feignClient")
public class FeignClientGetGoodsController {// @Autowired@Resourceprivate MyFeignClient myFeignClient;@RequestMapping("/getGoods")public String getGoods() {System.out.println("请求到来!");String oneGoods = myFeignClient.getOneGoods();return oneGoods;}
}
代码结构如下图:
postman调用结果如下:
http://localhost:11001/feignClient/getGoods
![]() |
![]() |
---|---|
第一次调用返回9002 | 第二次调用9001 |