深入讲解SpringCloud Alibaba 微服务调用,还不懂微服务的一定得看看!

概述

在微服务架构中,最常见的场景就是微服务间的相互调用。微服务间的相互调用方式主要有RestTemplate、Feign 、和OpenFeign 。

RestTemplate

  • RestTemplate是远程调用Http的工具,是对java底层http的封装,使用RestTemplata用户可以不再关注底层的连接建立;
  • RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率
  • RestTemplata不仅支持RESTful规范,还可以定义返回值对象类型。
  • RestTemplate 支持本地客户端负载均衡,是对Ribbon的封装。
    个人整理了一些资料,有需要的朋友可以直接点击领取。

Java基础知识大全

百本Java架构师核心书籍

对标阿里P8的Java学习路线和资料

2021年最新java面试题合集

Feign

  • Feign是Spring Cloud组件中的一个声明式的轻量级RESTful的HTTP服务客户端 ;
  • Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务;
  • Feign的使用方式是:使用Feign的注解定义接口,然后调用这个接口,就可以调用服务注册中心的服务 ,用起來就好像调用本地方法一样,完全感觉不到是调用的远程方法;
  • Feign本身不支持SpringMVC的注解,它有一套自己的注解;

OpenFeign

  • OpenFeign是Spring Cloud 在Feign的基础上支持SpringMVC的注解,如@RequesMapping等等。
  • OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

创建一个微服务消费者子模块

在 alibaba-server 子工程下创建一个微服务消费者子模块 springboot 项目alibaba-server-consumer,最终文件目录如下:


在微服务消费者子模块 alibaba-server-consumer 的pom文件中添加依赖:

<dependencies>
    <!-- web 应用 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 必须包含spring-boot-starter-actuator包,不然启动会报错。 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- 整合nacos配置中心所需jar包 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        <version>2.2.1.RELEASE</version>
    </dependency>
    <!-- 整合nacos服务注册 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2.2.1.RELEASE</version>
    </dependency>
    <!-- sentinel -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
        <!-- lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.2</version>
        <optional>true</optional>
    </dependency>
</dependencies>

将消费者微服务 alibaba-server-consumer 注册到 nacos上

其中配置如下:

调用提供者微服务

使用 RestTemplate

提供者 alibaba-server-helloworld 微服务的 controller 如下:

@RestController
@RequestMapping("/lhj")
public class HelloWorlsController {
    @RequestMapping("/hello")
    public String hello(){
        return "hello world!";
    }
}

端口号是8006,上下文是hello

添加一个 RestTemplate 的配置类

@Component
public class RestTemplateConfig {
    @Bean
    @LoadBalanced  // 负载均衡,使得loadBalancerClient可以通过应用名获取对应的url
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

启动类

@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

controller 中调用远程服务

注意:使用 @Autowired 注入 restTemplate 只能通过第三种方式来调用服务,@Autowired 注入的 restTemplate 因为不能直接访问地址,只能通过注册的服务应用名来访问。

@RestController

public class ConsumerController {
    @Autowired
    private LoadBalancerClient loadBalancerClient; // 注入 LoadBalancerClient
    @Autowired
    private RestTemplate restTemplate; // 注入 RestTemplate 

    @GetMapping("/diaoyong")
    public  ResponseEntity<String> msg(){
    
        //1.第一种方式(直接使用restTemplate,url写死)
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.getForEntity("http://localhost:8006/hello/lhj/hello", String.class);
        
        //2.弟二种方式(利用loadBalancerClient通过应用名获取url,然后再使用直接使用restTemplate)
        ServiceInstance serviceInstance = loadBalancerClient.choose("alibaba-server-helloworld");
        String url = String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort())+"/hello/lhj/hello";
        RestTemplate restTemplate = new RestTemplate();
        String response = restTemplate.getForObject(url, String.class);

        //3.弟二种方式(利用@LoadBalanced,可在restTemplate里使用应用名字)
        RestTemplate restTemplate = new RestTemplate();
        String response = restTemplate.getForObject("http://PRODUCT/msg", String.class);
        log.info("response={}",response);
        return response;
        
        System.out.println(response.getStatusCode());
        System.out.println(response.getBody());
        System.out.println(response.getHeaders());
        return response;
    }
}

RestTemplate 调用的三种方式

第一种方式:直接使用被调用服务的访问地址,url写死(必须new一个restTemplate,不能使用注入的)

RestTemplate restTemplate = new RestTemplate();  
String response = restTemplate.getForObject("http://localhost:8006/hello/lhj/hello",String.class)
return response;

第二种方式:利用loadBalancerClient通过应用名获取url,然后再使用restTemplate(必须new一个restTemplate,不能使用注入的)

ServiceInstance serviceInstance = loadBalancerClient.choose("alibaba-server-helloworld"); 
String url = String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort())+"/hello/lhj/hello";
RestTemplate restTemplate = new RestTemplate(); 
String response = restTemplate.getForObject(url, String.class); 
return response;

第三种方式:利用配置类中的@LoadBalanced,可在restTemplate里直接使用服务应用名字(可以使用注入的restTemplate)

String response = restTemplate.getForObject("http://alibaba-server-helloworld/hello/lhj/hello", String.class); 
return response;

注意:用 @Autowired 注入 restTemplate 的不能直接访问地址,只能通过注册的服务应用名来访问

restTemplate 的返回值类型

返回值类型一共有两类,getForEntity 和 getForObject,每一类有三个重载方法。


① getForEntity
既然 RestTemplate 发送的是 HTTP 请求,那么在响应的数据中必然也有响应头,如果开发者需要获取响应头的话,那么就需要使用 getForEntity 来发送 HTTP 请求,此时返回的对象是一个 ResponseEntity 的实例。这个实例中包含了响应数据以及响应头。
② getForObject
getForObject 方法的参数和 getForEntity 一样,getForObject 的返回值就是服务提供者返回的数据,使用 getForObject 无法获取到响应头。

浏览器访问

使用 Feign

消费者 alibaba-server-consumer 微服务的文件结构


提供者 alibaba-server-hellocloud 微服务的 controller 如下:

@RestController
@RequestMapping("zj")
public class HelloCloudController {
    @RequestMapping("hello")
    public String hello(String name){
        return "hello cloud,"+name;
    }
}

端口号是8007,上下文是hello

Feign 原理

● 启动时,程序会进行包扫描,扫描所有包下所有@FeignClient注解的类,并将这些类注入到spring的IOC容器中。当定义的Feign中的接口被调用时,通过JDK的动态代理来生成RequestTemplate。
● RequestTemplate中包含请求的所有信息,如请求参数,请求URL等。
● RequestTemplate声场Request,然后将Request交给client处理,这个client默认是JDK的HTTPUrlConnection,也可以是OKhttp、Apache的HTTPClient等。
● 最后client封装成LoadBaLanceClient,结合ribbon负载均衡地发起调用。

(1) pom 文件中添加 Feign 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

(2)启动类上添加注解 @EnableFeignClients

在服务的启动类上添加注解 @EnableFeignClients 以开启 Spring Cloud Feign 的支持。

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

(3)声明服务接口

@Service @FeignClient("alibaba-server-hellocloud") // 服务提供者的名称spring.application.name public interface FeignService {
    @RequestMapping(value="/hello/zj/hello") // 服务提供者方法的访问地址
    String getService(@RequestParam(value="name") String name); 
    } 

① 接口中的方法可以不用加public,方法名任意取。
② 在该接口中,使用 @FeignClient 注解指定要调用的服务名来绑定服务,然后再使用Spring MVC的注解 @RequestMapping 来绑定具体该服务提供的REST接口。
③@RequestParam 注解必须要加上 value 属性。

(4)controller 中调用服务接口

@RestController
public class ConsumerController {

    @Autowired
    private FeignService feignService;

    @GetMapping("/diaoyong")
    public  String msg(){
        return feignService.getService("lhj");
    }
}

(5)浏览器访问


(6)Feign 开启日志

如果我们想追踪Feign客户端发送的数据,就要启用 Feign 的日志。

Feign 在构建被 @FeignClient 注解修饰的服务客户端时,会为每一个客户端都创建一个feign.Logger实例,这样就可以利用该日志对象的DEBUG模式来帮助分析Feign的请求细节。

开启方法:

① 配置文件开启:在application.yml 中使用 logging.level.{Feign客户端对应的接口的全限定名} 的参数配置格式来开启指定客户端日志

logging:   
    level:
        {Feign客户端对应的接口的全限定名}: debug 

② java bean 的方式开启:@EnableFeignClients 注解上有个 defaultConfiguration 属性,可以指定默认Feign Client的一些配置。

@EnableFeignClients(defaultConfiguration =DefaultFeignConfiguration.class) 
@SpringBootApplication 
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    } 
 } 

@Configuration 
public class DefaultFeignConfiguration {
    @Bean
    public Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
     }
 }

使用 Feign 的注意事项

① 在 Feign 的服务声明接口使用对象作为参数时必须用 @RequestBody注解,让其以json方式接收

    void insert(@RequestBody User user);  

② 在 Feign 的服务声明接口中使用 @RequestParam 一定要加上value属性

    void delete(@RequestParam("accountCode") String accountCode); 

③ 在 Feign 的服务声明接口中使用 @PathVariable 一定要跟上面一样加上value属性

     ResultData<AccountDTO> getByCode(@PathVariable(value = "accountCode") String accountCode);  

④ 在消费者模块启动类上使用@EnableFeignClients注解后指明Feign接口所在的包路径

     @EnableFeignClients(basePackages = "com.javadaily.feign.*")

最后

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容