1. The ApplicationListener of Spring

InitApplicationEventMulticaster () : initialization context event multicast.

protected void initApplicationEventMulticaster(a) {
    // Get the bean factory
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // If there is a multicast in the bean factory, fetch the assignment to the current multicast.
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); }}else {
        // Create a new multicast
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        // Inject multicast into the bean project
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                         "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); }}}// ->DefaultListableBeanFactory.registerSingleton()
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
    super.registerSingleton(beanName, singletonObject);
    // This method checks whether the beanDefinition is created or in the process of being created, and if so, puts its name in manualSingletonNames
    updateManualSingletonNames(set -> set.add(beanName), set -> !this.beanDefinitionMap.containsKey(beanName));
    // Clear cached maps by dependency type
    clearByTypeCache();
}

// ->DefaultSingletonBeanRegistry.registerSingleton()
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
    Assert.notNull(beanName, "Bean name must not be null");
    Assert.notNull(singletonObject, "Singleton object must not be null");
    synchronized (this.singletonObjects) {
        // Check whether the singleton bean exists in the current bean factory
        Object oldObject = this.singletonObjects.get(beanName);
        if(oldObject ! =null) {
            throw new IllegalStateException("Could not register object [" + singletonObject +
                                            "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
        }
        // Add the multicast to the bean factoryaddSingleton(beanName, singletonObject); }}// Add the multicast to singletonObjects and remove the multicast from the secondary and tertiary caches
protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName); }}Copy the code

The method of initializing the multicast is relatively simple, which is to register the multicast in the bean factory. Next, see how to register listeners.

protected void registerListeners(a) {
    // Register static listeners (system) with the multicast.
    for(ApplicationListener<? > listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); }// Get the listener that implements the ApplicationListener interface and register it with the multicast.
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true.false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // Publish early events
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if(earlyEventsToProcess ! =null) {
        for(ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); }}}// SimpleApplicationEventMulticaster
public void multicastEvent(ApplicationEvent event) {
    multicastEvent(event, resolveDefaultEventType(event));
}

/** * ResolvableType: a generic class provided by Spring */
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType ! =null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    // Retrieve all listeners
    for(ApplicationListener<? > listener : getApplicationListeners(event, type)) {// Whether thread pool asynchrony is supported
        if(executor ! =null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else{ invokeListener(listener, event); }}}/** * the middle invokeListener is skipped, there is no logic */
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        // Call the onApplicationEvent method in the implementation ApplicationListener interface class.
        listener.onApplicationEvent(event);
    }
    catch (ClassCastException ex) {
        String msg = ex.getMessage();
        if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
            // 省略......
        }
        else {
            throwex; }}}Copy the code

2. The rear spring BeanFactoryPostProcessor and BeanDefinitionRegistryPostProcessor processor

Actually BeanDefinitionRegistryPostProcessor interface implementation spring BeanFactoryPostProcessor, but interface before the parent interface implementation.

The BeanFactoryPostProcessor interface is executed after the bean definition is loaded and before the instance is initialized.

BeanDefinitionRegistryPostProcessor the execution time of the interface is the bean definition will be loaded into the container, instance initialization before.

// AnnotationConfigApplicationContext.java
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    / / remove all realized the bean and execute invokeBeanFactoryPostProcessors BeanFactoryPostProcessors interface
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    // Check the LoadTimeWeaver and prepare to weave (if found in the meantime),
    / / LoadTimeWeaverAwareProcessor: the class loading operation
    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }}// 
/ PostProcessorRegistrationDelegate. * * * * * beanFactoryPostProcessors Java: Is getBeanFactoryPostProcessors all () method to get to the post processor * /
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List
       
         beanFactoryPostProcessors)
        {

    // Create a Set to store the processed post-processor
    Set<String> processedBeans = new HashSet<>();

    // Determine whether beanDefinitionFactory is BeanDefinitionRegistry
    if (beanFactory instanceof BeanDefinitionRegistry) {
        //1. Perform strong type conversion
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // Create a List to store BeanFactoryPostProcessor
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        / / create a List to store BeanDefinitionRegistryPostProcessor
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

        // Loop through all hard-coded (new created) injected afterprocessors
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor =
                    (BeanDefinitionRegistryPostProcessor) postProcessor;
                / / 1. - > perform postProcessBeanDefinitionRegistry () method, speak later
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                // Add to registryProcessors
                registryProcessors.add(registryProcessor);
            }
            else {
                / / realized BeanDefinitionRegistryPostProcessor interface, into the regularPostProcessorsregularPostProcessors.add(postProcessor); }}/ / 2. Create a list to store post processing, implementing the BeanDefinitionRegistryPostProcessor interface before processed
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        / / the first step, take out all realize rear BeanDefinitionRegistryPostProcessor interface of the processor
        String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
        for (String ppName : postProcessorNames) {
            // Determine whether the PriorityOrdered interface is implemented and place it in two collections
            if(beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); }}// Sort
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        / / execution invokeBeanDefinitionRegistryPostProcessors method
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        // Empty the list to avoid the repetition of loading after loading
        currentRegistryProcessors.clear();

        / / the second step, remove all rear BeanDefinitionRegistryPostProcessor interface of the processor
        // Our own classes with @Component annotations and their children, @improt imports, will be scanned out
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
        for (String ppName : postProcessorNames) {
            // Place the first unprocessed order interface into the list for the next step
            if(! processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));  processedBeans.add(ppName); }}/ / sorting
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        / / invokeBeanDefinitionRegistryPostProcessors execution
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        / / clean up the list
        currentRegistryProcessors.clear();

        // Execute not implemented PriorityOrdered and Ordered
        boolean reiterate = true;
        while (reiterate) {
            reiterate = false;
            // Fetch all the processors
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
            for (String ppName : postProcessorNames) {
                // Remove the unprocessed
                if(! processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate =true; }}// Sort by default
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            / / execution invokeBeanDefinitionRegistryPostProcessors ()
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            / / clean up the list
            currentRegistryProcessors.clear();
        }

        // Execute a post-processor that implements both interfaces simultaneously
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    }

    else {
        / / execution BeanFactoryPostProcessors interface
        invokeBeanFactoryPostPBeanFactoryPostProcessorsrocessors(beanFactoryPostProcessors, beanFactory);
    }

    // Retrieve the back processor that implements the BeanFactoryPostProcessor interface
    String[] postProcessorNames =
        beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true.false);

    // Stores data that implements the PriorityOrdered interface
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    // Stores the Ordered interface
    List<String> orderedPostProcessorNames = new ArrayList<>();
    // Stores objects that do not implement the PriorityOrdered and Ordered interfaces
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    // Loops are placed in different lists depending on the interface implemented
    for (String ppName : postProcessorNames) {
        if (processedBeans.contains(ppName)) {
            // skip - already processed in first phase above
        }
        / / implemented in priorityOrderedPostProcessors PriorityOrdered interface
        else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        }
        / / Ordered interface in orderedPostProcessorNames is realized
        else if(the beanFactory isTypeMatch (ppName Ordered interface in the class.)) {orderedPostProcessorNames. Add (ppName); }else {
            / / common in nonOrderedPostProcessorNamesnonOrderedPostProcessorNames.add(ppName); }}/ / sorting
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    // Implement the PriorityOrdered interface first
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

    // Retrieve the Ordered interface from beanFactory
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
    for (String postProcessorName : orderedPostProcessorNames) {
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    / / sorting
    sortPostProcessors(orderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

    // Implement normal
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

    // Clear the merged bean definition from the cache, because post-processing may have modified the metadata.
    beanFactory.clearMetadataCache();
}
Copy the code
  1. The execution of the BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactoryAfter that, you can seeBeanDefinitionRegistryThere are only some post-processors injected in the constructor and passed in the configuration classes themselves.

  1. Because there is no hard-coded injection back processor, whilepostProcessBeanDefinitionRegistry()Method will be called later when processing other handlers, so expand the argument when it is called.

  1. performinvokeBeanDefinitionRegistryPostProcessors()Parse out the configuration class we passed inScanConfig, through the class@ComponentScan(value = "com.soring.ioc.annotation.postProcessors")Note, the scan packet path has@ComponentAnd its sub-annotations and@ Improt annotationsThe injected class is injected into the registry.

  1. Finish processing implementationPriorityOrderedandOrderedAfter the post-processing of the interface, it’s time to deal with our own implementationBeanDefinitionRegistryPostProcessorInterface back processor.
  2. After processing the implementationBeanDefinitionRegistryPostProcessorInterface postprocessing, in a similar manner, to handle the implementationBeanFactoryPostProcessorsInterface to the rear processor, where thegeBean()Methods, which will be covered in more detail in a later article.

2.1 postProcessBeanDefinitionRegistry ()

// PostProcessorRegistrationDelegate.java
private static void invokeBeanDefinitionRegistryPostProcessors( Collection
        postProcessors, BeanDefinitionRegistry registry) {
	// loop processing
    for(BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanDefinitionRegistry(registry); }}// ConfigurationClassPostProcessor.java
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    int registryId = System.identityHashCode(registry);
    if (this.registriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
            "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
    }
    if (this.factoriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
            "postProcessBeanFactory already called on this post-processor against " + registry);
    }
    this.registriesPostProcessed.add(registryId);
    processConfigBeanDefinitions(registry);
}

// ConfigurationClassPostProcessor.java
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    Get the names of all BeanDefinitions from the container
    String[] candidateNames = registry.getBeanDefinitionNames();

    for (String beanName : candidateNames) {
        Get beanDefinitionMap from beanDefinitionMap
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        // Check whether it is treated as a configuration class
        if(beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) ! =null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: "+ beanDef); }}// Get the configuration class you passed in and check if it is a configuration class
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            configCandidates.add(newBeanDefinitionHolder(beanDef, beanName)); }}// The configuration class is not returned directly, no processing
    if (configCandidates.isEmpty()) {
        return;
    }

    / / sorting
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });

    // Bean name generation policy
    SingletonBeanRegistry sbr = null;
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        if (!this.localBeanNameGeneratorSet) {
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
                AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
            if(generator ! =null) {
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator; }}}// Set the standard environment
    if (this.environment == null) {
        this.environment = new StandardEnvironment();
    }

    // Get the parser for the configuration class
    // this.metadataReaderFactory = metadataReaderFactory; Metadata read factory
	// this.problemReporter = problemReporter; Problem reporter
	// this.environment = environment; The environment
	// this.resourceLoader = resourceLoader; Resource loader
	// this.registry = registry; registry
	// this.componentScanParser = new ComponentScanAnnotationParser(environment, resourceLoader, componentScanBeanNameGenerator, registry); Component scanner
	// this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader); Conditional parser
    ConfigurationClassParser parser = new ConfigurationClassParser(
        this.metadataReaderFactory, this.problemReporter, this.environment,
        this.resourceLoader, this.componentScanBeanNameGenerator, registry);

    // Store each new parsed value in the following loop
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    // Stores the parsed configuration classes in the loop
    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    do {
        // Real parsing method
        parser.parse(candidates);
        / / check
        parser.validate();
		// Store the parsed configuration classes
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        // Remove all parsed ones from it
        configClasses.removeAll(alreadyParsed);

        // Create a new reader to configure beanDefinition
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                registry, this.sourceExtractor, this.resourceLoader, this.environment,
                this.importBeanNameGenerator, parser.getImportRegistry());
        }
        // Load the config class into the container, and finally call registerBeanDefinition()
        this.reader.loadBeanDefinitions(configClasses);
        // Add to the parsed list
        alreadyParsed.addAll(configClasses);
		
        candidates.clear();
        // Whether there is a new configuration class after parsing
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
            // The container now has a collection of bean definition names
            String[] newCandidateNames = registry.getBeanDefinitionNames();
            // The old bean definition collection
            Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
            // Store the parsed bean definition
            Set<String> alreadyParsedClasses = new HashSet<>();
            // Put what was just parsed into the parsed collection for this loop
            for (ConfigurationClass configurationClass : alreadyParsed) {
                alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
            }
            // Loop to check if there are any configuration classes in the container that have not been parsed, put them into the collection for the next loop to parse
            for (String candidateName : newCandidateNames) {
                if(! oldCandidateNames.contains(candidateName)) { BeanDefinition bd = registry.getBeanDefinition(candidateName);if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && ! alreadyParsedClasses.contains(bd.getBeanClassName())) { candidates.add(newBeanDefinitionHolder(bd, candidateName)); }}}// Replace the old collection of in-container bean definitionscandidateNames = newCandidateNames; }}while(! candidates.isEmpty());// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
    if(sbr ! =null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }

    // The metadata read factory is the cache factory, which clears the cache
    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        // Clear cache in externally provided MetadataReaderFactory; this is a no-op
        // for a shared cache since it'll be cleared by the ApplicationContext.
        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); }}Copy the code
  1. processConfigBeanDefinitions()Method After checking the configuration processing,configCandidatesIn the end, only the incoming configuration goes into the loop for real parsing.

The real parse method: parse()

// ConfigurationClassParser.java
public void parse(Set<BeanDefinitionHolder> configCandidates) {
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            // Annotation class AnnotatedBeanDefinition
            if (bd instanceof AnnotatedBeanDefinition) {
                parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
            }
            AbstractBeanDefinition abstract class AbstractBeanDefinition
            else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
            }
            else {
                // Common BeanDefinitionparse(bd.getBeanClassName(), holder.getBeanName()); }}catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); }}// Execute the found DeferredImportSelector
    this.deferredImportSelectorHandler.process(); } no matter which kind of type of BeanDefinition above, will eventually perform processConfigurationClass method.// ConfigurationClassParser.java
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    // Decide whether to skip, if there is an @Conditional annotation
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }

    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    // The configuration class has already been handled
    if(existingClass ! =null) {
    	// Check if @import is imported
    	// ConfigurationClass has a set of importedBy, which stores the classes imported via @import
    	// For example, if A imports B with the @import annotation, then B contains A
        if (configClass.isImported()) {
            if (existingClass.isImported()) {
            	// Merge the set sets of two configuration classes
                existingClass.mergeImportedBy(configClass);
            }
            // Otherwise ignore new imported config class; existing non-imported class overrides it.
            return;
        }
        else {
            // configClass was imported once via @import and then injected in a non-@import way
            this.configurationClasses.remove(configClass);
            this.knownSuperclasses.values().removeIf(configClass::equals); }}// Parse the annotations on the configuration class and do some checking
    SourceClass sourceClass = asSourceClass(configClass);
    do {
    	// Parse the attributes in the annotation and get the wrapper class for the annotation
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while(sourceClass ! =null);
	
    this.configurationClasses.put(configClass, configClass);
}
Copy the code

DoProcessConfigurationClas () method

DoProcessConfigurationClass method is mainly analytical annotation properties, and do some processing.

// ConfigurationClassParser.java
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {

    // Handle the @Component annotation to get the attributes in the annotation
    if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
        // Handle the inner class, or if the inner class is also an annotation class
        processMemberClasses(configClass, sourceClass);
    }

    // Process the @propertysource annotation
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) {
        if (this.environment instanceof ConfigurableEnvironment) {
            // Process metadata for @propertysource annotations
            processPropertySource(propertySource);
        }
        else {
            logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                        "]. Reason: Environment must implement ConfigurableEnvironment"); }}// Handle annotations for @ComponentScan
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    if(! componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
        for (AnnotationAttributes componentScan : componentScans) {
            // Parse to get the beanDefinition introduced by @ComponentScan
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // Check to see if there are any configuration classes
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                // Continue parsing if there are configurations
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); }}}}// Handle the @import annotation
    processImports(configClass, sourceClass, getImports(sourceClass), true);

    // Handle the @importResource annotation
    AnnotationAttributes importResource =
        AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
    if(importResource ! =null) {
        String[] resources = importResource.getStringArray("locations");
        Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
        for (String resource : resources) {
            String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); }}// a method to handle @bean annotations
    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    for (MethodMetadata methodMetadata : beanMethods) {
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }

    // The default method for handling interfaces
    processInterfaces(configClass, sourceClass);

    // Handle the parent class
    if (sourceClass.getMetadata().hasSuperClass()) {
        String superclass = sourceClass.getMetadata().getSuperClassName();
        if(superclass ! =null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) {
            this.knownSuperclasses.put(superclass, configClass);
            // Superclass found, return its annotation metadata and recurse
            returnsourceClass.getSuperClass(); }}// No superclass -> processing is complete
    return null;
}
Copy the code

Now I’m going to focus on processing @ComponentScan annotations,

AnnotationConfigUtils.attributesForRepeatableIt’s mainly analytic@ComponentScanProperty for later processing.

A way to parse @ComponentScan annotations

// ConfigurationClassParser.java
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    // Create a bean definition scanner
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

    // set the nameGenerator property, bean nameGenerator
    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
                                 BeanUtils.instantiateClass(generatorClass));
    
	// Set the scopedProxy property to generate a proxy class for the detected component
    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
    if(scopedProxyMode ! = ScopedProxyMode.DEFAULT) { scanner.setScopedProxyMode(scopedProxyMode); }else {
        // Set the scopeResolver property to handle the scope of the bean
        Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
        scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
    }
	// Set the resourcePattern property to filter component criteria, default "**/*.class
    scanner.setResourcePattern(componentScan.getString("resourcePattern"));
	
    // Set the includeFilters property to detect components that meet the Filter criterion, i.e., the type specified by FilterType
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
        for(TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addIncludeFilter(typeFilter); }}// Set the excludeFilters property to exclude components based on the criteria
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
        for(TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addExcludeFilter(typeFilter); }}// Set the lazyInit property to check whether the scanned component is lazily loaded
    boolean lazyInit = componentScan.getBoolean("lazyInit");
    if (lazyInit) {
        scanner.getBeanDefinitionDefaults().setLazyInit(true);
    }

    // Get the set scan packet path
    Set<String> basePackages = new LinkedHashSet<>();
    String[] basePackagesArray = componentScan.getStringArray("basePackages");
    for (String pkg : basePackagesArray) {
        String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
                                                               ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        Collections.addAll(basePackages, tokenized);
    }
    
    // Get the classes to scan
    for(Class<? > clazz : componentScan.getClassArray("basePackageClasses")) {
        basePackages.add(ClassUtils.getPackageName(clazz));
    }
    // If the package path is empty, set it to the package path of the configuration class
    if (basePackages.isEmpty()) {
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }

    // Filter abstract classes
    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false.false) {
        @Override
        protected boolean matchClassName(String className) {
            returndeclaringClass.equals(className); }});// Scan the components that precede the package path
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}
Copy the code

ScopedProxy is based on the CGLIB proxy. The main purpose of scopedProxy is to generate a reference proxy, such as a reference to another scoped bean in a singleton bean. If scopedProxy is not used, the reference held by the singleton bean will always be the same, i.e. injected at initialization.

Note that you cannot set the scopedProxy property for the singleton bean, otherwise it will run wrong.

doScan()

Scan @ComponentScan annotations set under package paths and specify concrete classes

// ClassPathBeanDefinitionScanner.java
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    // Save beanDefinition scanned from package path
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    // Iterate over the package path passed in
    for (String basePackage : basePackages) {
        // Scan the component under the package path for its beanDefinition
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        for (BeanDefinition candidate : candidates) {
            // Set scope for beanDefinition
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            // The abstract beanDefinition is processed
            if (candidate instanceof AbstractBeanDefinition) {
                // Set beanDefinition lazy load, initialization method, etc
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            // Handle the annotation beanDefinition
            if (candidate instanceof AnnotatedBeanDefinition) {
                // Set beanDefinition lazy load, initialization method, etc
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            // Check whether beanDefinition is already registered, and if so, whether it is the same
            if (checkCandidate(beanName, candidate)) {
                BbHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                / / set scopedProxy
                definitionHolder =
                    AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                // Register beanDefinition with the bean factory
                registerBeanDefinition(definitionHolder, this.registry); }}}return beanDefinitions;
}
Copy the code

findCandidateComponents()

Resolve the components scanned by @ComponentScans to BeanDefinition

// ClassPathScanningCandidateComponentProvider.java
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    // Access processing to THE CANDIDATE components of ENGINE in/Spring.ponents
    if (this.componentsIndex ! =null && indexSupportsIncludeFilters()) {
        return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    }
    else {
        returnscanCandidateComponents(basePackage); }}// ClassPathScanningCandidateComponentProvider.java
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
        // Process files in the package path to be scanned, default **/*.class
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        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 {
                    // Get the metadata reader
                    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    // Check the detected components
                    if (isCandidateComponent(metadataReader)) {
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setResource(resource);
                        sbd.setSource(resource);
                        if (isCandidateComponent(sbd)) {
                            if (debugEnabled) {
                                logger.debug("Identified candidate component class: " + resource);
                            }
                            candidates.add(sbd);
                        }
                        else {
                           // 省略......}}else {
                       // 省略......}}catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                        "Failed to read candidate component class: "+ resource, ex); }}else {
                // 省略......}}}catch (IOException ex) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    return candidates;
}
Copy the code

As you can see, only the metadata information and type of the beanDefinition are retrieved after processing. Some attributes have not been initialized yet, so the variable names of these BeanDefinitions are candidates.

2.2 postProcessBeanFactory

Processing spring BeanFactoryPostProcessor method and BeanDefinitionRegistryPostProcessor is substantially the same, just a few more other processing.

// PostProcessorRegistrationDelegate.java
private static void invokeBeanFactoryPostProcessors( Collection
        postProcessors, ConfigurableListableBeanFactory beanFactory) {

    for(BeanFactoryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanFactory(beanFactory); }}// ConfigurationClassPostProcessor.java
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)) {
        / / same as processing BeanDefinitionRegistryPostProcessor
        processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
    }
   
    // Generate a proxy for the @Configuration annotation class for enhancement
    enhanceConfigurationClasses(beanFactory);
    // beanFactory
    beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
Copy the code

EnhanceConfigurationClasses () method

// 
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
    // Loop all beanDefinitions in the bean factory
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        / / get BeanDefinition
        BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
        // Get the properties of the configuration class
        Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
        MethodMetadata methodMetadata = null;
        if (beanDef instanceof AnnotatedBeanDefinition) {
            // If it is an annotation beanDefinition, get the factory method metadata
            methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
        }
        if((configClassAttr ! =null|| methodMetadata ! =null) && beanDef instanceof AbstractBeanDefinition) {
            // Configuration class (full or lite) or a configuration-derived @Bean method
            // -> resolve bean class at this point...
            AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
            if(! abd.hasBeanClass()) {try {
                    abd.resolveBeanClass(this.beanClassLoader);
                }
                catch (Throwable ex) {
                    throw new IllegalStateException(
                        "Cannot load configuration class: "+ beanDef.getBeanClassName(), ex); }}}if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
            / / to omitconfigBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef); }}if (configBeanDefs.isEmpty()) {
        // nothing to enhance -> return immediately
        return;
    }

    // Classes annotated by @configuration are enhanced
    ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
        AbstractBeanDefinition beanDef = entry.getValue();
        // To set the property, @configuration annotated classes must generate proxy classesbeanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE); Class<? > configClass = beanDef.getBeanClass(); Class<? > enhancedClass = enhancer.enhance(configClass,this.beanClassLoader);
        if(configClass ! = enhancedClass) {if (logger.isTraceEnabled()) {
                logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                                           "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName())); } beanDef.setBeanClass(enhancedClass); }}}publicClass<? > enhance(Class<? > configClass,@Nullable ClassLoader classLoader) {
    if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
        / / to omit
        return configClass;
    }
   	// Create the proxy classClass<? > enhancedClass = createClass(newEnhancer(configClass, classLoader));/ / to omit
    return enhancedClass;
}

// ConfigurationClassEnhancer.java
private Enhancer newEnhancer(Class<? > configSuperClass,@Nullable ClassLoader classLoader) {
    Enhancer enhancer = new Enhancer();
    // Set the parent class
    enhancer.setSuperclass(configSuperClass);
    // Set the interface
    enhancer.setInterfaces(newClass<? >[] {EnhancedConfiguration.class});// Do not inherit the factory interface
    enhancer.setUseFactory(false);
    // Set up a custom extension of CGLIB to avoid conflicts between other libraries and Spring
    enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
	// Set the build policy,
	// A custom extension of CGLIB DefaultGeneratorStrategy that introduces a {@link BeanFactory} field.
    enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
    // Set the filter
    enhancer.setCallbackFilter(CALLBACK_FILTER);
    enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
    return enhancer;
}
Copy the code

2.3 Post-processing process