在上一节中,我们说了Consul注册中心实现了服务的注册和发现功能,这一节说一下服务的调用
在单体应用中,代码可以直接依赖,依赖后可直接调用,在微服务的架构中,服务都运行在各自的进程中,还有可能在不同的服务器上,所以需要相关的远程调用技术
Spring Cloud有两种比较广泛的微服务调用
1、使用RestTemplate进行调用,可以通过Ribbon注解RestTemplate模板,使用其拥有负载均衡的功能。
2、使用Feign进行声明式服务调用,声明之后就像调用本地方法一样,Feign默认使用Ribbon实现负载均衡。
方法一、RestTemplate方法
一、服务提供者
新建mango-producer项目
在pom中添加
Swagger:API文档
Consul:注册中心
Spring boot Admin :服务监控
依赖
<?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.4.4</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.louis</groupId> <artifactId>mango-producer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>mango-producer</name> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.version>1.0.0</project.version> <java.version>1.8</java.version> <swagger.version>2.9.2</swagger.version> <mybatis.spring.version>1.3.2</mybatis.spring.version> <druid.version>1.1.10</druid.version> <spring.boot.admin.version>2.0.4</spring.boot.admin.version> <spring-cloud.version>Finchley.RELEASE</spring-cloud.version> </properties> <dependencies> <!-- web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${swagger.version}</version> </dependency> <!--spring-boot-admin--> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-client</artifactId> <version>${spring.boot.admin.version}</version> </dependency> <!--consul--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <!--test--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</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>
修改配置文件
将application.properties改为application.yml
在yml配置文件中添加以下内容,将服务注册到注册中心并添加服务监控相关配置
server: port: 8003 spring: application: name: mango-producer cloud: consul: host: localhost port: 8500 discovery: serviceName: ${spring.application.name} # 注册到consul的服务名称 boot: admin: client: url: "http://localhost:8000" # 开放健康检查接口 management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS
修改启动类
在启动类添加 @EnableDiscoveryClient开启服务发现支持
@EnableDiscoveryClient @SpringBootApplication public class MangoProducerApplication { public static void main(String[] args) { SpringApplication.run(MangoProducerApplication.class, args); } }
添加控制器
@RestController public class HelloController { @RequestMapping("/hello") public String hello() { return "hello Mango !"; } }
为了模拟负载均衡,我们将上面的项目复制一份,修改端口为8004
然后启动注册中心、服务监控、和两个服务提供者
启动项目后访问http://localhost:8500/
可以看到我们的服务已经注册到了注册中心
可以看到两个提供的服务已经在监控的列表中
上面我们完成了服务提供者的搭建
下面进行服务消费者
二、服务消费者
新建项目mango-consumer
在pom文件中添加
Swagger:API文档
Consul:注册中心
Spring boot Admin :服务监控
依赖
配置yml
server: port: 8005 spring: application: name: mango-consumer cloud: consul: host: localhost port: 8500 discovery: serviceName: ${spring.application.name} # 注册到consul的服务名称 boot: admin: client: url: "http://localhost:8000" # 开放健康检查接口 management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS 启动类
在启动类添加
@EnableDiscoveryClient
开启服务发现支持
@EnableDiscoveryClient @SpringBootApplication public class MangoConsumerApplication { public static void main(String[] args) { SpringApplication.run(MangoConsumerApplication.class, args); } }
服务消费
添加消费服务测试类
ServiceController.java
添加两个接口,一个查询所有我们注册的服务
另一个从我们注册的服务中选一个服务,采取轮询的方式
@RestController public class ServiceController { @Autowired private LoadBalancerClient loadBalancerClient; @Autowired private DiscoveryClient discoveryClient; /** * 获取所有服务 */ @RequestMapping("/services") public Object services() { return discoveryClient.getInstances("mango-producer"); } /** * 从所有服务中选择一个服务(轮询) */ @RequestMapping("/discover") public Object discover() { return loadBalancerClient.choose("mango-producer").getUri().toString(); } }
添加完后,启动项目访问http://localhost:8500/
可以看到我们的消费服务已经注册到了注册中心
可以看到消费服务已在监控列表中
访问http://localhost:8005/services
可以看到返回的两个服务分别是8003和8004
然后反复访问http://localhost:8005/discover
交替返回8003和8004,因为默认负载均衡采用的是轮询方式
大多数情况下,我们采用负载均衡的形式去获取服务端提供的服务,因此我们新建一个CallHelloController.java
模拟调用服务的hello方法
@RestController public class CallHelloController { @Autowired private LoadBalancerClient loadBalancer; @RequestMapping("/call") public String call() { ServiceInstance serviceInstance = loadBalancer.choose("mango-producer"); System.out.println("服务地址:" + serviceInstance.getUri()); System.out.println("服务名称:" + serviceInstance.getServiceId()); String callServiceResult = new RestTemplate().getForObject(serviceInstance.getUri().toString() + "/hello", String.class); System.out.println(callServiceResult); return callServiceResult; } }
在上面内容中,我们是先通过LoadBalancerClient选取出对应的服务,然后使用RestTemplate进行远程调用
LoadBalancerClient就是负载均衡器,RibbonLoadBalancerClient是Ribbon默认使用的负载均衡器,采用的负载均衡策略是轮询
1、查找服务,通过loadBalancer
ServiceInstance serviceInstance = loadBalancer.choose("mango-producer")
2、调用服务,通过RestTemplate
String callServiceResult = new RestTemplate().getForObject(serviceInstance.getUri().toString() + "/hello", String.class);
这样就完成了一个简单的服务调用和负载均衡。下面我们说一下Ribbon
Ribbon负载均衡器
Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP的客户端的行为。
Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。我们也可以实现自定义负载均衡算法。
下面我们进行Ribbon配置
1、修改启动类
在启动类注入RestTemplate,并添加@LoadBalanced用于拦截请求,以使用ribbon来进行负载均衡
@EnableDiscoveryClient @SpringBootApplication public class MangoConsumerApplication { public static void main(String[] args) { SpringApplication.run(MangoConsumerApplication.class, args); } @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
2、添加服务
新建一个控制类RibbonHelloController .java,注入RestTemplate,并调用服务提供者的hello服务
@RestController public class RibbonHelloController { @Autowired private RestTemplate restTemplate;
@Bean @RequestMapping("/ribbon/call") public String call() { // 调用服务, service-producer为注册的服务名称,LoadBalancerInterceptor会拦截调用并根据服务名找到对应的服务 String callServiceResult = restTemplate.getForObject("http://mango-producer/hello", String.class); return callServiceResult; } }
配置完重启服务,访问http://localhost:8005//ribbon/call
访问返回不同的结果,说明负载均衡已生效。
修改均衡策略只需要在yml中配置对应策略即可
service-producer: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
方法二、Feign方法
Feign是一套基于Netflix Feign实现的声明式服务调用客户端,使用Feign可使得Web服务客户端的写入更加方便。
它具有可插拔注释支持,包括Feign注解和JAX-RS注解、Feign还支持可插拔编码器和解码器、Spring Cloud增加了对Spring MVC注释的支持,并HttpMessageConverters在Spring Web中使用了默认使用的相同方式。
第一步、添加pom依赖
添加feign依赖
<!--feign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
第二步、启动类
在启动类添加@EnableFeignClients注解,开启扫描Spring cloud Feign客户端的功能。
@EnableFeignClients @EnableDiscoveryClient @SpringBootApplication public class MangoConsumerApplication { public static void main(String[] args) { SpringApplication.run(MangoConsumerApplication.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
第三步、添加Fegin接口
在类头上添加@FeignClient(name = "mango-producer")注入要调的服务名,
添加一个和调用目标一样的接口方法
@FeignClient(name = "mango-producer") public interface MangoProducerService { @RequestMapping("/hello") public String hello(); }
第四步、添加控制器
添加FeignHelloController.java
注入MangoProducerService.java
@RestController public class FeignHelloController { @Autowired private MangoProducerService mangoProducerService; @RequestMapping("/feign/call") public String call() { // 像调用本地服务一样 return mangoProducerService.hello(); } }
配置完后,重启项目,访问http://localhost:8005/feign/call
可以看到,我们也实现了负载均衡,第二种方法比较简单
转载:https://blog.csdn.net/JavaLLU/article/details/115678657