最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringCloud Gateway加載斷言predicates與過(guò)濾器filters的源碼分析

 更新時(shí)間:2021年05月10日 14:31:12   作者:努力的小雨  
這篇文章主要介紹了SpringCloud Gateway加載斷言predicates與過(guò)濾器filters的詳細(xì)過(guò)程,本文通過(guò)源碼給大家解析的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

  我們今天的主角是Gateway網(wǎng)關(guān),一聽(tīng)名字就知道它基本的任務(wù)就是去分發(fā)路由。根據(jù)不同的指定名稱去請(qǐng)求各個(gè)服務(wù),下面是Gateway官方的解釋:

https://spring.io/projects/spring-cloud-gateway,其他的博主就不多說(shuō)了,大家多去官網(wǎng)看看,只有官方的才是最正確的,回歸主題,我們的過(guò)濾器與斷言如何加載進(jìn)來(lái)的,并且是如何進(jìn)行對(duì)請(qǐng)求進(jìn)行過(guò)濾的。

  大家如果對(duì)SpringBoot自動(dòng)加載的熟悉的話,一定知道要看一個(gè)代碼的源碼,要找到META-INF下的spring.factories,具體為啥的博主就不多說(shuō)了,網(wǎng)上也有很多講解自動(dòng)加載的源碼分析,今天就講解Gateway,所有項(xiàng)目三板斧:加依賴、寫(xiě)注解、弄配置

  依賴:

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

  注解:?jiǎn)?dòng)類上需要添加@EnableDiscoveryClient,啟動(dòng)服務(wù)發(fā)現(xiàn)

  配置:

spring:
  cloud:
    gateway:
      routes:
       - id: after-route #id必須要唯一
         uri: lb://product-center
         predicates:
          - After=2030-12-16T15:53:22.999+08:00[Asia/Shanghai]
        filters:
          - PrefixPath=/product-api

  大家看到這個(gè)配置的時(shí)候,為什么我們寫(xiě)After斷言與PrefixPath過(guò)濾器,gateway就會(huì)自動(dòng)識(shí)別呢,那我們有沒(méi)有那一個(gè)地方可以看到所有的自帶的屬性呢?當(dāng)然有,而且我們本篇就主要講解為什么gateway會(huì)自動(dòng)識(shí)別,并且我們要自己實(shí)現(xiàn)并且添加自定義屬性。開(kāi)始源碼解析第一步,找到自動(dòng)加載的類一探究竟;

  看到這里的時(shí)候,第一步就成功了,剩下的就是找到org.springframework.cloud.gateway.config.GatewayAutoConfiguration這個(gè)關(guān)鍵類,我們主要看看里面的兩個(gè)類

@Bean
    public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
                                                   List<GatewayFilterFactory> GatewayFilters,
                                                   List<RoutePredicateFactory> predicates,
                                                   RouteDefinitionLocator routeDefinitionLocator) {
        return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties);
    }

    @Bean
    @Primary
    //TODO: property to disable composite?
    public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
        return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
    }

  這倆個(gè)類配置,大家可能非常熟悉,大家上手一個(gè)新知識(shí)點(diǎn)的時(shí)候,肯定會(huì)找一些快速入門(mén)的文章看看,博主還是習(xí)慣直接找官方的quick start來(lái)看,大家可以看看這些快速上手項(xiàng)目:https://spring.io/guides/gs/gateway/

  所以博主直接就找到了RouteLocator這個(gè)類配置,果不其然,我們找到了斷言與過(guò)濾器的注入,雖然實(shí)在方法體內(nèi)作為參數(shù)傳入,但是會(huì)被spring解析到,直接去工廠里拿到,具體怎么拿呢?我們?cè)賮?lái)看看:

public BeanWrapper instantiateUsingFactoryMethod(
            String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

        .....

            for (Method candidate : candidates) {
                Class<?>[] paramTypes = candidate.getParameterTypes();

                if (paramTypes.length >= minNrOfArgs) {
                    ArgumentsHolder argsHolder;

                    if (explicitArgs != null) {
                        // Explicit arguments given -> arguments length must match exactly.
                        if (paramTypes.length != explicitArgs.length) {
                            continue;
                        }
                        argsHolder = new ArgumentsHolder(explicitArgs);
                    }
                    else {
                        // Resolved constructor arguments: type conversion and/or autowiring necessary.
                        try {
                            String[] paramNames = null;
                            ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                            if (pnd != null) {
                                paramNames = pnd.getParameterNames(candidate);
                            }
                            //主要就是會(huì)進(jìn)入到這里去解析每一個(gè)參數(shù)類型
                            argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
                                    paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
                        }
                        catch (UnsatisfiedDependencyException ex) {
                            if (logger.isTraceEnabled()) {
                                logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
                            }
                            // Swallow and try next overloaded factory method.
                            if (causes == null) {
                                causes = new LinkedList<>();
                            }
                            causes.add(ex);
                            continue;
                        }
                    }

                    int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                            argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
                    // Choose this factory method if it represents the closest match.
                    if (typeDiffWeight < minTypeDiffWeight) {
                        factoryMethodToUse = candidate;
                        argsHolderToUse = argsHolder;
                        argsToUse = argsHolder.arguments;
                        minTypeDiffWeight = typeDiffWeight;
                        ambiguousFactoryMethods = null;
                    }
                    // Find out about ambiguity: In case of the same type difference weight
                    // for methods with the same number of parameters, collect such candidates
                    // and eventually raise an ambiguity exception.
                    // However, only perform that check in non-lenient constructor resolution mode,
                    // and explicitly ignore overridden methods (with the same parameter signature).
                    else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
                            !mbd.isLenientConstructorResolution() &&
                            paramTypes.length == factoryMethodToUse.getParameterCount() &&
                            !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
                        if (ambiguousFactoryMethods == null) {
                            ambiguousFactoryMethods = new LinkedHashSet<>();
                            ambiguousFactoryMethods.add(factoryMethodToUse);
                        }
                        ambiguousFactoryMethods.add(candidate);
                    }
                }
            }

            .....
        return bw;
    }

  每一個(gè)參數(shù)都需要解析,但是看這里不像沒(méi)關(guān)系,繼續(xù)往下走:就會(huì)看到

private ArgumentsHolder createArgumentArray(
            String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
            BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
            boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {

        ....
        //這下就是了,每個(gè)參數(shù)都被進(jìn)行解析
        for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
            ....
                try {
                //我們的參數(shù)就是在這里被進(jìn)行解析的--resolveAutowiredArgument
                    Object autowiredArgument = resolveAutowiredArgument(
                            methodParam, beanName, autowiredBeanNames, converter, fallback);
                    args.rawArguments[paramIndex] = autowiredArgument;
                    args.arguments[paramIndex] = autowiredArgument;
                    args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
                    args.resolveNecessary = true;
                }
                catch (BeansException ex) {
                    throw new UnsatisfiedDependencyException(
                            mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
                }
            }
        }
        //其他不重要的,直接忽略掉
        ...
        return args;
    }

  開(kāi)始解析的時(shí)看到了,我們需要把斷言和過(guò)濾器列表都加在進(jìn)來(lái),那spring是如何加載的呢?是根據(jù)方法體內(nèi)傳入的類型找到所有實(shí)現(xiàn)了斷言和過(guò)濾器工廠接口的類并且進(jìn)行獲取實(shí)例,我們仔細(xì)這些工廠的實(shí)現(xiàn)類,就會(huì)找到我們的使用的一些屬性,比如我們例子中的PrefixPath過(guò)濾器和Path斷言;

protected Map<String, Object> findAutowireCandidates(
            @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
        //主要的就是這個(gè),beanNamesForTypeIncludingAncestors方法,該方法就是從bean工廠中獲取所有當(dāng)前類的實(shí)現(xiàn)實(shí)例名稱,
        String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this, requiredType, true, descriptor.isEager());
        Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
        ...
        //遍歷名稱,進(jìn)行實(shí)例化
        for (String candidate : candidateNames) {
            if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
                addCandidateEntry(result, candidate, descriptor, requiredType);
            }
        }
        .....
        return result;
    }

  這下我們知道了,系統(tǒng)配置的斷言和過(guò)濾器是如何被加載 的了,那我們還有一個(gè)問(wèn)題,如果我自定義一個(gè),如何被系統(tǒng)識(shí)別呢?并且怎么進(jìn)行配置呢?不難發(fā)現(xiàn)我們之前看源碼時(shí),他是被spring通過(guò)找工廠實(shí)現(xiàn)類找到并且加載進(jìn)來(lái)的,那我們自己實(shí)現(xiàn)工廠接口并且使用@Component注解,讓spring加載進(jìn)來(lái)不就的了嗎?但是你會(huì)發(fā)現(xiàn)系統(tǒng)自定義的屬性斷言或者過(guò)濾器都有工廠名字的后綴,這是為什么呢?影響我們自定義 的類被加載到gateway中且生效嗎?事實(shí)是會(huì)影響,那為什么影響呢?我們還是看源碼。因?yàn)槲覀冎暗念惣虞d還沒(méi)有看完,我們最開(kāi)始的時(shí)候就找到了兩個(gè)@bean 的自動(dòng)加載,那這兩個(gè)類實(shí)例化的時(shí)候都做了哪些工作,我們還沒(méi)有細(xì)看;

public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
                                       List<RoutePredicateFactory> predicates,
                                       List<GatewayFilterFactory> gatewayFilterFactories,
                                       GatewayProperties gatewayProperties) {
        this.routeDefinitionLocator = routeDefinitionLocator;
        initFactories(predicates);
        gatewayFilterFactories.forEach(factory -> this.gatewayFilterFactories.put(factory.name(), factory));
        this.gatewayProperties = gatewayProperties;
    }

  initFactories(predicates):這段代碼主要是進(jìn)行解析斷言工廠實(shí)現(xiàn)類;并且放入一個(gè)Map中,

  gatewayFilterFactories.forEach(factory -> this.gatewayFilterFactories.put(factory.name(), factory)):跟斷言的代碼幾乎一樣,因?yàn)闆](méi)有其他多余的邏輯,所以沒(méi)有封裝到方法中,直接使用java8 的流特性,寫(xiě)完了遍歷的過(guò)程。大家要注意一段代碼就是factory.name(),這里使用了一個(gè)方法;

 default String name() {
        return NameUtils.normalizeRoutePredicateName(getClass());
    }

  主要就是把當(dāng)前類包含工廠名字的部分去掉了,然后用剩下的字符串當(dāng)key值,所以我們可以使用工廠名字做后墜,也可以不用,但是剩下的字符則是你要寫(xiě)進(jìn)配置的關(guān)鍵字,不過(guò)博主基本都是按照系統(tǒng)自帶屬性一樣,用的是工廠接口的名字做的后綴。

   好了,今天就講解這么多,下次在講解gateway接到請(qǐng)求后,是如何進(jìn)行一步一步過(guò)濾的,何時(shí)進(jìn)行斷言校驗(yàn)的。一次不講這么多,消化了就好。

到此這篇關(guān)于SpringCloud Gateway加載斷言predicates與過(guò)濾器filters的源碼分析的文章就介紹到這了,更多相關(guān)SpringCloud Gateway斷言內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot中的@Inherited注解詳解

    SpringBoot中的@Inherited注解詳解

    這篇文章主要介紹了SpringBoot中的@Inherited注解詳解,@Inherited是一個(gè)標(biāo)識(shí),用來(lái)修飾注解,如果一個(gè)類用上了@Inherited修飾的注解,那么其子類也會(huì)繼承這個(gè)注解,需要的朋友可以參考下
    2023-08-08
  • Java class文件格式之方法_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java class文件格式之方法_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了Java class文件格式之方法的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • java鏈表數(shù)據(jù)結(jié)構(gòu)LinkedList插入刪除元素時(shí)間復(fù)雜度面試精講

    java鏈表數(shù)據(jù)結(jié)構(gòu)LinkedList插入刪除元素時(shí)間復(fù)雜度面試精講

    這篇文章主要為大家介紹了java LinkedList插入和刪除元素的時(shí)間復(fù)雜度面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • 一文讓你了解透徹Java中的IO模型

    一文讓你了解透徹Java中的IO模型

    本文只是說(shuō)明了IO模型,讓你了解IO模型是什么,怎么區(qū)分IO模型,以及分析了Java中的三種IO模型,本文是純理論知識(shí),看完之后會(huì)讓你對(duì)IO有更加深刻的理解,感興趣的同學(xué)可以參考一下
    2023-05-05
  • SpringBoot整合RabbitMQ及原理

    SpringBoot整合RabbitMQ及原理

    這篇文章主要介紹了SpringBoot整合RabbitMQ及其原理分析,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • Java8中Stream的一些神操作

    Java8中Stream的一些神操作

    Stream是Java8中處理集合的關(guān)鍵抽象概念,它可以指定你希望對(duì)集合進(jìn)行的操作,可以執(zhí)行非常復(fù)雜的查找、過(guò)濾和映射數(shù)據(jù)等操作,這篇文章主要給大家介紹了Java8中Stream的一些神操作,需要的朋友可以參考下
    2021-11-11
  • Java中關(guān)于ThreadLocal的隱式引用詳解

    Java中關(guān)于ThreadLocal的隱式引用詳解

    這篇文章主要介紹了Java中關(guān)于ThreadLocal的隱式引用,從線程的角度看,每個(gè)線程都保持一個(gè)對(duì)其線程局部變量副本的隱式引用,只要線程是活動(dòng)的,ThreadLocal實(shí)例就是可訪問(wèn)的,下面我們來(lái)具體看看
    2024-03-03
  • Java多線程同步工具類CountDownLatch詳解

    Java多線程同步工具類CountDownLatch詳解

    這篇文章主要介紹了Java多線程同步工具類CountDownLatch詳解,CountDownLatch是一個(gè)多線程同步工具類,在多線程環(huán)境中它允許多個(gè)線程處于等待狀態(tài),直到前面的線程執(zhí)行結(jié)束
    2022-06-06
  • Java阻塞隊(duì)列必看類:BlockingQueue快速了解大體框架和實(shí)現(xiàn)思路

    Java阻塞隊(duì)列必看類:BlockingQueue快速了解大體框架和實(shí)現(xiàn)思路

    這篇文章主要介紹了Java阻塞隊(duì)列必看類:BlockingQueue快速了解大體框架和實(shí)現(xiàn)思路,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • mybatis動(dòng)態(tài)插入list傳入List參數(shù)的實(shí)例代碼

    mybatis動(dòng)態(tài)插入list傳入List參數(shù)的實(shí)例代碼

    本文通過(guò)實(shí)例代碼給大家介紹了mybatis動(dòng)態(tài)插入list,Mybatis 傳入List參數(shù)的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2018-04-04

最新評(píng)論

金溪县| 嵊泗县| 青浦区| 新建县| 灵山县| 班玛县| 贵南县| 娄烦县| 和硕县| 广宗县| 延安市| 石林| 武义县| 全椒县| 景谷| 西畴县| 铜梁县| 安溪县| 康平县| 西和县| 茂名市| 云林县| 绵阳市| 桦南县| 精河县| 依安县| 加查县| 璧山县| 无锡市| 凭祥市| 乌拉特中旗| 大安市| 宁阳县| 广南县| 花莲县| 开鲁县| 黄梅县| 普格县| 天水市| 明溪县| 河西区|