zoukankan      html  css  js  c++  java
  • RestTemplate 负载均衡原理

    RestTemplate负载均衡原理

    RestTemplate为什么具有负载均衡的功能?

        在使用了@LoadBalanced后,Spring容器在启动的时候会为被修饰过的RestTemplate添加拦截器,拦截器里会使用LoadBalanced相关的负载均衡接口来处理请求,通过这样一个间接的处理,会使原来的RestTemplate变得不是原来的RestTemplate了,就变的更NB了,因此具备了负载均衡的功能。
    那么在这章的内容中呢,笔者将带大家实现一个很简单的LoadBalanced注解,为RestTemplate添加拦截器的这么一个过程,至于如何在拦截器中实现负载均衡的功能,这个还需探索。。。(如果各位道友知道如何实现,请告知一二,先感谢了)

    引入web依赖:pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.0.3.RELEASE</version>
        </dependency>
    </dependencies>

    自定义注解:MyLoadBalanced.java

    /**
     * 修饰:域、参数、方法
     */
    @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
    /**
     * 作用是定义被它所注解的注解保留多久,一共有三种策略,定义在RetentionPolicy枚举中
     * 1. SOURCE:被编译器忽略
     * 2. CLASS:注解将会被保留在Class文件中,但在运行时并不会被VM保留。这是默认行为,所有没有用Retention注解的注解,都会采用这种策略
     * 3. RUNTIME:保留至运行时。所以我们可以通过反射去获取注解信息。
     */
    @Retention(RetentionPolicy.RUNTIME)
    /**
     * 限定注解
     */
    @Qualifier
    public @interface MyLoadBalanced {
    
    }

    创建Controller:MyController.java

    @RestController
    @Configuration
    public class MyController { @Bean // 将getRestTemplate修饰为Bean,交给spring管理 @MyLoadBalanced // 这里使用刚刚自定义的注解 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }

    创建配置类:Config.java

    @Configuration
    public class Config {
        
        @Autowired(required = false)// 非必须的,将那些被@MyLoadBalanced注解修饰过的对象,自动装配到tpls集合中
        @MyLoadBalanced
        private List<RestTemplate> tpls = Collections.emptyList();
        
        // 在spring容器启动之后,需要对每一个RestTemplate都要设置一个拦截器,拦截器里面会实现负载均衡的功能
        @Bean
        public SmartInitializingSingleton lbInitializing(){
            return new SmartInitializingSingleton() {
                @Override
                public void afterSingletonsInstantiated() {
                    System.out.println("RestTemplate集合大小:"+tpls.size());
                }
            };
        }
    
    }

    下面我们创建一个启动类,看一看到底有没有自动装配成功:Application.java

    @SpringBootApplication
    public class Application {
        
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
        
    }

    如图,RestTemplate集合大小:1  说明,我们的配置生效了。。。。。。 

    下面我们创建一个自定义的拦截器:MyInterceptor.java  该拦截器需要实现 ClientHttpRequestInterceptor 接口

    public class MyInterceptor implements ClientHttpRequestInterceptor {
    
        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            System.out.println("==================== 进入自定义拦截器");
            return null;
        }
    
    }

    现在自定义拦截器有了,那么我们就去修改一下配置类,让程序启动后,循环向每个被@MyLoadBalanced修饰过的RestTemplate添加拦截器,修改 Config.java 如下:

    @Bean
    public SmartInitializingSingleton lbInitializing(){
        return new SmartInitializingSingleton() {
            @Override
            public void afterSingletonsInstantiated() {
                for(RestTemplate rtl : tpls){
                    // 为了防止覆盖默认拦截器,将默认拦截器取出
                    List<ClientHttpRequestInterceptor> interceptors = rtl.getInterceptors();
                    // 将自定义的拦截器加入到默认拦截器中
                    interceptors.add(new MyInterceptor());
                    // 给RestTemplate设置拦截器
                    rtl.setInterceptors(interceptors);
                }
            }
        };
    }

     拦截器是用来拦截请求的,我们还需要在 MyController.java 中定义一个接口,用于调用测试,修改 MyController.java 如下:

    @RequestMapping(value="/getPolice", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
    public String getPolice(){
        RestTemplate rtl = getRestTemplate();
        String result = rtl.getForObject("http://springCloud-ribbon-police/getPolice", String.class);
        return result;
    }

     下面,我们访问下接口,试试拦截器有没有配置成功,如图:

    拦截器中输出了内容,那么就证明拦截器配置成功了。报错是因为在拦截器中返回了null,那我们现在就来解决这个问题。

    在拦截器中暂时不实现负载均衡的功能,我们以跳转为例,给大家讲解。。。将旧请求进行修改,并返回一个新的请求。这样的话,就需要我们返回一个新的request对象。

    创建 NewRequest.java 并实现 HttpRequest 接口:NewRequest.java

    public class NewRequest implements HttpRequest{
        
        private HttpRequest sourceRequest;// 原请求request
    
        public NewRequest(HttpRequest sourceRequest){
            this.sourceRequest = sourceRequest;
        }
        
        @Override
        public HttpHeaders getHeaders() {
            return sourceRequest.getHeaders();
        }
    
        @Override
        public String getMethodValue() {
            return sourceRequest.getMethodValue();
        }
    
        @Override
        public URI getURI() {
            try {
                // 将拦截到的URI,修改为新的URI
                URI uri = new URI("http://localhost:9090/getPoliceById/123");
                return uri;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return sourceRequest.getURI();
        }
    
    }

     下面修改一下我们自定义的拦截器:MyInterceptor.java

    public class MyInterceptor implements ClientHttpRequestInterceptor {
    
        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            System.out.println("==================== 这是自定义拦截器");
            System.out.println("==================== 旧的URL:"+request.getURI());
            NewRequest newRequest = new NewRequest(request);
            System.out.println("==================== 新的URL:"+newRequest.getURI());
            return execution.execute(newRequest, body);
        }
    
    }

     我们再运行程序,得到如下结果:

    再看一下页面返回的结果,完美实现拦截跳转:

     OK,,,以上就是本章的全部内容了,一个简单的自定义注解、自定义拦截器,你 学会了吗!

  • 相关阅读:
    排序算法的实现(冒泡,选择,插入 O(N*N)--理解方法实现
    HTTPS工作原理和TCP握手机制
    HTTP协议学习
    IP头,TCP头,UDP头,MAC帧头定义
    单链表的实现
    数字图像处理------中值滤波
    对于矩阵的理解-- by 孟岩老师
    java编码问题总结
    jsp数据库连接大全和数据库操作封装到Javabean
    构建一个高可扩展性javabean和jsp连接数据库操作
  • 原文地址:https://www.cnblogs.com/lpxdbk/p/9828837.html
Copyright © 2011-2022 走看看