Spring Cloud 소스 코드 분석: 1부
소스 코드를 읽는 친구들을 비웃지 마세요. 요즘 인터뷰는 8부작 에세이에 불과하고 프로젝트 질문, 소스 코드 및 질문에 관한 것이 더 많습니다. 바퀴를 만드는 것 외에는 선택의 여지가 없습니다. 그렇지 않으면 매우 피곤하고 지루할 것입니다!
개인적으로 소스 코드를 읽기 위해서는 먼저 사용할 수 있어야 한다고 생각합니다. 일단 익숙해지면 다른 사람들이 어떻게 구현하는지 짐작할 수 있습니다. 관련 공식 문서가 있으면 공식 문서를 읽어보세요.
그러나 많은 공식 문서가 부실하게 작성되어 한동안 읽다가 혼란스러워지는 점이 안타깝습니다.
최근에 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">openfeign 소스 코드 당시 소스 코드에서 다음과 같은 주요 주석을 발견했습니다. @가져오기
. openfeign
源码的时候,发现在源码中有个关键注解:@Import
。
项目启动类:
/** * @author tianwc 公众号:java后端技术全栈、面试专栏 * @version 1.0.0 * @date 2023年07月07日 16:47 * 在线刷题 1200+题和1000+篇干货文章:<a href="http://woaijava.cc/">博客地址</a> */ @EnableFeignClients(basePackages = {"com.tian.feign"}) @SpringBootApplication() public class MqApplication { public static void main(String[] args) { SpringApplication.run(MqApplication.class, args); } }
然后,就是我们的feignclient
接口:
/** * @author tianwc 公众号:java后端技术全栈、面试专栏 * @version 1.0.0 * @date 2023年07月07日 16:47 * 在线刷题 1200+题和1000+篇干货文章:<a href="http://woaijava.cc/">博客地址</a> */ @FeignClient(contextId = "userFeignClient", value = "charge-user-service") public interface UserFeignClient { /** * 邀请成功增加收益 * * @param invitedDto 邀请增加收益 * @return 邀请成功 */ @PostMapping("/user/invited/register") CommonResult<Boolean> invitedRegister(@RequestBody InvitedDto invitedDto); }
使用案例:
/** * @author tianwc 公众号:java后端技术全栈、面试专栏 * @version 1.0.0 * @date 2023年07月07日 16:47 * 在线刷题 1200+题和1000+篇干货文章:<a href="http://woaijava.cc/">博客地址</a> */ @RestController @RequestMapping("/user") public class UserController { @Resource UserFeignClient userFeignClient; @PostMapping("/invited") public CommonResult invitedRegister(){ //省略不想搞的代码 return userFeignClient.invitedRegister(invitedDto); } }
从上面的代码中,我们可以看出openfeign
关键代码有:
@EnableFeignClients(basePackages = {"com.tian.feign"})
@FeignClient(contextId = "userFeignClient", value = "charge-user-service")
프로젝트 시작 클래스: 🎜
userFeignClient.invitedRegister(invitedDto);
🎜그런 다음/** * @author tianwc 公众号:java后端技术全栈、面试专栏 * @version 1.0.0 * @date 2023年07月07日 16:47 * 在线刷题 1200+题和1000+篇干货文章:<a href="http://woaijava.cc/">博客地址</a> */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients { String[] value() default {}; String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<?>[] defaultConfiguration() default {}; Class<?>[] clients() default {}; }로그인 후 복사로그인 후 복사feignclient
인터페이스: 🎜🎜사용 사례: 🎜@Import(FeignClientsRegistrar.class)로그인 후 복사로그인 후 복사🎜위 코드에서/** * @author tianwc 公众号:java后端技术全栈、面试专栏 * @version 1.0.0 * @date 2023年07月07日 16:47 * 在线刷题 1200+题和1000+篇干货文章:<a href="http://woaijava.cc/">博客地址</a> */ @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { registerDefaultConfiguration(metadata, registry); registerFeignClients(metadata, registry); }로그인 후 복사로그인 후 복사openfeign
키 코드는 다음과 같습니다: 🎜<코드 스타일="글꼴 크기: 14px;패딩: 2px 4px;국경 반경: 4px;마진-오른쪽: 2px;마진-왼쪽: 2px;배경-색상: rgba( 27 , 31, 35, 0.05);글꼴 계열: "Operator Mono", Consolas, Monaco, Menlo, monospace;단어 나누기: break-all;색상: rgb(239, 112, 96);">@EnableFeignClients( basePackages = {"com.tian.feign"})🎜
@FeignClient(contextId = "userFeignClient", value = " 요금-사용자-서비스")
🎜<코드 스타일 ="글꼴 크기: 14px; 패딩: 2px 4px; 테두리 반경: 4px; 여백 오른쪽: 2px; 여백 왼쪽: 2px; 배경 색상: rgba(27, 31, 35, 0.05); 글꼴 가족: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">userFeignClient.invitedRegister(invitedDto);🎜
@
EnableFeignClients
@EnableFeignClients
这个注解在启动类上,我们肯定要重点关注。小技巧:凡是以
@Enable
开头的各种注解基本上都是开启xxxx
。比如:@EnableFeignClients
表示开启feign客户端。我们进入
@EnableFeignClients
中/** * @author tianwc 公众号:java后端技术全栈、面试专栏 * @version 1.0.0 * @date 2023年07月07日 16:47 * 在线刷题 1200+题和1000+篇干货文章:<a href="http://woaijava.cc/">博客地址</a> */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients { String[] value() default {}; String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<?>[] defaultConfiguration() default {}; Class<?>[] clients() default {}; }로그인 후 복사로그인 후 복사我们通常只需要关心属性
basePackages
,表示我们需要扫描的包目录。如果既没有指定
basePackages
,也没有指定basePackageClasses
,则采用启动类所在的目录作为包扫描路径。默认是这种情况。本文重点来了,在这个注解
@EnableFeignClients
上有个注解@Import(FeignClientsRegistrar.class)
,这里到底是有什么作用?
@Import()
@Import()
@Import()
注解是在spring 3.0版本中引入的,字面意义就是导入.
@Import
注解的全类名是org.springframework.context.annotation.Import
。其只有一个默认的value属性,该属性类型为Class<?>[]
,表示可以传入一个或多个Class对象。通过注释可以看出,该注解有如下作用:
可以导入一个或多个组件类(通常是@Configuration配置类)该注解的功能与Spring XML中的
<import/>
元素相同。可以导入@Configuration
配置类、ImportSelect
和ImportBeanDefinitionRegistrar
的实现类。从spring 4.2版本开始,还可以引用常规组件类(普通类),该功能类似于
AnnotationConfigApplicationContext.register()
方法。该注解可以在类中声明,也可以在元注解中声明。如果需要导入XML或其他非
@Configuration
定义的资源,可以使用@ImportResource
🎜
@Import()
주석은 Spring 버전 3.0에서 도입되었으며 문자 그대로의 의미는 import입니다.@Import
주석의 전체 클래스 이름은org.springframework.context.annotation.Import
.클래스< ;?>[]
는 하나 이상의 Class 객체가 전달될 수 있음을 나타냅니다. 🎜🎜주석에서 볼 수 있듯이 주석에는 다음과 같은 기능이 있습니다. 🎜🎜하나 이상의 구성 요소 클래스(일반적으로 @Configuration 구성 클래스)를 가져올 수 있습니다. 이 주석의 기능은<import/>
요소는 동일합니다. .@Configuration
구성 클래스, < 코드 스타일="글꼴 크기: 14px; 패딩: 2px 4px; 테두리 반경: 4px; 여백 오른쪽: 2px; 여백 왼쪽: 2px; 배경 색상: rgba(27, 31, 35, 0.05); 글꼴- family : "Operator Mono", Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">ImportSelect 및ImportBeanDefinitionRegistrar
구현 클래스. 🎜🎜spring 4.2부터는 일반 컴포넌트 클래스(일반 클래스)도 참조할 수 있습니다. 이 함수는AnnotationConfigApplicationContext.register()
메서드. 🎜🎜이 주석은 클래스 또는 메타 주석에서 선언할 수 있습니다. XML 또는 기타 비, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96)를 가져와야 하는 경우 );">@Configuration 정의된 리소스의 경우@ImportResource
주석 . 🎜🎜일반적으로 세 가지 사용 방법이 있습니다: 🎜
@Import
一个普通类 spring会将该类加载到spring容器中@Import
一个类,该类实现了ImportBeanDefinitionRegistrar
接口,在重写的registerBeanDefinitions
方法里面,能拿到BeanDefinitionRegistry
的注册器,能手工往beanDefinitionMap
中注册beanDefinition
@Import
一个类 该类实现了ImportSelector
重写selectImports
方法该方法返回了String[]数组的对象,数组里面的类都会注入到spring容器当中。下面我们来聊聊
@Import
在openfeign的这里是起到什么作用。
openfeign
中作用回答上面的代码里
@Import(FeignClientsRegistrar.class)로그인 후 복사로그인 후 복사这里导入的是
FeignClientsRegistrar
类,我们再来看看他的类关系图:
从类关系图来看,
FeignClientsRegistrar
实现了ImportBeanDefinitionRegistrar
接口。再结合@Import
的三种使用方式中的第二种方式,能手工往beanDefinitionMap
中注册beanDefinition
。/** * @author tianwc 公众号:java后端技术全栈、面试专栏 * @version 1.0.0 * @date 2023年07月07日 16:47 * 在线刷题 1200+题和1000+篇干货文章:<a href="http://woaijava.cc/">博客地址</a> */ @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { registerDefaultConfiguration(metadata, registry); registerFeignClients(metadata, registry); }로그인 후 복사로그인 후 복사这个方法
registerBeanDefinitions()
是feign的核心入口方法,其中会做两件事:注册默认的配置和注册所有的FeignClient。
registerDefaultConfiguration(metadata, registry)
这个方法是负责注册
OpenFeign
的默认配置 ,逻辑相对简单:private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //获取@EnableFeignClients的全部属性 //@EnableFeignClients(basePackages = {"com.tian.feign"}) //这里的basePackages就是我们指定的熟悉 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(); } registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration")); } }로그인 후 복사
defaultAttrs
中内容如下:
但是这里我们只关注defaultConfiguration,我们并有对其进行设置,所以我们可以忽略他。重点是下面这个方法。
registerFeignClients(metadata, registry)
这里就是项目启动时和openfeign相关的核心代码,这也是
@EnableFeignClients
和@FeignClient
两个注解关联起来的地方。我们进入源码中:
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { ClassPathScanningCandidateComponentProvider scanner = getScanner(); scanner.setResourceLoader(this.resourceLoader); Set<String> basePackages; Map<String, Object> attrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName()); AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter( FeignClient.class); final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("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) { 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); registerClientConfiguration(registry, name, attributes.get("configuration")); registerFeignClient(registry, annotationMetadata, attributes); } } } }로그인 후 복사代码一行一行看是不是觉得很累,我给你总结好了。
上面的方法分为以下七个步骤:
먼저 @EnableFeignClients
주석이 달린 All 주로 스캔 패키지 경로를 가져오기 위한 속성(basePackages); <code style='font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);'>@EnableFeignClients
注解的所有属性,主要为了拿到扫描包路径(basePackages
);因为一般不会在 @EnableFeignClients
注解中配置clients属性,所以会进入到clients属性为空时的逻辑;然后通过 getScanner()
方法获取扫描器:ClassPathScanningCandidateComponentProvider
,并将上下文AnnotationConfigServletWebServerApplicationContext
作为扫描器的ResourceLoader
;接着给扫描器 ClassPathScanningCandidateComponentProvider
添加一个注解过滤器(AnnotationTypeFilter),只过滤出包含@FeignClient
注解的BeanDefinition
;- 🎜 일반적으로
再通过 getBasePackages(metadata)
方法获取@EnableFeingClients
@EnableFeignClients
는 주석에서 클라이언트 속성을 구성하여 클라이언트 속성이 비어 있을 때 논리를 입력하도록 합니다. 🎜🎜🎜🎜 그런 다음getScanner()
메소드는 스캐너를 가져옵니다:ClassPathScanningCandidateComponentProvider
및 컨텍스트AnnotationConfigServletWebServerApplicationContext
스캐너로ResourceLoader
;🎜🎜🎜🎜그런 다음 스캐너에ClassPathScanningCandidateComponentProvider
@FeignClient
주석BeanDefinition
; 🎜🎜🎜🎜 그런 다음getBasePackages(metadata)
메소드는@EnableFeingClients
주석에 지정된 패키지 스캐닝 경로 또는 스캐닝 클래스. 획득하지 못한 경우 시작 클래스가 있는 패키지 경로가 기본적으로 스캔됩니다. 🎜🎜그런 다음 핵심 논리를 입력합니다. scanner.findCandidateComponents( basePackage)
메서드는 패키지 경로@FeignClient
어셈블리를 위한 주석이 달고 검증된 인터페이스;scanner.findCandidateComponents(basePackage)
方法从包路径下扫描出所有标注了@FeignClient
注解并符合条件装配的接口;
FeignClientConfiguration
在BeanDefinitionRegistry
中注册一下,再对FeignClient
做真正的注册操作。总结
在openfeign
源码中的@Import注解在这里的作用就是将扫描到带有FeignClient
FeignClientConfiguration
BeanDefinitionRegistry에 등록
한 다음 FeignClient
는 실제 등록 작업을 수행합니다. 요약
Inopenfeign
소스 코드의 @Import 주석은 여기에서 FeignClient
주석이 달린 모든 인터페이스 클래스는 Bean 형식으로 등록됩니다. 스프링 IOC 컨테이너.
@Import
공통 클래스 스프링 이 클래스는 스프링 컨테이너@Import
一个普通类 spring会将该类加载到spring容器中@Import
一个类,该类实现了ImportBeanDefinitionRegistrar
接口,在重写的registerBeanDefinitions
方法里面,能拿到BeanDefinitionRegistry
的注册器,能手工往beanDefinitionMap
中注册beanDefinition
@Import
一个类 该类实现了ImportSelector
重写selectImports
@Import
ImportBeanDefinitionRegistrar code> 인터페이스, 다시 작성된 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px; background-color: rgba (27, 31) , 35, 0.05);글꼴 계열: " operator mono consolas monaco menlo monospace break-all rgb>registerBeanDefinitionsIn 이 방법을 사용하면 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px; background-color: rgba(27 , 31, 35, 0.05);font-family: " operator mono consolas monaco menlo monospace break-all rgb>BeanDefinitionRegistry
register, beanDefinitionMap
등록beanDefinition
위 내용은 Spring Cloud 소스 코드 분석: 1부의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











엔터프라이즈 애플리케이션의 복잡성이 계속 증가함에 따라 점점 더 많은 기업이 애플리케이션을 여러 마이크로서비스로 분할하고 마이크로서비스 간의 협업을 통해 전체 비즈니스 프로세스를 완료하기 시작했습니다. 이러한 아키텍처 접근 방식은 애플리케이션을 더욱 안정적이고 확장 가능하게 만들 수 있지만 로드 밸런싱, 서비스 검색 등과 같은 몇 가지 새로운 문제도 발생합니다. 이 기사에서는 Spring Cloud를 사용하여 마이크로서비스 아키텍처의 로드 밸런싱 문제를 해결하는 방법을 소개합니다. 로드 밸런싱이란 무엇입니까? 로드 밸런싱(LoadBalancing)은 여러 서버와 네트워크의 균형을 유지하는 것을 말합니다.

개인적으로 소스코드를 읽기 위해서는 먼저 사용할 수 있어야 한다고 생각하며, 익숙해지면 다른 사람들이 어떻게 구현했는지 짐작할 수 있습니다. 관련 공식 문서가 있으면 공식 문서를 읽어보세요.

인터넷의 발전과 기술의 지속적인 업데이트로 인해 기존의 단일 애플리케이션은 더 이상 사용자 요구를 충족할 수 없으며 마이크로서비스라는 개념이 등장했습니다. SpringCloud는 Pivotal에서 출시한 마이크로서비스 개발 툴킷으로 개발자에게 마이크로서비스 아키텍처 애플리케이션을 구축, 배포 및 관리할 수 있는 매우 편리한 방법을 제공합니다. 본 글에서는 SpringCloud의 개념과 아키텍처, 마이크로서비스 개발 프로세스,

Java를 사용하여 Spring Cloud Kubernetes 기반 컨테이너 오케스트레이션 애플리케이션을 개발하는 방법 컨테이너 기술이 개발되고 널리 적용됨에 따라 컨테이너 오케스트레이션 도구는 개발자에게 없어서는 안 될 부분이 되었습니다. 가장 널리 사용되는 컨테이너 오케스트레이션 도구 중 하나인 Kubernetes는 업계 표준이 되었습니다. 이러한 맥락에서 Spring Cloud와 Kubernetes를 결합하면 컨테이너 오케스트레이션을 기반으로 애플리케이션을 쉽게 개발할 수 있습니다. 이번 글에서는 자세히 소개하겠습니다

인터넷의 급속한 발전으로 인해 기업 수준의 애플리케이션은 날로 복잡해지고 있습니다. 이러한 상황에 대응하여 마이크로서비스 아키텍처가 탄생했습니다. 모듈성, 독립적 배포 및 높은 확장성을 통해 오늘날 엔터프라이즈 수준 애플리케이션 개발을 위한 첫 번째 선택이 되었습니다. 뛰어난 마이크로서비스 아키텍처인 Spring Cloud는 실제 애플리케이션에서 큰 이점을 보여왔습니다. 이 기사에서는 SpringCloud 마이크로서비스 아키텍처의 배포, 운영 및 유지 관리에 대해 소개합니다. 1. SpringCloud 마이크로서비스 아키텍처 배포 SpringCloud

Java 언어의 SpringCloud 프레임워크 소개 클라우드 컴퓨팅과 마이크로서비스의 인기로 인해 SpringCloud 프레임워크는 Java 언어로 클라우드 네이티브 애플리케이션을 구축하는 데 선호되는 프레임워크 중 하나가 되었습니다. 이 기사에서는 Spring Cloud 프레임워크의 개념과 기능을 소개하고 Spring Cloud를 사용하여 마이크로서비스 아키텍처를 구축하는 방법을 소개합니다. SpringCloud 소개 SpringCloud 프레임워크는 SpringBoot를 기반으로 하는 마이크로서비스 프레임워크입니다. 그것은

마이크로서비스 아키텍처의 인기로 인해 점점 더 많은 엔터프라이즈 개발 팀이 Spring Cloud를 사용하여 자체 마이크로서비스 시스템을 구축하기 시작했습니다. 분산 환경에서 분산 잠금을 구현하는 것은 중요한 기술적 과제입니다. 이 기사에서는 Spring Cloud 프레임워크에서 분산 잠금의 마이크로서비스 방식을 구현하는 방법을 소개합니다. 먼저 분산 잠금이 무엇인지 이해해야 합니다. 분산 잠금은 공유 리소스에 대한 액세스를 보호하는 데 사용되는 기술로, 분산 환경에서 여러 노드가 동시에 동일한 리소스를 수정하거나 수정하지 않도록 할 수 있습니다.

인터넷 기술이 지속적으로 발전함에 따라 점점 더 많은 기업이 시스템 구축을 위해 마이크로서비스 아키텍처를 채택하기 시작했습니다. SpringCloud는 이러한 맥락에서 빠르게 등장한 마이크로서비스 프레임워크입니다. 이를 바탕으로 이번 글에서는 SpringCloud 마이크로서비스와 컴포넌트화의 결합에 대해 논의하고, 그 장점과 구현 방법을 분석해보겠습니다. 1. SpringCloud 마이크로서비스 소개 SpringCloud는 SpringBoot 프로젝트의 업그레이드 버전으로, 다양한 도구를 제공합니다.
