深入講解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閱讀 227,250評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,923評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,041評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,475評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,253評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,801評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,023評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,530評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,494評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,639評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,890評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,289評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,552評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,242評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,626評論 2 370

推薦閱讀更多精彩內容