Don’t laugh at friends who read the source code. Nowadays, interviews are only about eight-part essays and are unreliable. They are more about asking project questions, source code and questions. I have no choice but to make wheels, otherwise it would be very tiring and boring!
Personally, I think the prerequisite for reading the source code is that you must be able to use it. Once you are familiar with it, you can guess how others implemented it. If there are relevant official documents, then read the official documents.
However, it is a pity that many official documents are poorly written, leaving you confused after reading them for a while.
When I was studying the openfeign
source code recently, I found a key annotation in the source code: @Import
.
Project startup class:
/** * @author tianwc 公眾號:java后端技術(shù)全棧、面試專欄 * @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); } }
Then, there is our feignclient
Interface:
/** * @author tianwc 公眾號:java后端技術(shù)全棧、面試專欄 * @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 邀請?jiān)黾邮找? * @return 邀請成功 */ @PostMapping("/user/invited/register") CommonResult<Boolean> invitedRegister(@RequestBody InvitedDto invitedDto); }
Use case:
/** * @author tianwc 公眾號:java后端技術(shù)全棧、面試專欄 * @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); } }
From above In the code, we can see that the key codes of openfeign
are:
@EnableFeignClients(basePackages = {"com.tian.feign"})
@FeignClient(contextId = "userFeignClient", value = "charge-user-service")
##userFeignClient.invitedRegister(invitedDto);
@EnableFeignClients
@EnableFeignClients
這個注解在啟動類上,我們肯定要重點(diǎn)關(guān)注。
小技巧:凡是以
@Enable
開頭的各種注解基本上都是開啟xxxx
。比如:@EnableFeignClients
表示開啟feign客戶端。
我們進(jìn)入@EnableFeignClients
中
/** * @author tianwc 公眾號:java后端技術(shù)全棧、面試專欄 * @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 {}; }
我們通常只需要關(guān)心屬性basePackages
,表示我們需要掃描的包目錄。
如果既沒有指定
basePackages
,也沒有指定basePackageClasses
,則采用啟動類所在的目錄作為包掃描路徑。默認(rèn)是這種情況。
本文重點(diǎn)來了,在這個注解@EnableFeignClients
上有個注解@Import(FeignClientsRegistrar.class)
,這里到底是有什么作用?
@Import()
@Import()
The annotation was introduced in spring version 3.0 , the literal meaning is import.
@Import
The full class name of the annotation is org.springframework.context.annotation.Import
. It has only one default value attribute, which is of type Class<?>[]
, indicating that one or more Class objects can be passed in.
As can be seen from the annotation, the annotation has the following functions:
You can import one or more component classes (usually the @Configuration configuration class). The function of this annotation is the same as # in Spring XML. ##The elements are the same. You can import the
@Configuration configuration class,
ImportSelect and
ImportBeanDefinitionRegistrar implementation classes.
AnnotationConfigApplicationContext.register() method.
@Configuration, you can use the
@ImportResource annotation.
@Import
一個普通類 spring會將該類加載到spring容器中@Import
一個類,該類實(shí)現(xiàn)了ImportBeanDefinitionRegistrar
接口,在重寫的registerBeanDefinitions
方法里面,能拿到BeanDefinitionRegistry
的注冊器,能手工往beanDefinitionMap
中注冊beanDefinition
@Import
一個類 該類實(shí)現(xiàn)了ImportSelector
重寫selectImports
方法該方法返回了String[]數(shù)組的對象,數(shù)組里面的類都會注入到spring容器當(dāng)中。
下面我們來聊聊@Import
在openfeign的這里是起到什么作用。
openfeign
中作用
回答上面的代碼里
@Import(FeignClientsRegistrar.class)
這里導(dǎo)入的是FeignClientsRegistrar
類,我們再來看看他的類關(guān)系圖:
從類關(guān)系圖來看,FeignClientsRegistrar
實(shí)現(xiàn)了ImportBeanDefinitionRegistrar
接口。再結(jié)合@Import
的三種使用方式中的第二種方式,能手工往beanDefinitionMap
中注冊 beanDefinition
。
/** * @author tianwc 公眾號:java后端技術(shù)全棧、面試專欄 * @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的核心入口方法,其中會做兩件事:
注冊默認(rèn)的配置和注冊所有的FeignClient。
registerDefaultConfiguration(metadata, registry)
這個方法是負(fù)責(zé)注冊OpenFeign
的默認(rèn)配置 ,邏輯相對簡單:
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
中內(nèi)容如下:
但是這里我們只關(guān)注defaultConfiguration,我們并有對其進(jìn)行設(shè)置,所以我們可以忽略他。重點(diǎn)是下面這個方法。
registerFeignClients(metadata, registry)
這里就是項(xiàng)目啟動時和openfeign相關(guān)的核心代碼,這也是@EnableFeignClients
和@FeignClient
兩個注解關(guān)聯(lián)起來的地方。
我們進(jìn)入源碼中:
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); } } } }
代碼一行一行看是不是覺得很累,我給你總結(jié)好了。
上面的方法分為以下七個步驟:
First get all the attributes of the @EnableFeignClients
annotation, mainly to get the scanning package path (basePackages
);-
Because the clients attribute is generally not configured in the @EnableFeignClients
annotation, it will enter the logic when the clients attribute is empty; Then pass getScanner()
method gets the scanner:ClassPathScanningCandidateComponentProvider
, and uses the contextAnnotationConfigServletWebServerApplicationContext
as the scanner'sResourceLoader
;Then add an annotation filter (AnnotationTypeFilter) to the scanner ClassPathScanningCandidateComponentProvider
, and only filter outBeanDefinition
containing the@FeignClient
annotation;Then use the getBasePackages(metadata)
method to obtain the specified package scanning path or scanning class in the@EnableFeingClients
annotation; if not obtained, it will be scanned by default The package path where the startup class is located;Then enter the core logic: use the scanner.findCandidateComponents(basePackage)
method to scan out all interfaces annotated with@FeignClient
and meet the conditions for assembly from the package path ;- ##Finally, register
FeignClientConfiguration in
BeanDefinitionRegistry, and then do the actual registration operation for
FeignClient.
The @Import annotation in the
openfeign source code is used here. All interface classes scanned with
FeignClient annotations will be registered in the spring IOC container in the form of beans.
@Import
A common class spring will load the class into the spring container@Import
A class that implements theImportBeanDefinitionRegistrar
interface. In the overriddenregisterBeanDefinitions
method, you can get theBeanDefinitionRegistry
register and manually add it toRegister in beanDefinitionMap
beanDefinition
@Import
A class that implementsImportSelector
OverrideselectImports
Method This method returns the object of the String[] array, and the classes in the array will be injected into the spring container.
Okay, that’s all I’ll share today. There are many interesting things in this openfeign, we will share them next time!
The above is the detailed content of Spring Cloud source code analysis: Part 1. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

As the complexity of enterprise applications continues to increase, more and more enterprises are beginning to split applications into multiple microservices and complete the entire business process through collaboration between microservices. This architectural approach can make applications more stable and scalable, but it also brings some new problems, such as load balancing, service discovery, etc. This article will introduce how to use Spring Cloud to solve the load balancing problem under the microservice architecture. What is load balancing? Load Balancing (LoadBalancing) refers to the balancing of multiple servers and networks

Personally, I think the prerequisite for reading the source code is that you must be able to use it. Once you are familiar with it, you can guess how others implemented it. If there are relevant official documents, then read the official documents.

With the rapid development of the Internet, the complexity of enterprise-level applications is increasing day by day. In response to this situation, the microservice architecture came into being. With its modularity, independent deployment, and high scalability, it has become the first choice for enterprise-level application development today. As an excellent microservice architecture, Spring Cloud has shown great advantages in practical applications. This article will introduce the deployment and operation and maintenance of SpringCloud microservice architecture. 1. Deploy SpringCloud microservice architecture SpringCloud

With the development of the Internet and the continuous updating of technology, traditional single applications can no longer meet user needs, and the concept of microservices has emerged. SpringCloud is a microservice development toolkit launched by Pivotal. It provides developers with an extremely convenient way to build, deploy and manage microservice architecture applications. This article will introduce the service-oriented SpringCloud microservice development in detail, including the concept and architecture of SpringCloud, the microservice development process and

Introduction to the Spring Cloud framework in the Java language With the popularity of cloud computing and microservices, the Spring Cloud framework has become one of the preferred frameworks for building cloud native applications in the Java language. This article will introduce the concepts and features of the Spring Cloud framework, and how to use Spring Cloud to build a microservice architecture. Introduction to SpringCloud The SpringCloud framework is a microservice framework based on SpringBoot. it is

How to use Java to develop a container orchestration application based on Spring Cloud Kubernetes. With the development and widespread application of container technology, container orchestration tools have become an indispensable part of developers. As one of the most popular container orchestration tools, Kubernetes has become the industry standard. In this context, combining Spring Cloud and Kubernetes, we can easily develop applications based on container orchestration. This article will introduce in detail

With the popularity of microservice architecture, more and more enterprise development teams are beginning to use Spring Cloud to build their own microservice systems. In a distributed environment, implementing distributed locks is an important technical challenge. This article will introduce how to implement microservice practices of distributed locks under the Spring Cloud framework. First, we need to understand what a distributed lock is. Distributed lock is a technology used to protect access to shared resources. It can ensure that in a distributed environment, multiple nodes will not modify the same resource at the same time or

With the widespread application of microservice architecture, how to effectively monitor and alert has become one of the problems faced by developers and operation and maintenance personnel. This article will focus on the specific methods of practicing monitoring and alarming under the SpringCloud microservice architecture. 1. Selection of monitoring indicators Before monitoring, you first need to determine the indicators that need to be monitored. Common indicators include: CPU utilization, memory usage, network bandwidth, disk space, HTTP request response time, number of service calls and latency, etc. These indicators can be used through various monitoring tools
