06 RestTemplate负载均衡

  本例将模仿拦截器机制,实现一个简单的ReatTemplate,以便更清楚地展示@LoadBalanced以及RestTemplate的原理。

[email protected]注解概述

  RestTemplate本是spring-web项目中的一个REST客户端,它遵循REST的设计原则,提供简单的API让我们去调用HTTP服务。RestTemplate本身并不具备负载均衡的功能,该类也与SpringCloud没有关系,但是为什么加入@LoadBalanced注解后,一个RestTemplate实例就具有了负载均衡的功能呢?实际上这要得益于RestTemplate的拦截器的功能。在Spring Cloud中,使用@LoadBalanced注解修饰后的RestTemplate,在Spring容器启动时,会为这些被修饰过的RestTemplate添加拦截器,拦截器中使用了LoadBalancerClient来处理请求,LoadBalancerClient本来就是Spring封装的负载均衡客户端,通过这样的间接处理,值得RestTemplate拥有了负载均衡的功能。

2.项目创建及测试

  新建一个项目,项目的目录结构如图所示

  

  2.1编写自定义注解以及拦截器

  模仿@LoadBalanced注解,编写一个自定义注解,代码清单如下

package com.triheart.resttemplatetest;

import org.springframework.beans.factory.annotation.Qualifier;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 阿遠
 * Date: 2018/8/27
 * Time: 21:56
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MyLoadBalanced {
}

  MyLoadBalanced 注解中使用了@Qualifier限定注解,接下来编写自定义的拦截器,代码清单如下

package com.triheart.resttemplatetest;

import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

import java.io.IOException;

/**
 * 自定义拦截器
 * @author 阿遠
 * Date: 2018/8/27
 * Time: 21:57
 */
public class MyInterceptor implements ClientHttpRequestInterceptor {
    public ClientHttpResponse intercept(HttpRequest request, byte[] body,
                                        ClientHttpRequestExecution execution) throws IOException {
        System.out.println("=============  这是自定义拦截器实现");
        System.out.println("               原来的URI:" + request.getURI());
        // 换成新的请求对象(更换URI)
        MyHttpRequest newRequest = new MyHttpRequest(request);
        System.out.println("               拦截后新的URI:" + newRequest.getURI());
        return execution.execute(newRequest, body);
    }
}

  在自定义拦截器MyInterceptor中,实现了intercept方法,该方法会将原来的HttpRequest对象转换为我们自定义的MyHttpRequest,MyHttpRequest是一个自定义的请求类,实现请求的代码清单如下

package com.triheart.resttemplatetest;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;

import java.net.URI;

/**
 * 自定义请求类
 * @author 阿遠
 * Date: 2018/8/27
 * Time: 21:59
 */
public class MyHttpRequest implements HttpRequest {

    private HttpRequest sourceRequest;

    public MyHttpRequest(HttpRequest sourceRequest) {
        this.sourceRequest = sourceRequest;
    }

    public HttpHeaders getHeaders() {
        return sourceRequest.getHeaders();
    }

    public HttpMethod getMethod() {
        return sourceRequest.getMethod();
    }

    /**
     * 将URI转换
     */
    public URI getURI() {
        try {
            URI newUri = new URI("http://localhost:8080/hello");
            return newUri;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sourceRequest.getURI();
    }

}

  在MyHttpRequest类中,会将原来请求的URI进行改写,只要使用了这个对象,所有的请求都会被转发到http://localhost:8080/hello这个地址。Spring Cloud在对RestTemplate进行拦截的时候也做了同样的事情,只不过并没有像这里一样固定了URI,而是对“源请求”进行了更灵活的处理。

  2.2使用自定义拦截器及注解

  编写一个Spring的配置类,在初始化的Bean中为容器中的RestTemplate实例设置自定义拦截器,自动配置类代码清单如下

package com.triheart.resttemplatetest;

import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author 阿遠
 * Date: 2018/8/27
 * Time: 22:01
 */
@Configuration
public class MyAutoConfiguration {

    @Autowired(required=false)
    @MyLoadBalanced
    private List<RestTemplate> myTemplates = Collections.emptyList();

    @Bean
    public SmartInitializingSingleton myLoadBalancedRestTemplateInitializer() {
        System.out.println("====  这个Bean将在容器初始化时创建    =====");
        return new SmartInitializingSingleton() {

            public void afterSingletonsInstantiated() {
                for(RestTemplate tpl : myTemplates) {
                    // 创建一个自定义的拦截器实例
                    MyInterceptor mi = new MyInterceptor();
                    // 获取RestTemplate原来的拦截器
                    List list = new ArrayList(tpl.getInterceptors());
                    // 添加到拦截器集合
                    list.add(mi);
                    // 将新的拦截器集合设置到RestTemplate实例
                    tpl.setInterceptors(list);
                }
            }
        };
    }
}

  在配置类中定义了RestTemplate实例的集合,并且使用了@MyLoadBalanced以及@Autowired注解进行修饰,@MyLoadBalanced中含有@Qualifier注解。简单的说就是在Spring容器中使用了@MyLoadBalanced修饰的RestTemplate实例,该实例将会被加入到配置类的RestTemplate集合中。在容器初始化时,Spring会调用myLoadBalancedRestTemplateInitializer方法来创建Bean,该Bean在初始化完成后,会遍历RestTemplate集合并为它们设置“自定义拦截器”。

  2.3在控制器中使用RestTemplate

  控制器代码清单如下

package com.triheart.resttemplatetest;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * @author 阿遠
 * Date: 2018/8/27
 * Time: 22:03
 */
@RestController
@Configuration
public class InvokerController {

    @Bean
    @MyLoadBalanced
    public RestTemplate getMyRestTemplate() {
        return new RestTemplate();
    }

    /**
     * 浏览器访问的请求
     */
    @RequestMapping(value = "/router", method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_VALUE)
    public String router() {
        RestTemplate restTpl = getMyRestTemplate();
        // 根据名称来调用服务,这个URI会被拦截器所置换
        String json = restTpl.getForObject("http://my-server/hello", String.class);
        return json;
    }

    /**
     * 最终的请求都会转到这个服务
     */
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String hello() {
        return "Hello World";
    }
}

  注意控制器中的hello方法,前面实现的拦截器会将全部的请求都转到这个服务中。控制器的RestTemplate使用了@MyLoadBalanced注解进行修饰。在控制器中router方法中,使用这个被拦截过的RestTemplate发送请求。打开浏览器,访问http://localhost:8080/router,可以看到如下界面

  可以看到,实际上是调用了hello服务。

3.总结

  本例展示了RestTemplate的原理,Spring Cloud对RestTemplate的拦截器实现更加复杂,并且在拦截器中使用LoadBalancerClient来实现请求的负载均衡功能。我们在实际环境中,并不需要实现自定义的注解以及拦截器,Spring已经帮我们提供了现成的API。

  一般情况下,Spring已经帮我们封装好了Ribbon,我们直接调用RestTemplate等API来访问服务即可实现负载均衡。

原文地址:https://www.cnblogs.com/a-yuan/p/9545344.html

时间: 2024-08-30 03:11:48

06 RestTemplate负载均衡的相关文章

RestTemplate 负载均衡原理

RestTemplate负载均衡原理 RestTemplate为什么具有负载均衡的功能? 在使用了@LoadBalanced后,Spring容器在启动的时候会为被修饰过的RestTemplate添加拦截器,拦截器里会使用LoadBalanced相关的负载均衡接口来处理请求,通过这样一个间接的处理,会使原来的RestTemplate变得不是原来的RestTemplate了,就变的更NB了,因此具备了负载均衡的功能.那么在这章的内容中呢,笔者将带大家实现一个很简单的LoadBalanced注解,为R

003客户端负载均衡Ribbon &amp; 短路器Hystrix

1.POM配置 和普通Spring Boot工程相比,仅仅添加了Eureka.Ribbon.Hystrix.Spring Boot Starter Actuator依赖和Spring Cloud依赖管理 <dependencies> <!--添加Eureka Server依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-

为何一个@LoadBalanced注解就能让RestTemplate拥有负载均衡的能力?【享学Spring Cloud】

每篇一句 你应该思考:为什么往往完成比完美更重要? 前言 在Spring Cloud微服务应用体系中,远程调用都应负载均衡.我们在使用RestTemplate作为远程调用客户端的时候,开启负载均衡极其简单:一个@LoadBalanced注解就搞定了. 相信大家大都使用过Ribbon做Client端的负载均衡,也许你有和我一样的感受:Ribbon虽强大但不是特别的好用.我研究了一番,其实根源还是我们对它内部的原理不够了解,导致对一些现象无法给出合理解释,同时也影响了我们对它的定制和扩展.本文就针对

Nginx学习笔记06负载均衡之(一)负载均衡介绍

1.1.1. 负载均衡的介绍 Nginx中使用upstream配置块,可以方便的配置出一个基于反向代理的负载均衡解决方案. 在upstream中可以包含多个server配置项,每个server配置项指定一个主机地址和端口号,代表一个主机(上游服务器). 在proxy_pass配置反向代理时,可以不指定最终的主机地址,而是只指定upstream配置块指定的引用名称.在本文中,upstream配置了一个包含三个主机地址的负载均衡主机集群. 配置内容: http { include       mim

nginx+keepalived的高可用负载均衡集群构建

实验架构图: 实验环境 Nginx和Keepalived原理介绍 参考博客:http://467754239.blog.51cto.com/4878013/1541421 1.nginx Nginx进程基于于Master+Slave(worker)多进程模型,自身具有非常稳定的子进程管理功能.在Master进程分配模式下,Master进程永远不进行业务处理,只是进行任务分发, 从而达到Master进程的存活高可靠性,Slave(worker)进程所有的业务信号都 由主进程发出,Slave(wor

基于HAProxy+Keepalived高可用负载均衡web服务的搭建

一 原理简介 1.HAProxyHAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费.快速并且可靠的一种解决方案.HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理.HAProxy运行在时下的硬件上,完全可以支持数以万计的并发连接.并且它的运行模式使得它可以很简单安全的整合进当前的架构中, 同时可以保护web服务器不被暴露到网络上.2.KeepalivedKeepalived 是一个基于VRRP协议来实现的LVS服务高

小白日记13:kali渗透测试之服务扫描(三)-SMTB扫描、防火墙识别、负载均衡识别、WAF识别

SMTP扫描 SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式.SMTP协议属于TCP/IP协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地.通过SMTP协议所指定的服务器,就可以把E-mail寄到收信人的服务器上了,整个过程只要几分钟.SMTP服务器则是遵循SMTP协议的发送邮件服务器,用来发送或中转发出的电子邮件. SMB扫描针对机器去发现其漏洞,SMTP扫描为主动发现目

Nginx反向代理、负载均衡、页面缓存、URL重写及读写分离详解

大纲 一.前言 二.环境准备 三.安装与配置Nginx 四.Nginx之反向代理 五.Nginx之负载均衡 六.Nginx之页面缓存 七.Nginx之URL重写 八.Nginx之读写分离 注,操作系统为 CentOS 6.4 x86_64 , Nginx 是版本是最新版的1.4.2,所以实验用到的软件请点击这里下载:http://yunpan.cn/QXIgqMmVmuZrm 一.前言 在前面的几篇博文中我们主要讲解了Nginx作为Web服务器知识点,主要的知识点有nginx的理论详解.ngin

基于Apache+Tomcat负载均衡的两种实现方法

Apache+Tomcat实现负载均衡的两种实现方法 如果我们将工作在不同平台的apache能够实现彼此间的高效通信,因此它需要一种底层机制来实现--叫做apr Apr的主要目的就是为了其能够让apache工作在不同的平台上,但在linux上安装apache的时候通常都是默认安装的 [[email protected] ~]#rpm -qi aprName                 :apr                                        Relocation