@FeignClient 주입 에서 이상 을 찾 을 수 없습니다.어떻게 해결 해 야 합 니까?

머리말
Springcloud 의 서비스 간 호출 은 Feign 을 통 해 호출 됩 니 다.호출 자 서비스 에서 저 희 는@FeignClient 주 해 를 가 진 인터페이스 류 를 정의 해 야 합 니 다.또한 시작 클래스 에@Enable FeignClient 주 해 를 추가 합 니 다.
프로그램 이 시 작 될 때@EnableFeignClient 주해 가 있 는 지 확인 합 니 다.이 주해 가 있 으 면 패키지 스 캔 을 열 고@FeignClient 주해 가 있 는 인 터 페 이 스 를 스 캔 합 니 다.
여기 서 이전에 겪 었 던 문제 하 나 를 결합 하여 여러분 과 함께@EnableFeignClients 시작 과정 을 배 웁 니 다.
문제 설명
이전에 간단 한 demo 를 만 들 때,시작 한 후에 항상 오 류 를 보고 합 니 다.
Field client1Feign in com.aiqinhai.client2.controller.Testrequired a bean of type
'com.aiqinhai.client2.feignclient.Client1Feign' that could not be found.
Action:
Consider defining a bean of type 'com.aiqinhai.client2.feignclient.Client1Feign' in your configuration.
Process finished with exit code 1
한 차례 조사 한 결과,시작 에 있 는@EnableFeignClient 주 해 를 발 견 했 고,basePackages 패키지 스 캔 경 로 를 지정 하지 않 았 습 니 다.
또한 Client 1 Feign 인 터 페 이 스 는 시작 클래스 와 같은 디 렉 터 리 에 있 지 않 기 때문에 시작 할 때 상기 오 류 를 보고 합 니 다.
나중에@Enable FeignClient 에서 스 캔 패키지 경 로 를 지정 하면 해 결 됩 니 다.

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.aiqinhai.client2.feignclient"})
public class Client2Application {
    public static void main(String[] args) {
        SpringApplication.run(Client2Application.class, args);
    }
}
문 제 는 확실히 해결 되 었 지만,우 리 는 서비스 가 시 작 될 때@EnableFeignClient 가 어떤 일 을 했 는 지 알 아야 합 니 다.
@EnableFeignClient
이 주해 의 작용 을 똑똑히 알 고 싶다 면 가장 좋 은 방법 은 주해 의 원본 코드 를 보 는 것 이다.눌 러 서 보 여요.

/**
 *     @FeignClient     
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
 // basePackages
 String[] value() default {};
        //   package.
 String[] basePackages() default {};
 //feigin client    ,     FeignClientsConfiguration  
 Class<?>[] defaultConfiguration() default {};
 //@FeignClient     ,        ,     。
 Class<?>[] clients() default {};
}
이 를 통 해 알 수 있 듯 이 주석 에서 import 는 FeignClient 레지스터 클래스 입 니 다.들 어가 보 니 패키지 스 캔 의 논 리 는 FeignClient 레지스터 에서 이 루어 진 것 입 니 다.모든'class 파일'을 스 캔 하여@FeignClient 에 표 시 된 인 터 페 이 스 를 걸 러 낸 다음 Bean DefinitionBuilder 를 통 해 FeignClient Factory Bean 대상 을 생 성하 여 IOC 용기 에 주입 합 니 다.
구체 적 인 코드 는 다음 과 같다.

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
		ResourceLoaderAware, EnvironmentAware {
	//       
	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		//      bean ioc
		registerDefaultConfiguration(metadata, registry);
		//  @FeignClients     bean,        
		registerFeignClients(metadata, registry);
	}
	private void registerDefaultConfiguration(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		//  @EnableFeignClients    
		Map<String, Object> defaultAttrs = metadata
				.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
		if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
			String name;
			if (metadata.hasEnclosingClass()) {
				name = "default." + metadata.getEnclosingClassName();
			}
			else {
				name = "default." + metadata.getClassName();
			}
			//  @EnableFeignClients defaultConfiguration      bean ioc
			registerClientConfiguration(registry, name,
					defaultAttrs.get("defaultConfiguration"));		}
	}
	public void registerFeignClients(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		//spring      
		ClassPathScanningCandidateComponentProvider scanner = getScanner();
		scanner.setResourceLoader(this.resourceLoader);
        //     
		Set<String> basePackages;
        //@EnableFeignClients    
		Map<String, Object> attrs = metadata
				.getAnnotationAttributes(EnableFeignClients.class.getName());
		//@FeignClient     ,   @FeignClient       
		AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
				FeignClient.class);
		//  @EnableFeignClient   clients
		final Class<?>[] clients = attrs == null ? null
				: (Class<?>[]) attrs.get("clients");
		//  @EnableFeignClient    clients,      ,      ,  clients
		if (clients == null || clients.length == 0) {
			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)));
		}
		for (String basePackage : basePackages) {
		    //        .class     @FeignClient     
			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();
					//@FeignClient          ,      。
					Assert.isTrue(annotationMetadata.isInterface(),
							"@FeignClient can only be specified on an interface");
                        //  FeignClient    
					Map<String, Object> attributes = annotationMetadata
							.getAnnotationAttributes(
									FeignClient.class.getCanonicalName());
                        //    
					String name = getClientName(attributes);
					//  configuration    bean
					registerClientConfiguration(registry, name,
							attributes.get("configuration"));
					//  FeignClient bean,    ioc
					registerFeignClient(registry, annotationMetadata, attributes);
				}
			}
		}
	}
 
    //  bean,   IOC  
	private void registerFeignClient(BeanDefinitionRegistry registry,
			AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
		// feignclient   
		String className = annotationMetadata.getClassName();
		BeanDefinitionBuilder definition = BeanDefinitionBuilder
				.genericBeanDefinition(FeignClientFactoryBean.class);
		validate(attributes);
		definition.addPropertyValue("url", getUrl(attributes));
		definition.addPropertyValue("path", getPath(attributes));
		String name = getName(attributes);
		definition.addPropertyValue("name", name);
		definition.addPropertyValue("type", className);
		definition.addPropertyValue("decode404", attributes.get("decode404"));
		definition.addPropertyValue("fallback", attributes.get("fallback"));
		definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
		definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); 
		String alias = name + "FeignClient";
		AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); 
		boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null
		beanDefinition.setPrimary(primary);
		String qualifier = getQualifier(attributes);
		if (StringUtils.hasText(qualifier)) {
			alias = qualifier;
		}
		BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
				new String[] { alias });
		//   ioc
		BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
	}
}
@FeignClient 클래스,클래스 를 찾 을 수 없 음 주입
원인:
@FeignClinet 과@EnableFeignClient 는 같은 가방 이 아 닙 니 다.
springboot 과 springcloud 버 전이 일치 하지 않 아서 그런 가 봐 요.
이상 은 개인 적 인 경험 이 므 로 여러분 에 게 참고 가 되 기 를 바 랍 니 다.여러분 들 도 저 희 를 많이 응원 해 주시 기 바 랍 니 다.

좋은 웹페이지 즐겨찾기