SpringCloud Gateway 로 딩 단언 predicates 와 필터 filter 의 소스 코드 분석

오늘 우리 의 주인공 은 게 이 트 웨 이 게 이 트 웨 이 입 니 다.이름 만 들 어도 기본 적 인 임 무 는 길 을 나 누 어 주 는 것 입 니 다.지 정 된 이름 에 따라 각 서 비 스 를 요청 합 니 다.다음은 Gateway 공식 설명 입 니 다.
4.567915.다른 블 로 거들 은 더 이상 말 하지 않 겠 습 니 다.여러분 은 홈 페이지 에 많이 가 보 세 요.공식 적 인 것 만 이 가장 정확 합 니 다.주제 로 돌아 갑 니 다.우리 의 필터 와 단언 이 어떻게 불 러 왔 는 지,그리고 어떻게 요 구 를 걸 러 냈 는 지 확인 하 세 요.
SpringBoot 자동 로 딩 에 익숙 하 다 면 코드 의 소스 코드 를 봐 야 한 다 는 것 을 알 아야 합 니 다.META-INF 에 있 는 spring.factories 를 찾 아야 합 니 다.구체 적 으로 왜 블 로 거들 은 더 이상 말 하지 않 습 니까?인터넷 에 도 자동 으로 로 딩 된 소스 코드 분석 이 많 습 니 다.오늘 은 Gateway 를 설명 하 겠 습 니 다.모든 프로젝트 의 스 리 스트로크 도끼:의존,주석 쓰기,설정 을 하 겠 습 니 다.
의존:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
설명:시작 클래스 에@EnableDiscoveryClient 를 추가 해 야 합 니 다.시작 서비스 발견
설정:

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
여러분 이 이 설정 을 보 았 을 때,왜 우 리 는 After 단언 과 PrefixPath 필 터 를 쓰 면 gateway 가 자동 으로 인식 되 는 지,그러면 우 리 는 모든 자체 테이프 의 속성 을 볼 수 있 는 곳 이 있 습 니까?물론 있 습 니 다.그리고 이 편 은 왜 gateway 가 자동 으로 인식 되 는 지 설명 하고 사용자 정의 속성 을 추가 해 야 합 니 다.원본 코드 분석 첫 번 째 단 계 를 시작 하여 자동 으로 불 러 오 는 클래스 를 찾 습 니 다.

이곳 을 보 았 을 때 첫 번 째 단 계 는 성공 적 이 었 습 니 다.나머지 는 org.spring from work.cloud.gateway.config.Gateway AutoConfiguration 이라는 관건 적 인 종 류 를 찾 았 습 니 다.우 리 는 주로 안의 두 가지 종 류 를 보 았 습 니 다.

@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)));
    }
이 두 가지 유형 설정 은 모두 가 잘 알 고 있 을 것 입 니 다.여러분 이 새로운 지식 을 손 에 넣 었 을 때 빠 른 입문 글 을 찾 아 볼 것 입 니 다.블 로 거들 은 공식 적 인 quick start 를 직접 찾 아 보 는 습관 이 있 습 니 다.여러분 은 이런 빠 른 시작 항목 을 볼 수 있 습 니 다https://spring.io/projects/spring-cloud-gateway
그래서 블 로 거들 은 RouteLocator 라 는 설정 을 직접 찾 았 습 니 다.아니 나 다 를 까 우 리 는 단언 과 필터 의 주입 을 찾 았 습 니 다.실제 적 인 방법 으로 체 내 에 매개 변수 로 들 어 갔 지만 spring 에 의 해 해석 되 었 습 니 다.공장 에 가서 직접 받 았 습 니 다.구체 적 으로 어떻게 가 져 갑 니까?우리 다시 한번 봅 시다.

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);
                            }
                            //                    
                            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;
    }
모든 매개 변 수 는 해석 이 필요 하지만 여 기 를 보면 괜 찮 은 것 같 지 않 습 니 다.계속 내 려 가면 보 입 니 다.

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 {

        ....
        //     ,          
        for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
            ....
                try {
                //                --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;
    }
분석 을 시 작 했 을 때 보 았 습 니 다.단언 과 필터 목록 을 모두 추가 해 야 합 니 다.그러면 spring 은 어떻게 불 러 옵 니까?방법 에 따라 체 내 에 들 어 오 는 유형 에 따라 단언 과 필터 공장 인 터 페 이 스 를 실현 하 는 모든 종 류 를 찾 고 인 스 턴 스 를 얻 습 니 다.우 리 는 이 공장 들 의 실현 류 를 자세히 살 펴 보면 우리 가 사용 하 는 속성 을 찾 을 수 있 습 니 다.예 를 들 어 우리 사례 의 PrefixPath 필터 와 Path 단언 등 입 니 다.

protected Map<String, Object> findAutowireCandidates(
            @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
        //       ,beanNamesForTypeIncludingAncestors  ,      bean                 ,
        String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this, requiredType, true, descriptor.isEager());
        Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
        ...
        //    ,     
        for (String candidate : candidateNames) {
            if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
                addCandidateEntry(result, candidate, descriptor, requiredType);
            }
        }
        .....
        return result;
    }


이제 우 리 는 시스템 설정 의 단언 과 필터 가 어떻게 불 러 오 는 지 알 게 되 었 습 니 다.그러면 우 리 는 또 하나의 문제 가 있 습 니 다.만약 내 가 하 나 를 사용자 정의 한다 면 어떻게 시스템 에 의 해 인식 되 는 지 알 게 되 었 습 니 다.그리고 설정 은 어떻게 하나 요?우리 가 이전에 소스 코드 를 보 았 을 때 그 는 spring 에 의 해 공장 실현 류 를 찾 아 불 러 왔 다 는 것 을 알 수 있 습 니 다.그러면 우 리 는 공장 인 터 페 이 스 를 실현 하고@Component 주 해 를 사용 하여 spring 을 불 러 오 면 되 지 않 습 니까?하지만 시스템 사용자 정의 속성 단언 이나 필터 에 공장 이름 의 접미사 가 있 는 것 을 발견 할 수 있 습 니 다.왜 일 까요?사용자 정의 클래스 가 gateway 에 불 러 오고 유효 합 니까?사실은 영향 을 줄 수 있 는데,왜 영향 을 줍 니까?우 리 는 소스 코드 를 보 는 것 이 좋 겠 다.우리 가 이전에 클래스 로 딩 을 다 보지 못 했 기 때문에 우 리 는 처음에 두 개의@bean 의 자동 로 딩 을 찾 았 습 니 다.그러면 이 두 가지 사례 화 할 때 어떤 일 을 했 는 지 우 리 는 아직 자세히 보지 못 했 습 니 다.

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;
    }
initFactory(predicates):이 코드 는 주로 공장 실현 류 를 분석 하 는 것 입 니 다.그리고 지도 에 넣 고,
gateway FilterFactories.foreach(factory->this.gateway FilterFactories.put(factory.name(),factory):단언 코드 와 거의 같 습 니 다.다른 논리 가 없 기 때문에 방법 에 봉인 되 지 않 고 자바 8 의 흐름 특성 을 직접 사용 하여 옮 겨 다 니 는 과정 을 썼 습 니 다.여러분 은 코드 가 factory.name()이라는 것 을 주의해 야 합 니 다.여기 서 방법 을 사 용 했 습 니 다.

 default String name() {
        return NameUtils.normalizeRoutePredicateName(getClass());
    }
주로 현재 클래스 의 공장 이름 을 포함 하 는 부분 을 제거 한 다음 에 남 은 문자열 을 key 값 으로 사용 하기 때문에 우 리 는 공장 이름 을 사용 하여 펜던트 를 할 수도 있 고 사용 하지 않 아 도 된다.그러나 나머지 문 자 는 당신 이 설정 한 키 워드 를 써 야 한다.그러나 블 로 거들 은 기본적으로 시스템 자체 속성 과 마찬가지 로 공장 인터페이스의 이름 으로 접 두 사 를 만 들 었 다.
자,오늘 은 이렇게 많은 것 을 설명 하 겠 습 니 다.다음 에는 gateway 가 요청 을 받 은 후에 어떻게 한 걸음 한 걸음 걸 러 냈 는 지,언제 단언 검 사 를 했 는 지 설명 하 겠 습 니 다.한 번 에 이렇게 많은 것 을 말 하지 않 고 소화 하면 된다.
스프링 클 라 우 드 게 이 트 웨 이 로 딩 단언 predicates 와 필터 filter 의 소스 코드 분석 에 관 한 글 은 여기까지 소개 되 었 습 니 다.더 많은 스프링 클 라 우 드 게 이 트 웨 이 단언 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 지원 을 바 랍 니 다!

좋은 웹페이지 즐겨찾기