In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly explains the "Spring Boot configuration class loading process example", the content of the article is simple and clear, easy to learn and understand, now please follow the editor's train of thought slowly in depth, together to study and learn "Spring Boot configuration class loading process example" bar!
This article is based on the Spring Boot 1.4.1.RELEASE version
The startup code is as follows
@ SpringBootApplicationpublic class SampleApplication {public static void main (String [] args) throws Exception {SpringApplication.run (SampleApplication.class, args);}}
Then start the analysis process, because there are many details of Spring, so we just focus on the key points, otherwise it's easy to get lost in it.
/ / Line 273 of ConfigurationClassPostProcessor.java// public void processConfigBeanDefinitions (BeanDefinitionRegistry registry) {List configCandidates = new ArrayList (); String [] candidateNames = registry.getBeanDefinitionNames (); / / traverses all registered bean for (String beanName: candidateNames) {BeanDefinition beanDef = registry.getBeanDefinition (beanName) / / determine whether this bean is a configuration class if (ConfigurationClassUtils.isFullConfigurationClass (beanDef) | | ConfigurationClassUtils.isLiteConfigurationClass (beanDef)) {if (logger.isDebugEnabled ()) {logger.debug ("Bean definition has already been processed as a configuration class:" + beanDef) that has been loaded. }} / / if it has not been loaded, determine whether the configuration class / / this judgment logic is very simple, interested friends can learn about / / because it is a tool class, in fact, do not look at it does not affect the overall situation, notice here after the check The above check is true else if (ConfigurationClassUtils.checkConfigurationClassCandidate (beanDef, this.metadataReaderFactory)) {configCandidates.add (new BeanDefinitionHolder (beanDef, beanName) }} if (configCandidates.isEmpty ()) {return } / / the function of this code is to sort the configuration classes by Order, but it is actually useless, / / because there is only one element in the configCandidates list at this time, that is, SampleApplication Collections.sort (configCandidates, new Comparator () {@ Override public int compare (BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {int i1 = ConfigurationClassUtils.getOrder (bd1.getBeanDefinition ()); int i2 = ConfigurationClassUtils.getOrder (bd2.getBeanDefinition () Return (i1)
< i2) ? -1 : (i1 >I2)? 1: 0;}); / / omit part of the code / / here is the key parser.parse (candidates) of configuration parsing; / / omit part of the code}
Let's take a look at the class ConfigurationClassParser.
/ / ConfigurationClassParser.java// line 166 public void parse (Set configCandidates) {this.deferredImportSelectors = new LinkedList (); / / traverses all configuration classes, calling different parse methods according to the type / / what each of the three types here represents. It is not clear that for (BeanDefinitionHolder holder: configCandidates) {BeanDefinition bd = holder.getBeanDefinition () Try {if (bd instanceof AnnotatedBeanDefinition) {parse (AnnotatedBeanDefinition) bd). GetMetadata (), holder.getBeanName ());} else if (bd instanceof AbstractBeanDefinition & & ((AbstractBeanDefinition) bd) .hasBeanClass ()) {parse (AbstractBeanDefinition) bd) .getBeanClass (), holder.getBeanName ()) } else {parse (bd.getBeanClassName (), holder.getBeanName ());} catch (BeanDefinitionStoreException ex) {throw ex;} catch (Throwable ex) {throw new BeanDefinitionStoreException ("Failed to parse configuration class [" + bd.getBeanClassName () + "]", ex) } / / omit part of the code}
Different parse methods assemble various parameters into ConfigurationClass objects, which are passed to processConfigurationClass ()
/ / ConfigurationClassParser.java// line 208 protected void processConfigurationClass (ConfigurationClass configClass) throws IOException {/ / determine whether the current bean to be parsed meets the parsing condition if (this.conditionEvaluator.shouldSkip (configClass.getMetadata (), ConfigurationPhase.PARSE_CONFIGURATION)) {return;} ConfigurationClass existingClass = this.configurationClasses.get (configClass) If (existingClass! = null) {if (configClass.isImported ()) {if (existingClass.isImported ()) {existingClass.mergeImportedBy (configClass);} return;} else {this.configurationClasses.remove (configClass); for (Iterator it = this.knownSuperclasses.values (). Iterator (); it.hasNext () ) {if (configClass.equals (it.next () {it.remove ();}} / omit part of the code} / / line 73 of ConditionEvaluator.java// AnnotatedTypeMetadata: comment information on the class / / ConfigurationPhase:PARSE_CONFIGURATION- verifies when parsing the configuration REGISTER_BEAN- verifies public boolean shouldSkip (AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {/ / if there is no configuration condition when registering bean, directly return if (metadata = = null | |! metadata.isAnnotated (Conditional.class.getName () {return false } / / if phase is not specified, the configuration class uses PARSE_CONFIGURATION, and others use REGISTER_BEAN if (phase = = null) {if (metadata instanceof AnnotationMetadata & & ConfigurationClassUtils.isConfigurationCandidate ((AnnotationMetadata) metadata)) {return shouldSkip (metadata, ConfigurationPhase.PARSE_CONFIGURATION);} return shouldSkip (metadata, ConfigurationPhase.REGISTER_BEAN);} / / get Condition and determine the condition List conditions = new ArrayList () For (String [] conditionClasses: getConditionClasses (metadata)) {for (String conditionClass: conditionClasses) {Condition condition = getCondition (conditionClass, this.context.getClassLoader ()); conditions.add (condition);}} AnnotationAwareOrderComparator.sort (conditions); for (Condition condition: conditions) {ConfigurationPhase requiredPhase = null; if (condition instanceof ConfigurationCondition) {requiredPhase = ((ConfigurationCondition) condition). GetConfigurationPhase () } if (requiredPhase = = null | | requiredPhase = = phase) {if (! condition.matches (this.context, metadata)) {return true;} return false;}
Before starting to parse the configuration class, it will determine whether the current class meets the criteria and whether it has been parsed before entering the parsing process
/ / Line 208 of ConfigurationClassParser.java// protected void processConfigurationClass (ConfigurationClass configClass) throws IOException {/ / omit some code / / Recursive processing configuration class and its parent class SourceClass sourceClass = asSourceClass (configClass); do {sourceClass = doProcessConfigurationClass (configClass, sourceClass);} while (sourceClass! = null); this.configurationClasses.put (configClass, configClass);}
There are a lot of parsing processes, so let's deal with them in stages.
1. Handle nested (internal) configuration classes
/ / Line 252 of ConfigurationClassParser.java// protected final SourceClass doProcessConfigurationClass (ConfigurationClass configClass, SourceClass sourceClass) throws IOException {/ / Recursive processing of nested (internal) configuration class processMemberClasses (configClass, sourceClass) / / omit part of the code} / / Line 326 of ConfigurationClassParser.java// private void processMemberClasses (ConfigurationClass configClass SourceClass sourceClass) throws IOException {for (SourceClass memberClass: sourceClass.getMemberClasses ()) {if (ConfigurationClassUtils.isConfigurationCandidate (memberClass.getMetadata ()) & &! memberClass.getMetadata (). GetClassName (). Equals (configClass.getMetadata (). GetClassName ()) {if (this.importStack.contains (configClass)) {this.problemReporter.error (new CircularImportProblem (configClass, this.importStack)) } else {this.importStack.push (configClass); try {/ / return to the original parsing and recursively process processConfigurationClass (memberClass.asConfigClass (configClass));} finally {this.importStack.pop () }}}
2. Handle @ PropertySource annotations
/ / Line 252 of ConfigurationClassParser.java// protected final SourceClass doProcessConfigurationClass (ConfigurationClass configClass, SourceClass sourceClass) throws IOException {/ / omit part of the code for (AnnotationAttributes propertySource: AnnotationConfigUtils.attributesForRepeatable (sourceClass.getMetadata (), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {/ / parse the properties configuration file and put it in the Spring environment processPropertySource (propertySource) } else {logger.warn ("Ignoring @ PropertySource annotation on [" + sourceClass.getMetadata () .getClassName () + "]. Reason: Environment must implement ConfigurableEnvironment ");}} / / omit part of the code}
3. Handle @ ComponentScan annotations
/ / Line 252 of ConfigurationClassParser.java// protected final SourceClass doProcessConfigurationClass (ConfigurationClass configClass, SourceClass sourceClass) throws IOException {/ / omit some code / / get all @ ComponentScan annotations Set componentScans = AnnotationConfigUtils.attributesForRepeatable (sourceClass.getMetadata (), ComponentScans.class, ComponentScan.class) If (! componentScans.isEmpty () & &! this.conditionEvaluator.shouldSkip (sourceClass.getMetadata (), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan: componentScans) {/ / get bean Set scannedBeanDefinitions = this.componentScanParser.parse (componentScan, sourceClass.getMetadata (). GetClassName ()) according to the @ ComponentScan annotation For (BeanDefinitionHolder holder: scannedBeanDefinitions) {/ / determine whether there is a configuration class in the scanned bean, and if so, continue to recursively parse if (ConfigurationClassUtils.checkConfigurationClassCandidate (holder.getBeanDefinition (), this.metadataReaderFactory)) {parse (holder.getBeanDefinition (). GetBeanClassName (), holder.getBeanName ()). } / / omit part of the code}
4. Handle @ Import annotations. @ Import is used to import Java configuration classes.
Spring Boot's @ EnableAutoConfiguration annotation will also be handled here, so if your autoconfiguration class is scanned by the @ ComponentScan annotation, it will only be treated as a normal configuration class, and autoconfiguration sorting related annotations (@ AutoConfigureAfter, etc.) are invalid.
/ / ConfigurationClassParser.java// line 252 protected final SourceClass doProcessConfigurationClass (ConfigurationClass configClass, SourceClass sourceClass) throws IOException {/ / omit partial code processImports (configClass, sourceClass, getImports (sourceClass), true); / / omit partial code} / / ConfigurationClassParser.java// line 441 private Set getImports (SourceClass sourceClass) throws IOException {Set imports = new LinkedHashSet (); Set visited = new LinkedHashSet (); collectImports (sourceClass, imports, visited); return imports } / / Line 461 of ConfigurationClassParser.java// private void collectImports (SourceClass sourceClass, Set imports, Set visited) throws IOException {/ / visited saves all processed classes to prevent repeated processing of all @ Import annotations on if (visited.add (sourceClass)) {/ / fetch all @ Import annotations on sourceClass, including @ Import annotations for (SourceClass annotation: sourceClass.getAnnotations ()) {String annName = annotation.getMetadata (). GetClassName () / / I don't quite understand why to judge the beginning of java if (! annName.startsWith ("java") & &! annName.equals (Import.class.getName ()) {collectImports (annotation, imports, visited);}} imports.addAll (sourceClass.getAnnotationAttributes (Import.class.getName (), "value")) }} / / Line 494 of ConfigurationClassParser.java// private void processImports (ConfigurationClass configClass, SourceClass currentSourceClass, Collection importCandidates, boolean checkForCircularImports) throws IOException {if (importCandidates.isEmpty ()) {return;} / / verify whether there is a circular dependency if (checkForCircularImports & & isChainedImportOnStack (configClass)) {this.problemReporter.error (new CircularImportProblem (configClass, this.importStack) } else {this.importStack.push (configClass); try {for (SourceClass candidate: importCandidates) {if (candidate.isAssignable (ImportSelector.class)) {Class candidateClass = candidate.loadClass (); ImportSelector selector = BeanUtils.instantiateClass (candidateClass, ImportSelector.class) ParserStrategyUtils.invokeAwareMethods (selector, this.environment, this.resourceLoader, this.registry) / / if it is a DeferredImportSelector interface, store it temporarily after the final processing of the ConfigurationClassParser.parse (Set) method (that is, after other configuration classes have been loaded) if (this.deferredImportSelectors! = null & & selector instanceof DeferredImportSelector) {this.deferredImportSelectors.add (new DeferredImportSelectorHolder (configClass, (DeferredImportSelector) selector) } / / ordinary ImportSelector interfaces directly recursively process else {String [] importClassNames = selector.selectImports (currentSourceClass.getMetadata ()); Collection importSourceClasses = asSourceClasses (importClassNames); processImports (configClass, currentSourceClass, importSourceClasses, false) }} / / the ImportBeanDefinitionRegistrar interface is processed after the ConfigurationClassParser.parse (Set) method is executed (that is, after all configuration classes are loaded) else if (candidate.isAssignable (ImportBeanDefinitionRegistrar.class)) {Class candidateClass = candidate.loadClass () ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass (candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods (registrar, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar (registrar, currentSourceClass.getMetadata ()) } / / neither ImportSelector nor ImportBeanDefinitionRegistrar, handle else {this.importStack.registerImport (currentSourceClass.getMetadata (), candidate.getMetadata (). GetClassName ()); processConfigurationClass (candidate.asConfigClass (configClass)) as a normal @ Configuration class } catch (BeanDefinitionStoreException ex) {throw ex;} catch (Throwable ex) {throw new BeanDefinitionStoreException ("Failed to process import candidates for configuration class [" + configClass.getMetadata (). GetClassName () + "]", ex) } finally {this.importStack.pop ();}
5. Deal with @ ImportResource annotation. @ ImportResource is used to import XML configuration.
/ / Line 252 of ConfigurationClassParser.java// protected final SourceClass doProcessConfigurationClass (ConfigurationClass configClass, SourceClass sourceClass) throws IOException {/ / omit some code if (sourceClass.getMetadata (). IsAnnotated (ImportResource.class.getName () {AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor (sourceClass.getMetadata (), ImportResource.class); String [] resources = importResource.getStringArray ("locations"); Class
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.