RestTemplate負載均衡原理java
RestTemplate爲何具備負載均衡的功能?web
在使用了@LoadBalanced後,Spring容器在啓動的時候會爲被修飾過的RestTemplate添加攔截器,攔截器裏會使用LoadBalanced相關的負載均衡接口來處理請求,經過這樣一個間接的處理,會使原來的RestTemplate變得不是原來的RestTemplate了,就變的更NB了,所以具有了負載均衡的功能。
那麼在這章的內容中呢,筆者將帶你們實現一個很簡單的LoadBalanced註解,爲RestTemplate添加攔截器的這麼一個過程,至於如何在攔截器中實現負載均衡的功能,這個還需探索。。。(若是各位道友知道如何實現,請告知一二,先感謝了)spring
引入web依賴:pom.xmlapp
<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.javaide
@RestController
@Configuration public class MyController { @Bean // 將getRestTemplate修飾爲Bean,交給spring管理 @MyLoadBalanced // 這裏使用剛剛自定義的註解 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
建立配置類:Config.javaspring-boot
@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 說明,咱們的配置生效了。。。。。。 ui
下面咱們建立一個自定義的攔截器:MyInterceptor.java 該攔截器須要實現 ClientHttpRequestInterceptor 接口this
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,,,以上就是本章的所有內容了,一個簡單的自定義註解、自定義攔截器,你 學會了嗎!