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,,,以上就是本章的全部内容了,一个简单的自定义注解、自定义拦截器,你 学会了吗!
上一篇: 用asp生成wml
下一篇: 027.1 反射技术 Class
推荐阅读