// The above is to scan the normal bean

// Handle the three cases of @import (normal class; ImportSelector classes; ImportBeanDefinitionRegistrar class) private void processImports (ConfigurationClass configClass, SourceClass currentSourceClass, Collection importCandidates, boolean checkForCircularImports) { if (importCandidates.isEmpty()) { return; }

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)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<? > candidateClass = candidate.loadClass(); / / reflection to realize an object ImportSelector selector. = BeanUtils instantiateClass (candidateClass, ImportSelector. Class); ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); if (this.deferredImportSelectors ! = null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else {/ / callback String [] importClassNames = selector. SelectImports (currentSourceClass. For getMetadata ()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); // Recursion, where processImports is called the second time // If it is a normal class, Else processImports(configClass, currentSourceClass, importSourceClasses, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class<? > candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); / / added to a list of and different configClass importselector addImportBeanDefinitionRegistrar (registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration Class // Otherwise, To join the call after importStack processConfigurationClass processing / / processConfigurationClass is mainly put class configurationClasses inside //configurationClasses is a set that will be parsed into bd and registered. // You can see that the normal class is registered when scanned. // If importSelector, For out of the back in configurationClasses this. Registration will be importStack. RegisterImport (currentSourceClass. For getMetadata (), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process imports candidates for configuration  class [" + configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); }}Copy the code

}

>processImports, the class that handles import. >1. Ordinary beans >2. Implementation of importSelector beans (can register multiple classes of String array strings) >3. Implements ImportBeanDefinitionRegistrar > 1. Import common bean, will join the call after importStack processConfigurationClass for processing, Put it in after configurationClasses and register it out. >2. Import is an importSelector class. It instantiates the importSelector class and then executes the selectImports method of the selector to get the string of the class array to be injected into spring. The String[] array is then processed by calling the processImports method again, which eventually leads to the import beans step: Will join the call after importStack processConfigurationClass processing, into the configurationClasses back for registration. > 3. Import ImportBeanDefinitionRegistrar, will instantiate the ImportBeanDefinitionRegistrar class first, then add it to a list and importselector among different.Copy the code

For the import of the bean processing, is in ConfigurationClassPostProcessor # processConfigBeanDefinitions () method of processing, namely the following code:

/ * *

  • It’s worth noting here that the scanned beans may contain special classes
  • Such as ImportBeanDefinitionRegistrar so are also treated in this way
  • But it is not included in configClasses
  • ConfigClasses mainly contains importSelector
  • Because ImportBeanDefinitionRegistrar when scan have been added to a list of

* / / / bd to map beyond ordinary enclosing reader. LoadBeanDefinitions (configClasses);

//ConfigurationClassBeanDefinitionReader public void loadBeanDefinitions(Set configurationModel) { TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator(); for (ConfigurationClass configClass : configurationModel) { loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator); }}

private void loadBeanDefinitionsForConfigurationClass( ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

if (trackedConditionEvaluator.shouldSkip(configClass)) { String beanName = configClass.getBeanName(); if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { this.registry.removeBeanDefinition(beanName); } this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); return; } // If a class is imported, Complete registration will be standard / / early spring here if (configClass. IsImported ()) {registerBeanDefinitionForImportedConfigurationClass (configClass); } //@Bean for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } //xml loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); / / registered Registrar loadBeanDefinitionsFromRegistrars (configClass getImportBeanDefinitionRegistrars ());Copy the code

}

// Insert import and importSelector into the bean, Registered with the bean factory in private void registerBeanDefinitionForImportedConfigurationClass (ConfigurationClass configClass) { AnnotationMetadata metadata = configClass.getMetadata(); AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);

ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);

if (logger.isDebugEnabled()) {
	logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
}
Copy the code

}

/ / inject ImportBeanDefinitionRegistrar bean, Registered with the bean factory in private void loadBeanDefinitionsFromRegistrars (Map < ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) { registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, this.registry)); }

< DefinitionMap (definitionMap); > definitionMap (DefinitionMap); > 2. Import (normal class) and scan to a map stored in configurationClasses. > 3. Import (importSelector), scan through the traversal loop and place it one by one into a map of configurationClasses. > 4. Import (importBeanDefinitionRegistrar), after scanning to the store to importBeanDefinitionRegistrars a map in the collection. < DefinitionMap > For import classes, spring calls loadBeanDefinitions to register the class scanned for import with beanDefinitionMap. > 1. When a bean is annotated with @Configuration, it is a full annotation class. Spring generates a CGlib proxy class for a bean with @Component, @ComponentScan, @Import, @ImportResource, etc. For classes annotated with @Configuration, Spring uses Cglib to generate a proxy class for that class. Why do YOU need a Cglib agent? > > AppConfig class, which injects two beans with @Bean, calls configDao1() in the configDao2() method to prevent the configDao1 object from being created twice. > > Note: CGLIb is based on inheritance. > is in invokeBeanFactoryPostProcessors (registryProcessors, the beanFactory); Method.Copy the code

private static void invokeBeanFactoryPostProcessors( Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory the beanFactory) {/ / because there is only one data ConfigurationClassPostProcessor for (spring BeanFactoryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanFactory(beanFactory); }}

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { int factoryId = System.identityHashCode(beanFactory); if (this.factoriesPostProcessed.contains(factoryId)) { throw new IllegalStateException( “postProcessBeanFactory already called on this post-processor against ” + beanFactory); } this.factoriesPostProcessed.add(factoryId); if (! this.registriesPostProcessed.contains(factoryId)) { // BeanDefinitionRegistryPostProcessor hook apparently not supported… // Simply call processConfigurationClasses lazily at this point then. processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); } // Generate cglib agent for the configuration class // Why do you need to generate cglib agent? (the proxy class to AppConfig, configDao2 () method calls the configDao1 () method) enhanceConfigurationClasses (the beanFactory); beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); }

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) { Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>(); for (String beanName : beanFactory.getBeanDefinitionNames()) { BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName); // Check whether it is a fully annotated class. The relationship between full and lite the if (ConfigurationClassUtils isFullConfigurationClass (beanDef)) {if (! (beanDef instanceof AbstractBeanDefinition)) { throw new BeanDefinitionStoreException(“”); } else if (logger.isWarnEnabled() && beanFactory.containsSingleton(beanName)) { logger.warn(“”); } configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef); } } if (configBeanDefs.isEmpty()) { return; }

/ / complete additional agent ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer (); for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) { AbstractBeanDefinition beanDef = entry.getValue(); // If a @Configuration class gets proxied, always proxy the target class beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE); try { // Set enhanced subclass of the user-specified bean class Class<? > configClass = beanDef.resolveBeanClass(this.beanClassLoader); if (configClass ! = null) {// Complete the cGLIb proxy Class<? > enhancedClass = enhancer.enhance(configClass, this.beanClassLoader); if (configClass ! = enhancedClass) { if (logger.isDebugEnabled()) { logger.debug("")); } beanDef.setBeanClass(enhancedClass); }}}}Copy the code

}

ConfigurationClassEnhancer

public Class enhance(Class configClass, @ Nullable this this) {/ / determine whether been agent if (EnhancedConfiguration. Class. IsAssignableFrom (configClass)) {if (logger.isDebugEnabled()) { logger.debug(“”); } return configClass; } // Cglib Class<? > enhancedClass = createClass(newEnhancer(configClass, classLoader)); if (logger.isDebugEnabled()) { logger.debug(String.format(“”); } return enhancedClass; }

private Enhancer newEnhancer(Class configSuperClass, @Nullable ClassLoader classLoader) { Enhancer enhancer = new Enhancer(); Cglib is based on the inherited enhancer.setsuperclass (configSuperClass); // Enhance the interface. Why do you want to enhance the interface? BeanFactoryAware (BeanFactoryAware, BeanFactoryAware) In order to obtain the BeanFactory object) enhancer. SetInterfaces (new Class [] {EnhancedConfiguration. Class}); // do not inherit the Factory interface enhancer.setUseFactory(false); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); / / BeanFactoryAwareGeneratorStrategy is a generation strategy / / add member variables to generate additional classes $$the beanFactory / / The setBeanFactory method in BeanFactoryAware is based on the parent interface of EnhancedConfiguration. // Set the value of this variable to beanFactory in the current Context, so that our cglib proxy object has a beanFactory. // The function of the BeanFactory is to intercept this call when it is called, And directly in the beanFactory target bean enhancer. SetStrategy (new BeanFactoryAwareGeneratorStrategy (this)); / / filter method, can’t always go to the new enhancer. SetCallbackFilter (CALLBACK_FILTER); enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes()); return enhancer; }

/ / CALLBACK_FILTER: SetCallbackFilter private static final Callback[] CALLBACKS = new Callback[] { / / the scope of the main control bean (don’t every time to call new) new BeanMethodInterceptor (), / / set a the beanFactory new BeanFactoryAwareMethodInterceptor (), NoOp.INSTANCE }; private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);

/ * *

  • Used to intercept calls to the @bean method and get the target Bean directly from the BeanFactory, rather than by executing the method.

*/ private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {

@Override @Nullable public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs, Throws Throwable {// enhancedConfigInstance Proxy // BeanFactory is obtained from the $$beanFactory member generated by cglib in enhancedConfigInstance. ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance); String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod); // Determine whether this bean is a scoped-proxy Scope scope = AnnotatedElementUtils.findMergedAnnotation(beanMethod, Scope.class); if (scope ! = null && scope.proxyMode() ! = ScopedProxyMode.NO) { String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName); if (beanFactory.isCurrentlyInCreation(scopedBeanName)) { beanName = scopedBeanName; } } if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) && factoryContainsBean(beanFactory, beanName)) { Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName); if (factoryBean instanceof ScopedProxyFactoryBean) { // Scoped proxy factory beans are a special case and should not be further proxied } else { // It is a candidate FactoryBean - go ahead with enhancement return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName); }} / / / / a very newbier judgments to determine whether new or get / / judgement method of execution and invoke method is the same if (isCurrentlyInvokedFactoryMethod (beanMethod)) {/ / if it is the same way: Calls methods on the proxy object, Implemented the proxy class method (namely configDao1 () new configDao1 () object instantiation configDao1) return cglibMethodProxy. InvokeSuper (enhancedConfigInstance, beanMethodArgs); } // Not the same method: call the getBean method. Return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName); } private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs, ConfigurableBeanFactory beanFactory, String beanName) {/ / whether he is creating a Boolean alreadyInCreation. = the beanFactory isCurrentlyInCreation (beanName); try { if (alreadyInCreation) { beanFactory.setCurrentlyInCreation(beanName, false); } boolean useArgs = ! ObjectUtils.isEmpty(beanMethodArgs); if (useArgs && beanFactory.isSingleton(beanName)) { for (Object arg : beanMethodArgs) { if (arg == null) { useArgs = false; break; BeanInstance = (useArgs?); // beanInstance = (useArgs?); beanFactory.getBean(beanName, beanMethodArgs) : beanFactory.getBean(beanName)); if (! ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) { if (beanInstance.equals(null)) { if (logger.isDebugEnabled()) { logger.debug("")); } beanInstance = null; } else { String msg = ""; try { BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName); msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription(); } catch (NoSuchBeanDefinitionException ex) { // Ignore - simply no detailed message then. } throw new IllegalStateException(msg); } } Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod(); if (currentlyInvoked ! = null) { String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked); beanFactory.registerDependentBean(beanName, outerBeanName); } return beanInstance; } finally { if (alreadyInCreation) { beanFactory.setCurrentlyInCreation(beanName, true); }} / / judgment Method of execution and invoke Method is the same private Boolean isCurrentlyInvokedFactoryMethod Method (Method) {Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod(); return (currentlyInvoked ! = null && method.getName().equals(currentlyInvoked.getName()) && Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes())); }}Copy the code

}

> cglib dynamic proxy class for @Configuration annotated classes: >1. The main approach is to use the BeanMethodInterceptor class to intercept the bean when it is instantiated. = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = >> Check whether the method being executed is the same as the method being called, that is, when the configDao2() method is executed, the configDao1() method is called. >> So when the configDao1() method is executed again, make sure that the main method called is configDao2, that the executing method and the calling method are not the same. > > 3.1 if it is the same method: call the proxy object method, implemented the method of the proxy class > > cglibMethodProxy. InvokeSuper (enhancedConfigInstance beanMethodArgs); >> Return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName); ### Spring initialization summary #### Spring extension points (5) >1. BeanPostProcessor >> handles the bean instance process, after instantiation, and before the bean is managed by Spring's bean container. BeanFactoryPostProcessor >> Any bean in spring's bean container is executed before it is new, and built against the beanFactory. > > classic scene: ConfigurationClassPostProcessor# postProcessBeanFactory, in view of the Configuration class (@ Configuration annotations) plus additional agent. > 3. BeanFactoryRegistryPostProcessor > > is a subclass of spring BeanFactoryPostProcessor, before spring BeanFactoryPostProcessor implementation? Because the source code of the first traversal BeanFactoryRegistryPostProcessor (provided by the spring, and custom) custom first. >> Classic scene: ConfigurationClassPostProcessor# postProcessBeanDefinitionRegistry, scanning, three kinds of import scan, @ the Bean's scan, To determine if the configuration class is a complete configuration class >4. ImportSelector >> Returns an array of class names (full names) via this method selectImports, making it beanDefinition, Add a beanDefinition dynamically (this beanDefinition is written dead because it is generated internally by Spring, We can't change these BeanDefinition) > 5. ImportBeanDefinitionRegistrar Definitionregistry (DefinitionRegistry); / / Define the definition (definitionRegistry); / / define the definition (DefinitionRegistry). Mybatis mapperScan #### Spring bean initialization structure diagram: *! [insert picture description here] (https://img-blog.csdnimg.cn/20190911160302476.jpg?x-oss-process=image/watermark, type_ZmFuZ3poZW5naGVpdGk, sha dow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI0MTAxMzU3,size_16,color_FFFFFF,t_70)Copy the code