• spring源码分析之@ImportSelector、@Import、ImportResource工作原理分析


    1. @importSelector定义:

    /**
     * Interface to be implemented by types that determine which @{@link Configuration}
     * class(es) should be imported based on a given selection criteria, usually one or more
     * annotation attributes.
     *
     * <p>An {@link ImportSelector} may implement any of the following
     * {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective
     * methods will be called prior to {@link #selectImports}:
     * <ul>
     * <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
     * <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}</li>
     * <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}</li>
     * <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}</li>
     * </ul>
     *
     * <p>ImportSelectors are usually processed in the same way as regular {@code @Import}
     * annotations, however, it is also possible to defer selection of imports until all
     * {@code @Configuration} classes have been processed (see {@link DeferredImportSelector}
     * for details).
     *
     * @author Chris Beams
     * @since 3.1
     * @see DeferredImportSelector
     * @see Import
     * @see ImportBeanDefinitionRegistrar
     * @see Configuration
     */
    public interface ImportSelector {
    
        /**
         * Select and return the names of which class(es) should be imported based on
         * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
         */
        String[] selectImports(AnnotationMetadata importingClassMetadata);
    
    }

    实现线索:

    具体代码实现:

        private void processDeferredImportSelectors() {
            List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
            this.deferredImportSelectors = null;
            Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
    
            for (DeferredImportSelectorHolder deferredImport : deferredImports) {
                ConfigurationClass configClass = deferredImport.getConfigurationClass();
                try {
                    String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
                    processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
                }
                catch (BeanDefinitionStoreException ex) {
                    throw ex;
                }
                catch (Throwable ex) {
                    throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
                            configClass.getMetadata().getClassName() + "]", ex);
                }
            }
        }

    2、@Import和@ImportResource的实现如下:

    ConfigurationClassParser.java

    /**
         * Apply processing and build a complete {@link ConfigurationClass} by reading the
         * annotations, members and methods from the source class. This method can be called
         * multiple times as relevant sources are discovered.
         * @param configClass the configuration class being build
         * @param sourceClass a source class
         * @return the superclass, or {@code null} if none found or previously processed
         */
        protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
            // Recursively process any member (nested) classes first
            processMemberClasses(configClass, sourceClass);
    
            // Process any @PropertySource annotations
            for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
                    sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) {
                if (this.environment instanceof ConfigurableEnvironment) {
                    processPropertySource(propertySource);
                }
                else {
                    logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                            "]. Reason: Environment must implement ConfigurableEnvironment");
                }
            }
    
            // Process any @ComponentScan annotations
            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) {
                    // The config class is annotated with @ComponentScan -> perform the scan immediately
                    Set<BeanDefinitionHolder> scannedBeanDefinitions =
                            this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                    // Check the set of scanned definitions for any further config classes and parse recursively if necessary
                    for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
                            parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
                        }
                    }
                }
            }
    
            // Process any @Import annotations
            processImports(configClass, sourceClass, getImports(sourceClass), true);
    
            // Process any @ImportResource annotations
            if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
                AnnotationAttributes importResource =
                        AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
                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);
                }
            }
    
            // Process individual @Bean methods
            Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
            for (MethodMetadata methodMetadata : beanMethods) {
                configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
            }
    
            // Process default methods on interfaces
            processInterfaces(configClass, sourceClass);
    
            // Process superclass, if any
            if (sourceClass.getMetadata().hasSuperClass()) {
                String superclass = sourceClass.getMetadata().getSuperClassName();
                if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
                    this.knownSuperclasses.put(superclass, configClass);
                    // Superclass found, return its annotation metadata and recurse
                    return sourceClass.getSuperClass();
                }
            }
    
            // No superclass -> processing is complete
            return null;
        }

     3.三种方式:

    ImportSelector 
    ImportBeanDefinitionRegistrar 
    Configuration 

    ConfigurationClassParser.java

    private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
    
            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();
                            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 {
                                String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                                Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                                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);
                            configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                        }
                        else {
                            // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                            // process it as an @Configuration class
                            this.importStack.registerImport(
                                    currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                            processConfigurationClass(candidate.asConfigClass(configClass));
                        }
                    }
                }
                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();
                }
            }
        }
  • 相关阅读:
    Java.io.outputstream.PrintStream:打印流
    Codeforces 732F. Tourist Reform (Tarjan缩点)
    退役了
    POJ 3281 Dining (最大流)
    Light oj 1233
    Light oj 1125
    HDU 5521 Meeting (最短路)
    Light oj 1095
    Light oj 1044
    HDU 3549 Flow Problem (dinic模版 && isap模版)
  • 原文地址:https://www.cnblogs.com/davidwang456/p/6245635.html
Copyright © 2020-2023  润新知