3 @SpringBootApplication
4 public class ServiceCallerApp
5 {
6 public static void main( String[] args )
7 { SpringApplication.run(ServiceCallerApp.class, args); }
8 }
第四步,通过Feign封装客户端调用的细节,外部模块是通过Feign来调用客户端的,这部分的代码是在Controller.java里。
1 省略必要的package和import的代码
2 //通过注解指定待调用的服务名
3 @FeignClient(“sayHelloServiceProvider”)
4 //在这个接口里,通过Feign封装客户端的调用细节
5 interface FeignClientTool
6 {
7 @RequestMapping(method = RequestMethod.GET, value = “/hello/{name}”)
8 String sayHelloInClient(@PathVariable(“name”) String name);
9 }
10 //Controller是控制器类
11 @RestController
12 public class Controller {
13 @Autowired
14 private FeignClientTool tool;
15 //在callHello方法是,是通过Feign来调用服务
16 @RequestMapping(value = “/callHello”, method = RequestMethod.GET)
17 public String callHello(){
18 return tool.sayHelloInClient(“Peter”);
19 }
20 }
在Controller.java这个文件,其实定义了一个接口和一个类。在第5行的FeignClientTool接口里,我们封装了Feign的调用业务,具体来说,是通过第3行的FeignClient注解,指定了该接口会调用“sayHelloServiceProvider“服务提供者的服务,而通过第8行的,则指定了调用该服务提供者中sayHelloInClient的方法。
而在第12行的Controller类里,先是在第14行里,通过Autowired注解,引入了FeignClientTool类型的tool类,随后在第17行的callHello方法里,是通过tool类的sayHelloInClient方法,调用了服务提供者的相关方法。
也就是说,在callHello方法里,我们并没有再通过RestTemplate,以输入地址和服务名的方式调用服务,而是通过封装在FeignClientTool(Feign接口)里的方法调用服务。
完成上述代码后,我们可以通过如下的步骤查看运行效果。
第一步,启动FeignDemo-Server项目,随后输入http://localhost:8888/,能看到注册到Eureka服务器里的诸多服务。
第二步,启动FeignDemo-ServiceProvider项目,随后输入http://localhost:1111/hello/Peter,能调用其中的服务,此时,能在浏览里看到“hello Peter”的输出。
第三步,启动FeignDemo-ServiceCaller项目,随后输入http://localhost:8080/callHello,同样能在浏览里看到“hello Peter”的输出。请注意,这里的调用是通过Feign完成的。
2 通过比较其它调用方式,了解Feign的封装性
在之前的代码里,我们是通过如下形式,通过RestTemplate对象来调用服务。
1 RestTemplate template = getRestTemplate();
2 String retVal = template.getForEntity(“http://sayHello/hello/Eureka”, String.class).getBody();
在第2行的调用中,我们需要指定url以及返回类型等信息。
之前我们还见过基于RestClient对象的调用方式,关键代码如下。
1 RestClient client = (RestClient)ClientFactory.getNamedClient(“RibbonDemo”);
2 HttpRequest request = HttpRequest.newBuilder().uri(new URI(“/hello”)).build();
3 HttpResponse response = client.executeWithLoadBalancer(request);
其中是在第1行指定发起调用的RestClient类型的对象,在第2行里指定待调用的目标地址,随后在第3行发起调用。
这两种调用方式有着如下的共同点:调用时,需要详细地知道各种调用参数,比如服务提供者的url,如果有需要通过Ribbon实现负载均衡等机制,也需要在调用时一并指定。
但事实上,这些调用方式的底层细节,应该向服务使用者屏蔽,比如在调用时,无需关注目标url等信息。这就好比某位老板要秘书去订飞机票,作为服务使用者的老板只应当关心调用的结果,比如买到的飞机票是几点开的,该去哪个航站楼登机,至于调用服务的底层细节,比如该到哪个订票网站去买,服务使用者无需知道。
说得更专业些,这叫“解耦合”,即降低服务调动者和服务提供者之间的耦合度,这样的好处是,一旦服务提供者改变了实现细节(没改变服务调用接口),那么服务调用者部分的代码无需改动。
我们再来回顾下通过Feign调用服务的方式。
1 private FeignClientTool tool; //定义Feign类
2 tool.sayHelloInClient(“Peter”); //直接调用
第2行是调用服务,但其中,我们看不到任何服务提供者的细节,因为这些都在第1行引用的FeignClientTool类里封装掉了。也就是说,通过基于Feign的调用方式,开发者能真正地做到“面向业务”,而无需过多地关注发起调用的细节。
3 通过注解输出调用日志
在开发和调试阶段,我们希望能看到日志,从而能定位和排查问题。这里,我们将讲述在Feign里输出日志的方法,以便让大家能在通过Feign调用服务时,看到具体的服务信息。
这里我们将改写FeignDemo-ServiceCaller项目。
改动点1:在application.yml文件里,增加如下的代码,以开启Feign客户端的DEBUG日志模式,请注意,这里需要指定完成的路径,就像第3行那样。
1 logging:
2 level:
3 com.controller.FeignClientTool: DEBUG
改动点2:在这个项目的启动类ServiceCallerApp.java里,增加定义日志级别的代码,在第7行的feignLoggerLevel方法里,我们通过第8行的代码,指定了Feign日志级别是FULL。
1 //省略必要的pacakge和import代码
2 @EnableFeignClients
3 @EnableDiscoveryClient
4 @SpringBootApplication
5 public class ServiceCallerApp{
6 @Bean //定义日志级别是FULL
7 Level feignLoggerLevel() {
8 return Level.FULL;
9 }
10 //启动类
11 public static void main( String[] args ) {
12 SpringApplication.run(ServiceCallerApp.class, args);
13 }
14 }
完成后,依次运行Eureka服务器、服务提供者和服务调用者的启动类,随后在浏览器里输入http://localhost:8080/callHello,即能在控制台里看到DEBUG级别的日志,下面给出了部分输出。
1 2018-06-17 12:18:27.296 DEBUG 208 — [rviceProvider-2] com.controller.FeignClientTool : [FeignClientTool#sayHelloInClient] —> GET http://sayHelloServiceProvider/hello/Peter?name=Peter HTTP/1.1
2 2018-06-17 12:18:27.296 DEBUG 208 — [rviceProvider-2] com.controller.FeignClientTool : [FeignClientTool#sayHelloInClient] —> END HTTP (0-byte body)
从第1行的输出里,我们能看到以GET的方式向FeignClientTool类的sayHelloInClient方法发起调用,从第2行的输出里,能看到调用结束。
在上文里,我们用的是FULL级别的日志,此外,还有NONE、BASIC和HEADERS这三种,在下表里,我们将详细讲述各级别日志的输出情况。
日志输出级别 | 描述 |
NONE | 不输出任何日志 |
BASIC | 只输出请求的方法,请求的URL和相应的状态码,以及执行的时间 |
HEADERS | 除了会输出BASIC级别的日志外,还会记录请求和响应的头信息 |
FULL | 输出所有的和请求和响应相关的日志信息 |
一般情况下,在调试阶段,可以把日志级别设置成FULL,等上线后,可以把级别调整为BASIC,因为在生产环境上,过多的日志反而会降低排查和定位问题的效率。
4 压缩请求和返回,以提升访问效率
在网络传输过程中,如果我们能降低传输流量,那么即可提升处理请求的效率。尤其地,在一些日常访问量比较高的网络应用中,如果能降低处理请求(Request)和发送返回信息(Response)的时间,那么就能提升本站的吞吐量。
在Feign里,我们一般能通过如下的配置,来压缩请求和响应。
第一,可以通过在application.yml里增加如下的配置,从而压缩请求和返回信息。
1 feign:
2 compression:
3 request:
4 enabled: true
5 feign:
6 compression:
7 response:
8 enabled: true
其中,前4行是压缩请求,而后4行是压缩返回。
第二,可以通过如下的代码,设置哪类请求(或返回)将被压缩,这里我们在第4行里,指定了两类格式的请求将被压缩。
1 feign:
2 compression:
3 request:
4 mime-types: text/xml,application/xml
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
h2-1715061739823)]
[外链图片转存中…(img-4H107UBr-1715061739824)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!