RestTemplate 负载均衡原理

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,,,以上就是本章的所有内容了,一个简单的自定义注解、自定义拦截器,你 学会了吗!

相关文章
相关标签/搜索