1. 程式人生 > >RestTemplate 負載均衡原理

RestTemplate 負載均衡原理

cti .exe 功能 結果 新的 for wired eas .com

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,,,以上就是本章的全部內容了,一個簡單的自定義註解、自定義攔截器,你 學會了嗎!

RestTemplate 負載均衡原理