4.springcloud_eureka服务发现ribbon+resTemplate(Finchley.SR2)

这是一个从零开始的springcloud的系列教程,如果你从中间开始看,可能会看不明白.进入我的博客查看其他文章

前言

在之前课程中,我们学会创建了多工程项目,spring-cloud-learn.

搭建的项目有:

  • eureka-server:服务治理中心,为微服务提供注册和管理
  • eureka-client:在此工程学会了如何向服务端注册,如何发现其他服务.
  • eureka-client2: 一个eureka客户端工程

我们学会了如何发现其他服务.不过还不足以让我们方便的进行微服务之间的调用.SpringCloud提供两种服务调用方式,一种是ribbon+restTemplate,另一种是feign。feign是对ribbon的更高层级的封装,在学习feign之前,我们先来看ribbon+restTemplate如何实现微服务之间的调用

在开始前:

  • 启动eureka-server微服务

ribbon+restTemplate

Ribbon is a client side load balancer which gives you a lot of control over the behaviour of HTTP and TCP clients. Feign already uses Ribbon, so if you are using @FeignClient then this section also applies.

-----摘自官网

ribbon是一个负载均衡客户端,可以很好的控制http和tcp的一些行为。Feign默认集成了ribbon。

来看看代码怎么使用Ribbon+RestTemplate.

  • 第一步:eureka-client工程中引入ribbon.如果没有改工程,请点击这多Maven工程

    <?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>spring-cloud-learn</artifactId>
            <groupId>com.jack</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>eureka-client</artifactId>
    
        <dependencies>
    
            <!--
            一定要写称spring-cloud-starter-netflix-eureka-client
            如果写错成spring-cloud-netflix-eureka-client,将无法注册
            -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
    
            <!--引入ribbon-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
    
        </dependencies>
    
    </project>
    
  • 第二步:在eureka-client工程中创建RibbonConfiguration类,该类负责创建一个RestTemplate对象,@LoadBalanced会给创建RestTemplate增加请求拦截器,该拦截器可以对url进行改写,让其服务名称变为对应的服务实例的ip地址

package com.jack.eureka_client;

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 RibbonConfiguration {

    // 创建一个装有ribbon请求拦截器的restTemplate
    // @LoadBalanced会给创建RestTemplate增加请求拦截器,该拦截器会将对应的服务名称改成具体实例的域名
    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
package com.jack.eureka_client;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class HelloController {

    private RestTemplate restTemplate;

    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public Object hello(@RequestParam(value = "name", required = false) String name) {
        return restTemplate.getForObject("http://eureka-client2/hello?name=" + name, String.class);
    }
}
  • 第四步:在eureka-client2工程里也创建一个HelloController,这样就能收到eureka-client发送的http请求
 package com.jack.eureka_client2;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public Object hello(@RequestParam(value = "name", required = false) String name) {
        return "Hello " + name;
    }
}
 
  • 第五步:启动eureka-client和eureka-client2,调用http://localhost:7771/hello?name=Robbon

image.png

总结一下以上请求流程

  • 客户端发送get请求到eureka-client服务(localhost:7771)上
  • eureka-client服务收到http请求,通过restTemplate对eureka-client2服务发送http请求
  • restTemplate收到http://eureka-client2/hello?name=Robbon请求,将url改写为http://localhost:7772/hello?name=Robbon. localhost:7772是eureka-client2的ip地址
  • eureka-client2收到http请求,返回结果
  • eureka-client收到eureka-client2的结果,返回客户端

**很神奇?**只需要加入这份神奇的代码,就能完成服务之间的调用了.

@Bean
@LoadBalanced
RestTemplate restTemplate() {
    return new RestTemplate();
}

我们深入一下这部分代码做了什么.

RestTemplate是什么?它是一个spring提供的http请求类,可以十分方便的发送http请求,避免了复杂的代码,假如发送一个http://eureka-client2/hello请求,正常来说发送是失败的,因为域名是找不到的.所以我们需要在发送请求后,对请求进行拦截,将eureka-client2改写成实例实际的ip地址.想要达到这个目的可以为RestTemplate对象设置http拦截器,从而到达改写目的.

@LoadBalanced注解做的就是给RestTemplate设置http请求拦截器.打开LoadBalancerAutoConfiguration文件.

@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
	
    // 在这里将我们注册的RestTemplate放入restTemplates里面
	@LoadBalanced
	@Autowired(required = false)
	private List<RestTemplate> restTemplates = Collections.emptyList();
	
    // 通过该方法为RestTemplate进行配置,配置类型为RestTemplateCustomizer
	@Bean
	public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
			final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
		return () -> restTemplateCustomizers.ifAvailable(customizers -> {
            for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
                for (RestTemplateCustomizer customizer : customizers) {
                    customizer.customize(restTemplate);
                }
            }
        });
	}
    
    @Configuration
	@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
	static class LoadBalancerInterceptorConfig {
        // ribbon的拦截器,loadBalanceClient由RibbonAutoConfiguration文件创建
		@Bean
		public LoadBalancerInterceptor ribbonInterceptor(
				LoadBalancerClient loadBalancerClient,
				LoadBalancerRequestFactory requestFactory) {
			return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
		}
		
        // 创建RestTemplateCustomizer,为loadBalancedRestTemplateInitializerDeprecated使用
		@Bean
		@ConditionalOnMissingBean
		public RestTemplateCustomizer restTemplateCustomizer(
				final LoadBalancerInterceptor loadBalancerInterceptor) {
			return restTemplate -> {
                List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                        restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            };
		}
	}
...

可以发现LoadBalancerAutoConfiguration做了以下事情

  • 第一步: 将含有@LoadBalanced注解的RestTemplate放入restTemplates数组中

        // 在这里将我们注册的RestTemplate放入restTemplates里面
    	@LoadBalanced
    	@Autowired(required = false)
    	private List<RestTemplate> restTemplates = Collections.emptyList();
    
  • 第二步: 创建LoadBalancerInterceptor拦截器,LoadBalancerClient和LoadBalancerRequestFactory由Ribbon提供,在RibbonAutoConfiguration配置类中创建.

  • // ribbon的拦截器,loadBalanceClient由RibbonAutoConfiguration文件创建
    @Bean
    public LoadBalancerInterceptor ribbonInterceptor(
    		LoadBalancerClient loadBalancerClient,
    		LoadBalancerRequestFactory requestFactory) {
    	return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
    }
    
  • 第三步:创建RestTemplateCustomizer,该类的作用是给RestTemplate装配LoadBalancerInterceptor

  • @Bean
    @ConditionalOnMissingBean
    public RestTemplateCustomizer restTemplateCustomizer(
    	final LoadBalancerInterceptor loadBalancerInterceptor) {
    	return restTemplate -> {
       		List<ClientHttpRequestInterceptor> list = new ArrayList<(restTemplate.getInterceptors());
            list.add(loadBalancerInterceptor);
            restTemplate.setInterceptors(list);
        };
    }
    
  • 第四步: 对restTemplates中的元素进行装配LoadBalancerInterceptor拦截器,通过customizer.customize(restTemplate)代码来装配,最后达到改写http请求的目的.这里的RestTemplateCustomizer就是第三步创建的

  • // 通过该方法为RestTemplate进行配置,配置类型为RestTemplateCustomizer
    	@Bean
    	public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
    			final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
    		return () -> restTemplateCustomizers.ifAvailable(customizers -> {
                for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
                    for (RestTemplateCustomizer customizer : customizers) {
                        customizer.customize(restTemplate);
                    }
                }
            });
    	}
    

到此为RestTemplate设置Ribbon提供的LoadBalancerInterceptor拦截器的过程完毕


Cool! Ribbon+RestTemplate的调用方式我们已经深入了解,之后我们来讲解更加人性化调用的Feign

项目说明 该项目是一个典型的由Spring Cloud管理的微服务项目,主要包括如下模块 micro-service-cloud─────────────────顶层项目 ├──cloud-service-core───────────────基础核心模块 ├──cloud-service-tools──────────────全局通用工具类 ├──cloud-service-reids──────────────Redis二次封装 ├──cloud-eureka-server──────────────服务注册中心[8761] ├──cloud-turbine-server─────────────断路器聚合监控[8769] ├──cloud-zipkin-server──────────────链路追踪监控[9411] ├──cloud-zuul-server────────────────第一代服务网关(Zuul)[8080] ├──cloud-gateway-server─────────────第二代服务网关(Gateway)[8080] ├──cloud-modules-app────────────────App微服务模块 ├───────modules-app-user────────────App用户服务模块[努力更新中] ├───────modules-app-doctor──────────App医生服务模块[努力更新中] ├──cloud-modules-service────────────微服务通用服务模块 ├───────mongodb-file-service────────Mongodb文件服务模块[11010] ├───────redis-delay-service─────────延迟消费服务模块[11020] ├──cloud-modules-web────────────────Web微服务模块 ├───────modules-web-security────────Web医生服务模块[12010] ├───────modules-web-user────────────Web用户服务模块[12020] ├──cloud-modules-wechat─────────────Wechat微服务模块 ├───────modules-wechat-user─────────Wechat用户服务模块[努力更新中] └───────modules-wechat-doctor───────Wechat医生服务模块[努力更新中] 修改日志 修改日志 修改人 修改日期 版本计划 V1.0 刘岗强 2019-01-07 项目初始化 V1.1 刘岗强 待定 新增自动问答 项目介绍 基于Spring Cloud Finchley SR2 Spring Boot 2.0.7的最新版本。 核心基础项目内实现类自定义的权限注解,配合RBAC权限模型+拦截器即可实现权限的控制,具体的参考项目中的实现。同时也封装了一些顶层类和结果集等。 注册中心实现高可用配置,详情见eureka的one、two、three三个配置文件,摘要如下。 ------------------------------------------配置节点一---------------------------------------------- server: port: 8761 spring: application: name: cloud-eureka-server eureka: instance: hostname: cloud.server.one prefer-ip-address: true instance-id: ${spring.cloud.client.ip-address}:${server.port}:${spring.application.name} client: healthcheck: enabled: true register-with-eureka: false fetch-registry: false service-url: defaultZone: http://cloud.server.two:8762/eureka/,http://cloud.server.three:8763/eureka/ ------------------------------------------配置节点二----------------------------------------------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值