java版spring cloud微服務(wù)架構(gòu)b2b2c電子商務(wù)平臺(tái)-Feign使用及源碼深度解析

SpringCloud Feign基于Netflix Feign實(shí)現(xiàn)隧期,整合SpringCloud Ribbon和SpringCloud Hystrix

我們?cè)谑褂梦⒎?wù)框架的時(shí)候刽严,一般都會(huì)在項(xiàng)目中同時(shí)使用Ribbon和Hystrix,所以可以考慮直接使用Feign來整合

1.Feign的使用

我們現(xiàn)在需要?jiǎng)?chuàng)建一個(gè)服務(wù)消費(fèi)者應(yīng)用勾邦,消費(fèi)服務(wù)提供者的服務(wù)

1)引入maven依賴

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

2)創(chuàng)建接口FeignService,提供消費(fèi)服務(wù)

@FeignClient(name="part-1-sms-interface", fallback=FeginFallbackService.class)
public interface FeignService {
 
    @RequestMapping("/sms/test")
    String test();
}
 
// 服務(wù)降級(jí)類
@Component
public class FeginFallbackService {
 
    public String test(){
        return "fallback error";
    }
}

注意:

@FeignClient注解中的name為服務(wù)提供者所在應(yīng)用的spring.application.name,fallback所對(duì)應(yīng)的類為服務(wù)調(diào)用異常時(shí)服務(wù)降級(jí)的類

@RequestMapping("/sms/test")為服務(wù)提供者應(yīng)用中的方法路徑

@FeignClient還有一個(gè)關(guān)鍵的configuration參數(shù)舞痰,可以讓用戶自定義配置bean

注解默認(rèn)的配置bean所在類為FeignClientsConfiguration弃酌,用戶可參考其中的bean實(shí)現(xiàn)來自定義

3)創(chuàng)建Controller

@RestController
@RequestMapping("/feign")
public class FeignController {
 
    @Autowired
    private FeignService feignService;
    
    @GetMapping(value="/test")
    public String test(){
        return feignService.test();
    }
}

4)測(cè)試驗(yàn)證
調(diào)用/feign/test方法氨菇,可以看到其調(diào)用了服務(wù)提供者part-1-sms-interface提供的/sms/test方法,驗(yàn)證成功

2.寫在源碼分析之前
經(jīng)過上面的關(guān)于Feign的使用分析妓湘,可以看到使用的時(shí)候還是非常簡(jiǎn)單的查蓉,只需要兩個(gè)簡(jiǎn)單的注解就實(shí)現(xiàn)了Ribbon+Hystrix的功能。
那具體是如何實(shí)現(xiàn)的呢榜贴?
關(guān)鍵的一步就是如何把對(duì)接口的請(qǐng)求映射為對(duì)真正服務(wù)的請(qǐng)求(也就是一個(gè)HTTP請(qǐng)求)豌研,同時(shí)還要加上Hystrix的功能。
映射為HTTP請(qǐng)求唬党、Hystrix的功能都是每個(gè)服務(wù)共同的需求鹃共,所以肯定是被抽象出來的。而且我們沒有對(duì)接口有任何具體實(shí)現(xiàn)驶拱,那么應(yīng)該是用了反射的功能了霜浴,實(shí)現(xiàn)具體接口的實(shí)現(xiàn)類,并注冊(cè)到Spring容器中蓝纲,這樣才能在Controller層中使用@Autowired

3.分析注解@EnableFeignClients

通過上面的使用過程分析阴孟,@EnableFeignClients和@FeignClient兩個(gè)注解就實(shí)現(xiàn)了Feign的功能晌纫,那我們重點(diǎn)分析下@EnableFeignClients注解

1)@EnableFeignClients

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)// 重點(diǎn)在這里,注入FeignClientsRegistrar類
public @interface EnableFeignClients {}

2)FeignClientsRegistrar.java分析

通過其類結(jié)構(gòu)可知永丝,其實(shí)現(xiàn)了ImportBeanDefinitionRegistrar接口锹漱,那么在registerBeanDefinitions()中就會(huì)注冊(cè)一些bean到Spring中

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
        ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware{
        
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
        // 1.針對(duì)那些在@EnableFeignClients中添加了defaultConfiguration屬性的進(jìn)行操作
        // 將這些類定義的bean添加到容器中
        registerDefaultConfiguration(metadata, registry);
        
        // 2.注冊(cè)那些添加了@FeignClient的類或接口
        // 重點(diǎn)就在這里
        registerFeignClients(metadata, registry);
    }
}

3)registerFeignClients(metadata, registry)方法分析

public void registerFeignClients(AnnotationMetadata metadata,
                                 BeanDefinitionRegistry registry) {
    ClassPathScanningCandidateComponentProvider scanner = getScanner();
    scanner.setResourceLoader(this.resourceLoader);
 
    // 1.以下代碼的主要功能是掃描包下的所有帶有@FeignClient注解的類
    Set<String> basePackages;
 
    Map<String, Object> attrs = metadata
        .getAnnotationAttributes(EnableFeignClients.class.getName());
    // @FeignClient注解過濾器
    AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
        FeignClient.class);
    final Class<?>[] clients = attrs == null ? null
        : (Class<?>[]) attrs.get("clients");
    if (clients == null || clients.length == 0) {
        // 在這里獲取帶有@FeignClient注解的類,放在basePackages中
        scanner.addIncludeFilter(annotationTypeFilter);
        basePackages = getBasePackages(metadata);
    }
    else {
        final Set<String> clientClasses = new HashSet<>();
        basePackages = new HashSet<>();
        for (Class<?> clazz : clients) {
            basePackages.add(ClassUtils.getPackageName(clazz));
            clientClasses.add(clazz.getCanonicalName());
        }
        AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
            @Override
            protected boolean match(ClassMetadata metadata) {
                String cleaned = metadata.getClassName().replaceAll("\\$", ".");
                return clientClasses.contains(cleaned);
            }
        };
        scanner.addIncludeFilter(
            new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
    }
 
    // 2.針對(duì)所有帶有@FeignClient注解的類或接口分別封裝
    // 注冊(cè)其Configuration類(如果有的話)
    // 并將類或接口本身注入到Spring中
    for (String basePackage : basePackages) {
        Set<BeanDefinition> candidateComponents = scanner
            .findCandidateComponents(basePackage);
        for (BeanDefinition candidateComponent : candidateComponents) {
            if (candidateComponent instanceof AnnotatedBeanDefinition) {
                // verify annotated class is an interface
                AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                Assert.isTrue(annotationMetadata.isInterface(),
                              "@FeignClient can only be specified on an interface");
 
                Map<String, Object> attributes = annotationMetadata
                    .getAnnotationAttributes(
                    FeignClient.class.getCanonicalName());
 
                String name = getClientName(attributes);
                // 2.1 注冊(cè)其Configuration類(如果有的話)
                // 本例中使用的是默認(rèn)的Configuration,就不再分析該段代碼
                registerClientConfiguration(registry, name,
                                            attributes.get("configuration"));
 
                // 2.2 并將類或接口本身注入到Spring中
                registerFeignClient(registry, annotationMetadata, attributes);
            }
        }
    }
}

總結(jié):從3)的分析可知,@EnableFeignClients注解的主要功能就是把帶有@FeignClient注解的類或接口注冊(cè)到Spring中
關(guān)于具體是如何注冊(cè)的碉钠、請(qǐng)求時(shí)如何轉(zhuǎn)換的累贤,暫時(shí)還不清楚,但是代碼結(jié)構(gòu)已經(jīng)很清晰了。接下來我們繼續(xù)分析registerFeignClient()方法
電子商務(wù)社交平臺(tái)源碼請(qǐng)加企鵝求求:三五三六二四七二五九

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子辩诞,更是在濱河造成了極大的恐慌,老刑警劉巖纺涤,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件译暂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡撩炊,警方通過查閱死者的電腦和手機(jī)外永,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拧咳,“玉大人伯顶,你說我怎么就攤上這事÷嫦ィ” “怎么了祭衩?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)阅签。 經(jīng)常有香客問我掐暮,道長(zhǎng),這世上最難降的妖魔是什么政钟? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任路克,我火速辦了婚禮,結(jié)果婚禮上养交,老公的妹妹穿的比我還像新娘精算。我一直安慰自己,他們只是感情好碎连,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布灰羽。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谦趣。 梳的紋絲不亂的頭發(fā)上疲吸,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天座每,我揣著相機(jī)與錄音前鹅,去河邊找鬼。 笑死峭梳,一個(gè)胖子當(dāng)著我的面吹牛舰绘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播葱椭,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捂寿,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了孵运?” 一聲冷哼從身側(cè)響起秦陋,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎治笨,沒想到半個(gè)月后驳概,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旷赖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年顺又,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片等孵。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稚照,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出俯萌,到底是詐尸還是另有隱情果录,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布咐熙,位于F島的核電站雕憔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏糖声。R本人自食惡果不足惜斤彼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蘸泻。 院中可真熱鬧琉苇,春花似錦、人聲如沸悦施。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抡诞。三九已至穷蛹,卻和暖如春土陪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肴熏。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國打工鬼雀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蛙吏。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓源哩,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親鸦做。 傳聞我的和親對(duì)象是個(gè)殘疾皇子励烦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • ?通過前面兩章對(duì)Spring Cloud Ribbon和Spring Cloud Hystrix的介紹,我們已經(jīng)掌...
    Chandler_玨瑜閱讀 213,055評(píng)論 15 140
  • 5月2日我稱之為過渡的一日泼诱,上午在束河古鎮(zhèn)休閑半日后坛掠,下午要去大理了。 早上在民宿房頂拍了無數(shù)張玉龍雪山的照片治筒,還...
    子弈媽媽閱讀 256評(píng)論 0 3
  • 文/居里社 01 真的不要低估你身邊的每一個(gè)人,你也并不知道究竟哪片云彩會(huì)下雨句灌。 最近結(jié)交了一些新朋友夷陋,一些很時(shí)尚...
    居里葉閱讀 571評(píng)論 0 7
  • 大學(xué)四年,我收獲了許多胰锌,學(xué)會(huì)了許多骗绕,感謝大家的幫助和教導(dǎo)。 經(jīng)歷了很多事资昧,也從中得到很多反思酬土。 大一,滿滿的收獲格带,...
    桌子和1106閱讀 125評(píng)論 0 0
  • 內(nèi)鏈接:select * from t_student t inner join t_hours s on id ...
    無敵帥帥頭閱讀 304評(píng)論 0 0