In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
Spring IoC source code how to parse package scanning, in view of this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and easy way.
After we start Spring by passing in a package path through the AnnotationConfigApplicationContext class, we first initialize the filtering rules for packet scanning. Today, let's take a look at the specific process of packet scanning.
Let's take a look at the following code:
AnnotationConfigApplicationContext class
/ / this constructor automatically scans all classes under the given package and its subpackages, automatically identifies all Spring Bean, and registers them with the container public AnnotationConfigApplicationContext (String... BasePackages) {/ / initialize this (); / / scan package, register bean scan (basePackages); refresh ();}
Above we analyzed the this () method, which initializes the AnnotatedBeanDefinitionReader reader and ClassPathBeanDefinitionScanner scanner, and initializes the scan filtering rules.
Let's take a look at the scan (basePackages) method:
Keep tracking and find that the scan () method in the ClassPathBeanDefinitionScanner class has been called
/ / call the classpath Bean to define the scanner entry method public int scan (String... BasePackages) {/ / get the number of Bean registered in the container int beanCountAtScanStart = this.registry.getBeanDefinitionCount (); / / start the scanner to scan the given package doScan (basePackages); / / Register annotation config processors, if necessary. / / Register Annotation config processor if (this.includeAnnotationConfig) {AnnotationConfigUtils.registerAnnotationConfigProcessors (this.registry);} / / return the number of registered Bean return (this.registry.getBeanDefinitionCount ()-beanCountAtScanStart);}
You can see that it is mainly the doScan (basePackages) method that implements the logic of scanning. Let's continue to track it down and take a look.
/ / classpath Bean definition Scanner scans the given package and its subpackage protected Set doScan (String... BasePackages) {Assert.notEmpty (basePackages, "At least one base package must be specified"); / / create a collection to store the wrapper class Set beanDefinitions = new LinkedHashSet () defined by Bean / / traversal scan all given package for (String basePackage: basePackages) {/ / call the method of the parent class ClassPathScanningCandidateComponentProvider / / scan the given classpath to get the qualified Bean definition Set candidates = findCandidateComponents (basePackage) / / traverse the scanned Bean for (BeanDefinition candidate: candidates) {/ / get the value of @ Scope annotation, that is, get the scope of Bean ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata (candidate) / / set the scope candidate.setScope (scopeMetadata.getScopeName ()) for Bean; / / generate the name String beanName = this.beanNameGenerator.generateBeanName (candidate, this.registry) for Bean / / if the scanned Bean is not the annotated Bean of Spring, set the default value for Bean, / / set if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition ((AbstractBeanDefinition) candidate, beanName) such as automatic dependency injection assembly attributes of Bean. } / / if the scanned Bean is Spring's comment Bean, process its general Spring comment if (candidate instanceof AnnotatedBeanDefinition) {/ / process the general note in Bean AnnotationConfigUtils.processCommonDefinitionAnnotations ((AnnotatedBeanDefinition) candidate) has been analyzed when analyzing the annotated Bean definition class reader } / / check whether the specified Bean needs to be registered in the container according to the Bean name, or conflict with if (checkCandidate (beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder (candidate, beanName) in the container / / apply the corresponding proxy mode definitionHolder = AnnotationConfigUtils.applyScopedProxyMode (scopeMetadata, definitionHolder, this.registry) for Bean according to the scope configured in the note BeanDefinitions.add (definitionHolder); / / register the scanned Bean registerBeanDefinition (definitionHolder, this.registry) with the container } return beanDefinitions;}
This large piece of code is basically code that spring scans to identify annotations and registers Bean into the IOC container.
In line 10, there is a findCandidateComponents (basePackage) method, which is the specific scanning logic.
Continue to track:
ClassPathScanningCandidateComponentProvider class
/ / scan the package public Set findCandidateComponents (String basePackage) of the given classpath {/ / spring5.0 if the index starts to open, the generated file META-INF/spring.components is then loaded to read directly from the local file (generally not recommended to open spring.index.ignore=true) if (this.componentsIndex! = null & & indexSupportsIncludeFilters ()) {return addCandidateComponentsFromIndex (this.componentsIndex, basePackage) } else {return scanCandidateComponents (basePackage);}}
Here is an if judgment. By default, we take a branch of else, that is, the scanCandidateComponents (basePackage) method.
Private Set scanCandidateComponents (String basePackage) {Set candidates = new LinkedHashSet () Try {/ / complete the scan path and scan all .class files classpath*:com/mydemo/**/*.class String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage (basePackage) +'/'+ this.resourcePattern / / locate the resource Resource [] resources = getResourcePatternResolver () .getResources (packageSearchPath); boolean traceEnabled = logger.isTraceEnabled (); boolean debugEnabled = logger.isDebugEnabled () For (Resource resource: resources) {if (traceEnabled) {logger.trace ("Scanning" + resource) } if (resource.isReadable ()) {try {/ / obtain class metadata through ASM And encapsulated in the MetadataReader metadata reader MetadataReader metadataReader = getMetadataReaderFactory () .getMetadataReader (resource) / / determine whether the class conforms to @ CompoentScan's filtering rules / / filter matching exclusion excludeFilters exclusion filter (may not), including the inclusion filter in includeFilter (including at least one). If (isCandidateComponent (metadataReader)) {/ / convert metadata to BeanDefinition ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition (metadataReader); sbd.setResource (resource) Sbd.setSource (resource) / / determine whether it is a qualified bean definition if (isCandidateComponent (sbd)) {if (debugEnabled) { Logger.debug ("Identified candidate component class:" + resource) } / / add candidates.add (sbd) to the collection } else {/ / unqualified is not a top-level class, Concrete class if (debugEnabled) {logger.debug ("Ignored because not a concrete top-level class:" + resource) } else { / / does not match @ CompoentScan filtering rule if (traceEnabled) {logger.trace ("Ignored because not matching any filter:" + resource) } catch (Throwable ex) { Throw new BeanDefinitionStoreException ("Failed to read candidate component class:" + resource Ex) }} else {if (traceEnabled) {logger.trace ("Ignored because not readable:" + resource) } catch (IOException ex) {throw new BeanDefinitionStoreException ("I return candidates; O failure during classpath scanning", ex);} return candidates;}
Here is the main scanning logic, and the comments in the code have been made clear.
The main process:
Scan all .class files according to the package path
Generate the Resource object corresponding to .class according to the package path
Class metadata is obtained through ASM and encapsulated in MetadataReader metadata reader
Judge whether the class conforms to the filtering rules
Judge whether the class is an independent class or a concrete class.
Add to the collection
Let's take a look at the filtering method isCandidateComponent (metadataReader) in detail.
/ / determine whether the class read by the meta-information reader conforms to the container-defined annotation filtering rules / / @ CompoentScan's filtering rules support 5 (comments, classes, regularities, aop, customizations) protected boolean isCandidateComponent (MetadataReader metadataReader) throws IOException {/ / if the annotations of the read classes are in the exclusion comment filtering rules Return false for (TypeFilter tf: this.excludeFilters) {if (tf.match (metadataReader, getMetadataReaderFactory () {return false } / / if the comment of the read class is in the filtering rule of the included comment Return ture for (TypeFilter tf: this.includeFilters) {/ / to determine whether the annotations of the current class are match rules if (tf.match (metadataReader, getMetadataReaderFactory () {/ / have @ Conditional annotations, and perform related processing return isConditionMatch (metadataReader) }} / / if the comment of the read class is neither in the exclusion rule nor in the inclusion rule, false return false;} is returned
Then trace the tf.match () method
AbstractTypeHierarchyTraversingFilter class
Public boolean match (MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {/ / This method optimizes avoiding unnecessary creation of ClassReaders / / as well as visiting over those readers. / / check whether the comments of the current class conform to the regular rules if (matchSelf (metadataReader)) {return true;} / / check class names conform to the rules ClassMetadata metadata = metadataReader.getClassMetadata (); if (matchClassName (metadata.getClassName () {return true } / / if there is an inheritance parent class if (this.considerInherited) {String superClassName = metadata.getSuperClassName (); if (superClassName! = null) {/ / Optimization to avoid creating ClassReader for super class. Boolean superClassMatch = matchSuperClass (superClassName); if (superClassMatch! = null) {if (superClassMatch.booleanValue ()) {return true }} else {/ / Need to read super class to determine a match... Try {if (match (metadata.getSuperClassName (), metadataReaderFactory)) {return true }} catch (IOException ex) {logger.debug ("Could not read super class [" + metadata.getSuperClassName () +) "] of type-filtered class [" + metadata.getClassName () + "]") } / / if there is an implementation interface if (this.considerInterfaces) {for (String ifc: metadata.getInterfaceNames ()) { / / Optimization to avoid creating ClassReader for super class Boolean interfaceMatch = matchInterface (ifc) If (interfaceMatch! = null) {if (interfaceMatch.booleanValue ()) {return true }} else {/ / Need to read interface to determine a match... Try {if (match (ifc, metadataReaderFactory)) {return true }} catch (IOException ex) {logger.debug ("Could not read interface [" + ifc + "] for type-filtered class [" + metadata.getClassName () + "]") } return false;}
The most important of these is the matchSelf (metadataReader) method.
AnnotationTypeFilter class
Protected boolean matchSelf (MetadataReader metadataReader) {/ / get annotation metadata AnnotationMetadata metadata = metadataReader.getAnnotationMetadata () / / whether the check annotation and its derived annotations include @ Component / / get the annotations of the current class metadata.hasAnnotation @ Controller / / get the annotations of the current class and the @ Component\ @ Documented and other return metadata.hasAnnotation (this.annotationType.getName ()) contained in the derived annotations metadata.hasAnnotation @ Controller | (this.considerMetaAnnotations & metadata.hasMetaAnnotation (this.annotationType.getName () }
In this code, we can solve our previous confusion: "how did Spring find annotated classes such as @ Configuration, @ Controller, @ Service?"
It turns out that @ Configuration, @ Controller, and @ Service annotations are actually derivative annotations of @ Component. If we look at the code of these annotations, we will find that they are all modified by @ Component annotations. Spring gets these annotations including @ Component through the metadata.hasMetaAnnotation () method, so they can all be scanned. As follows:
Then we go back to the scanCandidateComponents (basePackage) method, and then there is an isCandidateComponent (sbd) method, as follows:
/ / whether it is an independent class, concrete class protected boolean isCandidateComponent (AnnotatedBeanDefinition beanDefinition) {AnnotationMetadata metadata = beanDefinition.getMetadata (); return (metadata.isIndependent () & & (metadata.isConcrete ()) | (metadata.isAbstract () & & metadata.hasAnnotatedMethods (Lookup.class.getName ();))
The purpose of this method is to determine whether the class is
Top-level class (no parent class or static inner class)
Concrete class (not abstract class or interface)
At this point, the findCandidateComponents (basePackage) method in the doScan (basePackages) method in the ClassPathBeanDefinitionScanner class is over, that is, our package scanning is over, and the scanned classes have been stored in the collection, which is the process of parsing and registering Bean.
Summary
Through this article, we can answer some of the previous questions:
How did Spring find annotated classes like @ Bean, @ Controller, @ Service?
Determine whether @ Component is included in these annotations by the matchSelf (metadataReader) method
How does the @ CompoentScan annotation work?
Filter through the isCandidateComponent (metadataReader) method
This is the answer to the question about how the Spring IoC source code parses the package scan. I hope the above content can be of some help to everyone. If you still have a lot of doubts to solve, you can follow the industry information channel to learn more about it.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.