zoukankan      html  css  js  c++  java
  • SpringBoot学习(三)探究Springboot自动装配

    目录

      什么是自动装配

      何时自动装配

      原理分析

      注:以下展示的代码springboot的版本为2.0.3版。因源码过长,大家选择展开代码 ㄟ( ▔, ▔ )ㄏ 

    什么是自动装配

      自动装配还是利用了SpringFactoriesLoader来加载META-INF/spring.factoires文件里所有配置的EnableAutoConfgruation,它会经过exclude和filter等操作,最终确定要装配的类

      流程:@Configuration 配置的Bean -> BeanFactory -> ImportSelector -> AutoConfigurationSelectImporter ->
         SpringFactoriesLoader -> META-INF/spring.factories->
         所有配置的@EnableAutoConfiguration -> @Configuration -> 收集好后注册到IOC容器里

    何时自动装配,过程是什么

      处理@Configuration的核心还是ConfigurationClassPostProcessor,这个类实现了BeanFactoryPostProcessor, 因此当AbstractApplicationContext执行refresh方法里的invokeBeanFactoryPostProcessors(beanFactory)方法时会执行自动装配

      通过:ConfigurationClassPostProcessor这个类中的 ConfigurationClassParser  parser()方法

      过程:refresh() -> 注册BeanFatoryPostProcessor  -> ConfigurationClassParser-> 内部类DeferredImportSelectorHolder
          -> DeferredImportSeletor -> AutoConfigurationImportSelector -> selectImports方法

    原理分析

    什么是自动装配?

      @EnableAutoConfiguration源码里import了EnableAutoConfigurationImportSelector这个类,

    EnableAutoConfiguration接口
    /*
     * Copyright 2012-2017 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.boot.autoconfigure;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
    import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    import org.springframework.core.io.support.SpringFactoriesLoader;
    
    /**
     * Enable auto-configuration of the Spring Application Context, attempting to guess and
     * configure beans that you are likely to need. Auto-configuration classes are usually
     * applied based on your classpath and what beans you have defined. For example, if you
     * have {@code tomcat-embedded.jar} on your classpath you are likely to want a
     * {@link TomcatServletWebServerFactory} (unless you have defined your own
     * {@link ServletWebServerFactory} bean).
     * <p>
     * When using {@link SpringBootApplication}, the auto-configuration of the context is
     * automatically enabled and adding this annotation has therefore no additional effect.
     * <p>
     * Auto-configuration tries to be as intelligent as possible and will back-away as you
     * define more of your own configuration. You can always manually {@link #exclude()} any
     * configuration that you never want to apply (use {@link #excludeName()} if you don't
     * have access to them). You can also exclude them via the
     * {@code spring.autoconfigure.exclude} property. Auto-configuration is always applied
     * after user-defined beans have been registered.
     * <p>
     * The package of the class that is annotated with {@code @EnableAutoConfiguration},
     * usually via {@code @SpringBootApplication}, has specific significance and is often used
     * as a 'default'. For example, it will be used when scanning for {@code @Entity} classes.
     * It is generally recommended that you place {@code @EnableAutoConfiguration} (if you're
     * not using {@code @SpringBootApplication}) in a root package so that all sub-packages
     * and classes can be searched.
     * <p>
     * Auto-configuration classes are regular Spring {@link Configuration} beans. They are
     * located using the {@link SpringFactoriesLoader} mechanism (keyed against this class).
     * Generally auto-configuration beans are {@link Conditional @Conditional} beans (most
     * often using {@link ConditionalOnClass @ConditionalOnClass} and
     * {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).
     *
     * @author Phillip Webb
     * @author Stephane Nicoll
     * @see ConditionalOnBean
     * @see ConditionalOnMissingBean
     * @see ConditionalOnClass
     * @see AutoConfigureAfter
     * @see SpringBootApplication
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    
        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    
        /**
         * Exclude specific auto-configuration classes such that they will never be applied.
         * @return the classes to exclude
         */
        Class<?>[] exclude() default {};
    
        /**
         * Exclude specific auto-configuration class names such that they will never be
         * applied.
         * @return the class names to exclude
         * @since 1.3.0
         */
        String[] excludeName() default {};
    
    }
    View Code

    但是该类在SpringBoot1.5.X版本已经过时了,因此我们看一下它的父类AutoConfigurationImportSelector。(2.0.3版直接引入了父类AutoConfigurationImportSelector)

    AutoConfigurationImportSelector类
    /*
     * Copyright 2012-2018 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.boot.autoconfigure;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.LinkedHashMap;
    import java.util.LinkedHashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.TimeUnit;
    import java.util.stream.Collectors;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.Aware;
    import org.springframework.beans.factory.BeanClassLoaderAware;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.NoSuchBeanDefinitionException;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.boot.context.properties.bind.Binder;
    import org.springframework.context.EnvironmentAware;
    import org.springframework.context.ResourceLoaderAware;
    import org.springframework.context.annotation.DeferredImportSelector;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.AnnotationAttributes;
    import org.springframework.core.env.ConfigurableEnvironment;
    import org.springframework.core.env.Environment;
    import org.springframework.core.io.ResourceLoader;
    import org.springframework.core.io.support.SpringFactoriesLoader;
    import org.springframework.core.type.AnnotationMetadata;
    import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
    import org.springframework.core.type.classreading.MetadataReaderFactory;
    import org.springframework.util.Assert;
    import org.springframework.util.ClassUtils;
    import org.springframework.util.StringUtils;
    
    /**
     * {@link DeferredImportSelector} to handle {@link EnableAutoConfiguration
     * auto-configuration}. This class can also be subclassed if a custom variant of
     * {@link EnableAutoConfiguration @EnableAutoConfiguration}. is needed.
     *
     * @author Phillip Webb
     * @author Andy Wilkinson
     * @author Stephane Nicoll
     * @author Madhura Bhave
     * @since 1.3.0
     * @see EnableAutoConfiguration
     */
    public class AutoConfigurationImportSelector
            implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
            BeanFactoryAware, EnvironmentAware, Ordered {
    
        private static final String[] NO_IMPORTS = {};
    
        private static final Log logger = LogFactory
                .getLog(AutoConfigurationImportSelector.class);
    
        private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
    
        private ConfigurableListableBeanFactory beanFactory;
    
        private Environment environment;
    
        private ClassLoader beanClassLoader;
    
        private ResourceLoader resourceLoader;
    
        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            }
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                    .loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            List<String> configurations = getCandidateConfigurations(annotationMetadata,
                    attributes);
            configurations = removeDuplicates(configurations);
            Set<String> exclusions = getExclusions(annotationMetadata, attributes);
            checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = filter(configurations, autoConfigurationMetadata);
            fireAutoConfigurationImportEvents(configurations, exclusions);
            return StringUtils.toStringArray(configurations);
        }
    
        @Override
        public Class<? extends Group> getImportGroup() {
            return AutoConfigurationGroup.class;
        }
    
        protected boolean isEnabled(AnnotationMetadata metadata) {
            if (getClass() == AutoConfigurationImportSelector.class) {
                return getEnvironment().getProperty(
                        EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
                        true);
            }
            return true;
        }
    
        /**
         * Return the appropriate {@link AnnotationAttributes} from the
         * {@link AnnotationMetadata}. By default this method will return attributes for
         * {@link #getAnnotationClass()}.
         * @param metadata the annotation metadata
         * @return annotation attributes
         */
        protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
            String name = getAnnotationClass().getName();
            AnnotationAttributes attributes = AnnotationAttributes
                    .fromMap(metadata.getAnnotationAttributes(name, true));
            Assert.notNull(attributes,
                    () -> "No auto-configuration attributes found. Is "
                            + metadata.getClassName() + " annotated with "
                            + ClassUtils.getShortName(name) + "?");
            return attributes;
        }
    
        /**
         * Return the source annotation class used by the selector.
         * @return the annotation class
         */
        protected Class<?> getAnnotationClass() {
            return EnableAutoConfiguration.class;
        }
    
        /**
         * Return the auto-configuration class names that should be considered. By default
         * this method will load candidates using {@link SpringFactoriesLoader} with
         * {@link #getSpringFactoriesLoaderFactoryClass()}.
         * @param metadata the source metadata
         * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
         * attributes}
         * @return a list of candidate configurations
         */
        protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
                AnnotationAttributes attributes) {
            List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
                    getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
            Assert.notEmpty(configurations,
                    "No auto configuration classes found in META-INF/spring.factories. If you "
                            + "are using a custom packaging, make sure that file is correct.");
            return configurations;
        }
    
        /**
         * Return the class used by {@link SpringFactoriesLoader} to load configuration
         * candidates.
         * @return the factory class
         */
        protected Class<?> getSpringFactoriesLoaderFactoryClass() {
            return EnableAutoConfiguration.class;
        }
    
        private void checkExcludedClasses(List<String> configurations,
                Set<String> exclusions) {
            List<String> invalidExcludes = new ArrayList<>(exclusions.size());
            for (String exclusion : exclusions) {
                if (ClassUtils.isPresent(exclusion, getClass().getClassLoader())
                        && !configurations.contains(exclusion)) {
                    invalidExcludes.add(exclusion);
                }
            }
            if (!invalidExcludes.isEmpty()) {
                handleInvalidExcludes(invalidExcludes);
            }
        }
    
        /**
         * Handle any invalid excludes that have been specified.
         * @param invalidExcludes the list of invalid excludes (will always have at least one
         * element)
         */
        protected void handleInvalidExcludes(List<String> invalidExcludes) {
            StringBuilder message = new StringBuilder();
            for (String exclude : invalidExcludes) {
                message.append("	- ").append(exclude).append(String.format("%n"));
            }
            throw new IllegalStateException(String
                    .format("The following classes could not be excluded because they are"
                            + " not auto-configuration classes:%n%s", message));
        }
    
        /**
         * Return any exclusions that limit the candidate configurations.
         * @param metadata the source metadata
         * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
         * attributes}
         * @return exclusions or an empty set
         */
        protected Set<String> getExclusions(AnnotationMetadata metadata,
                AnnotationAttributes attributes) {
            Set<String> excluded = new LinkedHashSet<>();
            excluded.addAll(asList(attributes, "exclude"));
            excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
            excluded.addAll(getExcludeAutoConfigurationsProperty());
            return excluded;
        }
    
        private List<String> getExcludeAutoConfigurationsProperty() {
            if (getEnvironment() instanceof ConfigurableEnvironment) {
                Binder binder = Binder.get(getEnvironment());
                return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class)
                        .map(Arrays::asList).orElse(Collections.emptyList());
            }
            String[] excludes = getEnvironment()
                    .getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
            return (excludes != null ? Arrays.asList(excludes) : Collections.emptyList());
        }
    
        private List<String> filter(List<String> configurations,
                AutoConfigurationMetadata autoConfigurationMetadata) {
            long startTime = System.nanoTime();
            String[] candidates = StringUtils.toStringArray(configurations);
            boolean[] skip = new boolean[candidates.length];
            boolean skipped = false;
            for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
                invokeAwareMethods(filter);
                boolean[] match = filter.match(candidates, autoConfigurationMetadata);
                for (int i = 0; i < match.length; i++) {
                    if (!match[i]) {
                        skip[i] = true;
                        skipped = true;
                    }
                }
            }
            if (!skipped) {
                return configurations;
            }
            List<String> result = new ArrayList<>(candidates.length);
            for (int i = 0; i < candidates.length; i++) {
                if (!skip[i]) {
                    result.add(candidates[i]);
                }
            }
            if (logger.isTraceEnabled()) {
                int numberFiltered = configurations.size() - result.size();
                logger.trace("Filtered " + numberFiltered + " auto configuration class in "
                        + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)
                        + " ms");
            }
            return new ArrayList<>(result);
        }
    
        protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
            return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
                    this.beanClassLoader);
        }
    
        protected final <T> List<T> removeDuplicates(List<T> list) {
            return new ArrayList<>(new LinkedHashSet<>(list));
        }
    
        protected final List<String> asList(AnnotationAttributes attributes, String name) {
            String[] value = attributes.getStringArray(name);
            return Arrays.asList(value != null ? value : new String[0]);
        }
    
        private void fireAutoConfigurationImportEvents(List<String> configurations,
                Set<String> exclusions) {
            List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
            if (!listeners.isEmpty()) {
                AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this,
                        configurations, exclusions);
                for (AutoConfigurationImportListener listener : listeners) {
                    invokeAwareMethods(listener);
                    listener.onAutoConfigurationImportEvent(event);
                }
            }
        }
    
        protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
            return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class,
                    this.beanClassLoader);
        }
    
        private void invokeAwareMethods(Object instance) {
            if (instance instanceof Aware) {
                if (instance instanceof BeanClassLoaderAware) {
                    ((BeanClassLoaderAware) instance)
                            .setBeanClassLoader(this.beanClassLoader);
                }
                if (instance instanceof BeanFactoryAware) {
                    ((BeanFactoryAware) instance).setBeanFactory(this.beanFactory);
                }
                if (instance instanceof EnvironmentAware) {
                    ((EnvironmentAware) instance).setEnvironment(this.environment);
                }
                if (instance instanceof ResourceLoaderAware) {
                    ((ResourceLoaderAware) instance).setResourceLoader(this.resourceLoader);
                }
            }
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory);
            this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
        }
    
        protected final ConfigurableListableBeanFactory getBeanFactory() {
            return this.beanFactory;
        }
    
        @Override
        public void setBeanClassLoader(ClassLoader classLoader) {
            this.beanClassLoader = classLoader;
        }
    
        protected ClassLoader getBeanClassLoader() {
            return this.beanClassLoader;
        }
    
        @Override
        public void setEnvironment(Environment environment) {
            this.environment = environment;
        }
    
        protected final Environment getEnvironment() {
            return this.environment;
        }
    
        @Override
        public void setResourceLoader(ResourceLoader resourceLoader) {
            this.resourceLoader = resourceLoader;
        }
    
        protected final ResourceLoader getResourceLoader() {
            return this.resourceLoader;
        }
    
        @Override
        public int getOrder() {
            return Ordered.LOWEST_PRECEDENCE - 1;
        }
    
        private static class AutoConfigurationGroup implements DeferredImportSelector.Group,
                BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
    
            private ClassLoader beanClassLoader;
    
            private BeanFactory beanFactory;
    
            private ResourceLoader resourceLoader;
    
            private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();
    
            @Override
            public void setBeanClassLoader(ClassLoader classLoader) {
                this.beanClassLoader = classLoader;
            }
    
            @Override
            public void setBeanFactory(BeanFactory beanFactory) {
                this.beanFactory = beanFactory;
            }
    
            @Override
            public void setResourceLoader(ResourceLoader resourceLoader) {
                this.resourceLoader = resourceLoader;
            }
    
            @Override
            public void process(AnnotationMetadata annotationMetadata,
                    DeferredImportSelector deferredImportSelector) {
                String[] imports = deferredImportSelector.selectImports(annotationMetadata);
                for (String importClassName : imports) {
                    this.entries.put(importClassName, annotationMetadata);
                }
            }
    
            @Override
            public Iterable<Entry> selectImports() {
                return sortAutoConfigurations().stream()
                        .map((importClassName) -> new Entry(this.entries.get(importClassName),
                                importClassName))
                        .collect(Collectors.toList());
            }
    
            private List<String> sortAutoConfigurations() {
                List<String> autoConfigurations = new ArrayList<>(this.entries.keySet());
                if (this.entries.size() <= 1) {
                    return autoConfigurations;
                }
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                        .loadMetadata(this.beanClassLoader);
                return new AutoConfigurationSorter(getMetadataReaderFactory(),
                        autoConfigurationMetadata).getInPriorityOrder(autoConfigurations);
            }
    
            private MetadataReaderFactory getMetadataReaderFactory() {
                try {
                    return this.beanFactory.getBean(
                            SharedMetadataReaderFactoryContextInitializer.BEAN_NAME,
                            MetadataReaderFactory.class);
                }
                catch (NoSuchBeanDefinitionException ex) {
                    return new CachingMetadataReaderFactory(this.resourceLoader);
                }
            }
    
        }
    
    }
    View Code

    该类实现了DeferredImportSelector接口,这个接口继承了ImportSelector。该接口主要是为了导入@Configuration的配置项。

    DeferredImportSelector接口
    /*
     * Copyright 2002-2018 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.annotation;
    
    import java.util.Objects;
    
    import org.springframework.core.type.AnnotationMetadata;
    import org.springframework.lang.Nullable;
    
    /**
     * A variation of {@link ImportSelector} that runs after all {@code @Configuration} beans
     * have been processed. This type of selector can be particularly useful when the selected
     * imports are {@code @Conditional}.
     *
     * <p>Implementations can also extend the {@link org.springframework.core.Ordered}
     * interface or use the {@link org.springframework.core.annotation.Order} annotation to
     * indicate a precedence against other {@link DeferredImportSelector}s.
     *
     * <p>Implementations may also provide an {@link #getImportGroup() import group} which
     * can provide additional sorting and filtering logic across different selectors.
     *
     * @author Phillip Webb
     * @author Stephane Nicoll
     * @since 4.0
     */
    public interface DeferredImportSelector extends ImportSelector {
    
        /**
         * Return a specific import group or {@code null} if no grouping is required.
         * @return the import group class or {@code null}
         */
        @Nullable
        default Class<? extends Group> getImportGroup() {
            return null;
        }
    
    
        /**
         * Interface used to group results from different import selectors.
         */
        interface Group {
    
            /**
             * Process the {@link AnnotationMetadata} of the importing @{@link Configuration}
             * class using the specified {@link DeferredImportSelector}.
             */
            void process(AnnotationMetadata metadata, DeferredImportSelector selector);
    
            /**
             * Return the {@link Entry entries} of which class(es) should be imported for this
             * group.
             */
            Iterable<Entry> selectImports();
    
            /**
             * An entry that holds the {@link AnnotationMetadata} of the importing
             * {@link Configuration} class and the class name to import.
             */
            class Entry {
    
                private final AnnotationMetadata metadata;
    
                private final String importClassName;
    
                public Entry(AnnotationMetadata metadata, String importClassName) {
                    this.metadata = metadata;
                    this.importClassName = importClassName;
                }
    
                /**
                 * Return the {@link AnnotationMetadata} of the importing
                 * {@link Configuration} class.
                 */
                public AnnotationMetadata getMetadata() {
                    return this.metadata;
                }
    
                /**
                 * Return the fully qualified name of the class to import.
                 */
                public String getImportClassName() {
                    return this.importClassName;
                }
    
                @Override
                public boolean equals(Object o) {
                    if (this == o) {
                        return true;
                    }
                    if (o == null || getClass() != o.getClass()) {
                        return false;
                    }
                    Entry entry = (Entry) o;
                    return Objects.equals(this.metadata, entry.metadata) &&
                            Objects.equals(this.importClassName, entry.importClassName);
                }
    
                @Override
                public int hashCode() {
                    return Objects.hash(this.metadata, this.importClassName);
                }
            }
        }
    
    }
    View Code
    ImportSelector接口
    /*
     * Copyright 2002-2013 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.annotation;
    
    import org.springframework.core.type.AnnotationMetadata;
    
    /**
     * 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);
    
    }
    View Code

      然后我们回头看AutoConfigurationImportSelector重写的selectImport方法,该方法刚开始会先判断是否进行自动装配,而后会从META-INF/spring-autoconfigure-metadata.properties读取元数据与元数据的相关属性

        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            }
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                    .loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            List<String> configurations = getCandidateConfigurations(annotationMetadata,
                    attributes);
            configurations = removeDuplicates(configurations);
            Set<String> exclusions = getExclusions(annotationMetadata, attributes);
            checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = filter(configurations, autoConfigurationMetadata);
            fireAutoConfigurationImportEvents(configurations, exclusions);
            return StringUtils.toStringArray(configurations);
        }

      紧接着会调用getCandidateConfigurations方法。这个方法里有个 SpringFactoryiesLoader, 它会读取META-INF/spring.factories下的EnableAutoConfiguration的配置

        /**
         * Return the auto-configuration class names that should be considered. By default
         * this method will load candidates using {@link SpringFactoriesLoader} with
         * {@link #getSpringFactoriesLoaderFactoryClass()}.
         * @param metadata the source metadata
         * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
         * attributes}
         * @return a list of candidate configurations
         */
        protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
                AnnotationAttributes attributes) {
            List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
                    getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
            Assert.notEmpty(configurations,
                    "No auto configuration classes found in META-INF/spring.factories. If you "
                            + "are using a custom packaging, make sure that file is correct.");
            return configurations;
        }
    
        /**
         * Return the class used by {@link SpringFactoriesLoader} to load configuration
         * candidates.
         * @return the factory class
         */
        protected Class<?> getSpringFactoriesLoaderFactoryClass() {
            return EnableAutoConfiguration.class;
        }

      紧接着在进行排除与过滤,进而得到需要装配的类。最后让所有配置在META-INF/spring.factories下的AutoConfigurationImportListener执行AutoConfigurationImportEvent事件
    所有配置的@EnableAutoConfiguration 收集好后注册到IOC容器里

        private void fireAutoConfigurationImportEvents(List<String> configurations,
                Set<String> exclusions) {
            List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
            if (!listeners.isEmpty()) {
                AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this,
                        configurations, exclusions);
                for (AutoConfigurationImportListener listener : listeners) {
                    invokeAwareMethods(listener);
                    listener.onAutoConfigurationImportEvent(event);
                }
            }
        }
    
        protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
            return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class,
                    this.beanClassLoader);
        }

    何时自动装配?

     上面只是确定最终要将哪些类进行自动装配,那么SpringBoot何时处理这些自动装配的类呢?下面我们简要的分析一下:

    AbstractApplicationContext的refresh方法:

      当AbstractApplicationContext执行refresh方法里的invokeBeanFactoryPostProcessors(beanFactory)方法时会执行自动装配

    AbstractApplicationContext类的refresh()方法
        @Override
        public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // Prepare this context for refreshing.
                prepareRefresh();
    
                // Tell the subclass to refresh the internal bean factory.
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // Prepare the bean factory for use in this context.
                prepareBeanFactory(beanFactory);
    
                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // Register bean processors that intercept bean creation.
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    onRefresh();
    
                    // Check for listener beans and register them.
                    registerListeners();
    
                    // Instantiate all remaining (non-lazy-init) singletons.
                    finishBeanFactoryInitialization(beanFactory);
    
                    // Last step: publish corresponding event.
                    finishRefresh();
                }
    
                catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                "cancelling refresh attempt: " + ex);
                    }
    
                    // Destroy already created singletons to avoid dangling resources.
                    destroyBeans();
    
                    // Reset 'active' flag.
                    cancelRefresh(ex);
    
                    // Propagate exception to caller.
                    throw ex;
                }
    
                finally {
                    // Reset common introspection caches in Spring's core, since we
                    // might not ever need metadata for singleton beans anymore...
                    resetCommonCaches();
                }
            }
        }
    View Code

      在这里是处理BeanFactoryPostProcessor的,那么我们在来看一下这个接口BeanDefinitionRegistryPostProcessor

    BeanDefinitionRegistryPostProcessor接口
    /*
     * Copyright 2002-2010 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.beans.factory.support;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    
    /**
     * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
     * the registration of further bean definitions <i>before</i> regular
     * BeanFactoryPostProcessor detection kicks in. In particular,
     * BeanDefinitionRegistryPostProcessor may register further bean definitions
     * which in turn define BeanFactoryPostProcessor instances.
     *
     * @author Juergen Hoeller
     * @since 3.0.1
     * @see org.springframework.context.annotation.ConfigurationClassPostProcessor
     */
    public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    
        /**
         * Modify the application context's internal bean definition registry after its
         * standard initialization. All regular bean definitions will have been loaded,
         * but no beans will have been instantiated yet. This allows for adding further
         * bean definitions before the next post-processing phase kicks in.
         * @param registry the bean definition registry used by the application context
         * @throws org.springframework.beans.BeansException in case of errors
         */
        void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
    
    }
    View Code

      该类又实现 BeanFactoryPostProcessor

    BeanFactoryPostProcessor接口
    /*
     * Copyright 2002-2016 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.beans.factory.config;
    
    import org.springframework.beans.BeansException;
    
    /**
     * Allows for custom modification of an application context's bean definitions,
     * adapting the bean property values of the context's underlying bean factory.
     *
     * <p>Application contexts can auto-detect BeanFactoryPostProcessor beans in
     * their bean definitions and apply them before any other beans get created.
     *
     * <p>Useful for custom config files targeted at system administrators that
     * override bean properties configured in the application context.
     *
     * <p>See PropertyResourceConfigurer and its concrete implementations
     * for out-of-the-box solutions that address such configuration needs.
     *
     * <p>A BeanFactoryPostProcessor may interact with and modify bean
     * definitions, but never bean instances. Doing so may cause premature bean
     * instantiation, violating the container and causing unintended side-effects.
     * If bean instance interaction is required, consider implementing
     * {@link BeanPostProcessor} instead.
     *
     * @author Juergen Hoeller
     * @since 06.07.2003
     * @see BeanPostProcessor
     * @see PropertyResourceConfigurer
     */
    @FunctionalInterface
    public interface BeanFactoryPostProcessor {
    
        /**
         * Modify the application context's internal bean factory after its standard
         * initialization. All bean definitions will have been loaded, but no beans
         * will have been instantiated yet. This allows for overriding or adding
         * properties even to eager-initializing beans.
         * @param beanFactory the bean factory used by the application context
         * @throws org.springframework.beans.BeansException in case of errors
         */
        void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
    
    }
    View Code

    ConfigurationClassPostProcessor 类

      处理@Configuration的核心还是ConfigurationClassPostProcessor。该类主要处理@Configuration注解的,它实现了BeanDefinitionRegistryPostProcessor,  那么也间接实现了BeanFactoryPostProcessor,代码如下:

    ConfigurationClassPostProcessor类
    /*
     * Copyright 2002-2018 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.annotation;
    
    import java.beans.PropertyDescriptor;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.LinkedHashMap;
    import java.util.LinkedHashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
    import org.springframework.beans.PropertyValues;
    import org.springframework.beans.factory.BeanClassLoaderAware;
    import org.springframework.beans.factory.BeanDefinitionStoreException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.config.BeanDefinitionHolder;
    import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
    import org.springframework.beans.factory.config.SingletonBeanRegistry;
    import org.springframework.beans.factory.parsing.FailFastProblemReporter;
    import org.springframework.beans.factory.parsing.PassThroughSourceExtractor;
    import org.springframework.beans.factory.parsing.ProblemReporter;
    import org.springframework.beans.factory.parsing.SourceExtractor;
    import org.springframework.beans.factory.support.AbstractBeanDefinition;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
    import org.springframework.beans.factory.support.BeanNameGenerator;
    import org.springframework.context.EnvironmentAware;
    import org.springframework.context.ResourceLoaderAware;
    import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration;
    import org.springframework.core.Ordered;
    import org.springframework.core.PriorityOrdered;
    import org.springframework.core.env.Environment;
    import org.springframework.core.env.StandardEnvironment;
    import org.springframework.core.io.DefaultResourceLoader;
    import org.springframework.core.io.ResourceLoader;
    import org.springframework.core.type.AnnotationMetadata;
    import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
    import org.springframework.core.type.classreading.MetadataReaderFactory;
    import org.springframework.lang.Nullable;
    import org.springframework.util.Assert;
    import org.springframework.util.ClassUtils;
    
    import static org.springframework.context.annotation.AnnotationConfigUtils.*;
    
    /**
     * {@link BeanFactoryPostProcessor} used for bootstrapping processing of
     * {@link Configuration @Configuration} classes.
     *
     * <p>Registered by default when using {@code <context:annotation-config/>} or
     * {@code <context:component-scan/>}. Otherwise, may be declared manually as
     * with any other BeanFactoryPostProcessor.
     *
     * <p>This post processor is {@link Ordered#HIGHEST_PRECEDENCE} as it is important
     * that any {@link Bean} methods declared in Configuration classes have their
     * respective bean definitions registered before any other BeanFactoryPostProcessor
     * executes.
     *
     * @author Chris Beams
     * @author Juergen Hoeller
     * @author Phillip Webb
     * @since 3.0
     */
    public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
            PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
    
        private static final String IMPORT_REGISTRY_BEAN_NAME =
                ConfigurationClassPostProcessor.class.getName() + ".importRegistry";
    
    
        private final Log logger = LogFactory.getLog(getClass());
    
        private SourceExtractor sourceExtractor = new PassThroughSourceExtractor();
    
        private ProblemReporter problemReporter = new FailFastProblemReporter();
    
        @Nullable
        private Environment environment;
    
        private ResourceLoader resourceLoader = new DefaultResourceLoader();
    
        @Nullable
        private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
    
        private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
    
        private boolean setMetadataReaderFactoryCalled = false;
    
        private final Set<Integer> registriesPostProcessed = new HashSet<>();
    
        private final Set<Integer> factoriesPostProcessed = new HashSet<>();
    
        @Nullable
        private ConfigurationClassBeanDefinitionReader reader;
    
        private boolean localBeanNameGeneratorSet = false;
    
        /* Using short class names as default bean names */
        private BeanNameGenerator componentScanBeanNameGenerator = new AnnotationBeanNameGenerator();
    
        /* Using fully qualified class names as default bean names */
        private BeanNameGenerator importBeanNameGenerator = new AnnotationBeanNameGenerator() {
            @Override
            protected String buildDefaultBeanName(BeanDefinition definition) {
                String beanClassName = definition.getBeanClassName();
                Assert.state(beanClassName != null, "No bean class name set");
                return beanClassName;
            }
        };
    
    
        @Override
        public int getOrder() {
            return Ordered.LOWEST_PRECEDENCE;  // within PriorityOrdered
        }
    
        /**
         * Set the {@link SourceExtractor} to use for generated bean definitions
         * that correspond to {@link Bean} factory methods.
         */
        public void setSourceExtractor(@Nullable SourceExtractor sourceExtractor) {
            this.sourceExtractor = (sourceExtractor != null ? sourceExtractor : new PassThroughSourceExtractor());
        }
    
        /**
         * Set the {@link ProblemReporter} to use.
         * <p>Used to register any problems detected with {@link Configuration} or {@link Bean}
         * declarations. For instance, an @Bean method marked as {@code final} is illegal
         * and would be reported as a problem. Defaults to {@link FailFastProblemReporter}.
         */
        public void setProblemReporter(@Nullable ProblemReporter problemReporter) {
            this.problemReporter = (problemReporter != null ? problemReporter : new FailFastProblemReporter());
        }
    
        /**
         * Set the {@link MetadataReaderFactory} to use.
         * <p>Default is a {@link CachingMetadataReaderFactory} for the specified
         * {@linkplain #setBeanClassLoader bean class loader}.
         */
        public void setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory) {
            Assert.notNull(metadataReaderFactory, "MetadataReaderFactory must not be null");
            this.metadataReaderFactory = metadataReaderFactory;
            this.setMetadataReaderFactoryCalled = true;
        }
    
        /**
         * Set the {@link BeanNameGenerator} to be used when triggering component scanning
         * from {@link Configuration} classes and when registering {@link Import}'ed
         * configuration classes. The default is a standard {@link AnnotationBeanNameGenerator}
         * for scanned components (compatible with the default in {@link ClassPathBeanDefinitionScanner})
         * and a variant thereof for imported configuration classes (using unique fully-qualified
         * class names instead of standard component overriding).
         * <p>Note that this strategy does <em>not</em> apply to {@link Bean} methods.
         * <p>This setter is typically only appropriate when configuring the post-processor as
         * a standalone bean definition in XML, e.g. not using the dedicated
         * {@code AnnotationConfig*} application contexts or the {@code
         * <context:annotation-config>} element. Any bean name generator specified against
         * the application context will take precedence over any value set here.
         * @since 3.1.1
         * @see AnnotationConfigApplicationContext#setBeanNameGenerator(BeanNameGenerator)
         * @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR
         */
        public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
            Assert.notNull(beanNameGenerator, "BeanNameGenerator must not be null");
            this.localBeanNameGeneratorSet = true;
            this.componentScanBeanNameGenerator = beanNameGenerator;
            this.importBeanNameGenerator = beanNameGenerator;
        }
    
        @Override
        public void setEnvironment(Environment environment) {
            Assert.notNull(environment, "Environment must not be null");
            this.environment = environment;
        }
    
        @Override
        public void setResourceLoader(ResourceLoader resourceLoader) {
            Assert.notNull(resourceLoader, "ResourceLoader must not be null");
            this.resourceLoader = resourceLoader;
            if (!this.setMetadataReaderFactoryCalled) {
                this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
            }
        }
    
        @Override
        public void setBeanClassLoader(ClassLoader beanClassLoader) {
            this.beanClassLoader = beanClassLoader;
            if (!this.setMetadataReaderFactoryCalled) {
                this.metadataReaderFactory = new CachingMetadataReaderFactory(beanClassLoader);
            }
        }
    
    
        /**
         * Derive further bean definitions from the configuration classes in the registry.
         */
        @Override
        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);
        }
    
        /**
         * Prepare the Configuration classes for servicing bean requests at runtime
         * by replacing them with CGLIB-enhanced subclasses.
         */
        @Override
        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);
            }
    
            enhanceConfigurationClasses(beanFactory);
            beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
        }
    
        /**
         * Build and validate a configuration model based on the registry of
         * {@link Configuration} classes.
         */
        public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
            List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
            String[] candidateNames = registry.getBeanDefinitionNames();
    
            for (String beanName : candidateNames) {
                BeanDefinition beanDef = registry.getBeanDefinition(beanName);
                if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                        ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                    }
                }
                else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                    configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
                }
            }
    
            // Return immediately if no @Configuration classes were found
            if (configCandidates.isEmpty()) {
                return;
            }
    
            // Sort by previously determined @Order value, if applicable
            configCandidates.sort((bd1, bd2) -> {
                int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
                int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
                return Integer.compare(i1, i2);
            });
    
            // Detect any custom bean name generation strategy supplied through the enclosing application context
            SingletonBeanRegistry sbr = null;
            if (registry instanceof SingletonBeanRegistry) {
                sbr = (SingletonBeanRegistry) registry;
                if (!this.localBeanNameGeneratorSet) {
                    BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
                    if (generator != null) {
                        this.componentScanBeanNameGenerator = generator;
                        this.importBeanNameGenerator = generator;
                    }
                }
            }
    
            if (this.environment == null) {
                this.environment = new StandardEnvironment();
            }
    
            // Parse each @Configuration class
            ConfigurationClassParser parser = new ConfigurationClassParser(
                    this.metadataReaderFactory, this.problemReporter, this.environment,
                    this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
            Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
            Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
            do {
                parser.parse(candidates);
                parser.validate();
    
                Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
                configClasses.removeAll(alreadyParsed);
    
                // Read the model and create bean definitions based on its content
                if (this.reader == null) {
                    this.reader = new ConfigurationClassBeanDefinitionReader(
                            registry, this.sourceExtractor, this.resourceLoader, this.environment,
                            this.importBeanNameGenerator, parser.getImportRegistry());
                }
                this.reader.loadBeanDefinitions(configClasses);
                alreadyParsed.addAll(configClasses);
    
                candidates.clear();
                if (registry.getBeanDefinitionCount() > candidateNames.length) {
                    String[] newCandidateNames = registry.getBeanDefinitionNames();
                    Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
                    Set<String> alreadyParsedClasses = new HashSet<>();
                    for (ConfigurationClass configurationClass : alreadyParsed) {
                        alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
                    }
                    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(new BeanDefinitionHolder(bd, candidateName));
                            }
                        }
                    }
                    candidateNames = 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());
            }
    
            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();
            }
        }
    
        /**
         * Post-processes a BeanFactory in search of Configuration class BeanDefinitions;
         * any candidates are then enhanced by a {@link ConfigurationClassEnhancer}.
         * Candidate status is determined by BeanDefinition attribute metadata.
         * @see ConfigurationClassEnhancer
         */
        public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
            Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
            for (String beanName : beanFactory.getBeanDefinitionNames()) {
                BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
                if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
                    if (!(beanDef instanceof AbstractBeanDefinition)) {
                        throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                                beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
                    }
                    else if (logger.isWarnEnabled() && beanFactory.containsSingleton(beanName)) {
                        logger.warn("Cannot enhance @Configuration bean definition '" + beanName +
                                "' since its singleton instance has been created too early. The typical cause " +
                                "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
                                "return type: Consider declaring such methods as 'static'.");
                    }
                    configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
                }
            }
            if (configBeanDefs.isEmpty()) {
                // nothing to enhance -> return immediately
                return;
            }
    
            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) {
                        Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
                        if (configClass != enhancedClass) {
                            if (logger.isDebugEnabled()) {
                                logger.debug(String.format("Replacing bean definition '%s' existing class '%s' with " +
                                        "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
                            }
                            beanDef.setBeanClass(enhancedClass);
                        }
                    }
                }
                catch (Throwable ex) {
                    throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
                }
            }
        }
    
    
        private static class ImportAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    
            private final BeanFactory beanFactory;
    
            public ImportAwareBeanPostProcessor(BeanFactory beanFactory) {
                this.beanFactory = beanFactory;
            }
    
            @Override
            public PropertyValues postProcessPropertyValues(
                    PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
    
                // Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
                // postProcessPropertyValues method attempts to autowire other configuration beans.
                if (bean instanceof EnhancedConfiguration) {
                    ((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
                }
                return pvs;
            }
    
            @Override
            public Object postProcessBeforeInitialization(Object bean, String beanName)  {
                if (bean instanceof ImportAware) {
                    ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
                    AnnotationMetadata importingClass = ir.getImportingClassFor(bean.getClass().getSuperclass().getName());
                    if (importingClass != null) {
                        ((ImportAware) bean).setImportMetadata(importingClass);
                    }
                }
                return bean;
            }
        }
    
    }
    View Code

      其关键代码为:postProcessBeanFactory和processConfigBeanDefinitions方法

      这里可以看到解析每一个@ConfigurationClass的关键类是:ConfigurationClassParser 会调用该类的parse方法

    ConfigurationClassParser类
    /*
     * Copyright 2002-2018 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.annotation;
    
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.lang.annotation.Annotation;
    import java.net.UnknownHostException;
    import java.util.ArrayDeque;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.Deque;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.LinkedHashMap;
    import java.util.LinkedHashSet;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import org.springframework.beans.BeanUtils;
    import org.springframework.beans.factory.BeanDefinitionStoreException;
    import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.config.BeanDefinitionHolder;
    import org.springframework.beans.factory.parsing.Location;
    import org.springframework.beans.factory.parsing.Problem;
    import org.springframework.beans.factory.parsing.ProblemReporter;
    import org.springframework.beans.factory.support.AbstractBeanDefinition;
    import org.springframework.beans.factory.support.BeanDefinitionReader;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.beans.factory.support.BeanNameGenerator;
    import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase;
    import org.springframework.context.annotation.DeferredImportSelector.Group;
    import org.springframework.core.NestedIOException;
    import org.springframework.core.OrderComparator;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.AnnotationAttributes;
    import org.springframework.core.annotation.AnnotationAwareOrderComparator;
    import org.springframework.core.annotation.AnnotationUtils;
    import org.springframework.core.env.CompositePropertySource;
    import org.springframework.core.env.ConfigurableEnvironment;
    import org.springframework.core.env.Environment;
    import org.springframework.core.env.MutablePropertySources;
    import org.springframework.core.env.PropertySource;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.ResourceLoader;
    import org.springframework.core.io.support.DefaultPropertySourceFactory;
    import org.springframework.core.io.support.EncodedResource;
    import org.springframework.core.io.support.PropertySourceFactory;
    import org.springframework.core.io.support.ResourcePropertySource;
    import org.springframework.core.type.AnnotationMetadata;
    import org.springframework.core.type.MethodMetadata;
    import org.springframework.core.type.StandardAnnotationMetadata;
    import org.springframework.core.type.classreading.MetadataReader;
    import org.springframework.core.type.classreading.MetadataReaderFactory;
    import org.springframework.core.type.filter.AssignableTypeFilter;
    import org.springframework.lang.Nullable;
    import org.springframework.util.Assert;
    import org.springframework.util.ClassUtils;
    import org.springframework.util.CollectionUtils;
    import org.springframework.util.LinkedMultiValueMap;
    import org.springframework.util.MultiValueMap;
    import org.springframework.util.StringUtils;
    
    /**
     * Parses a {@link Configuration} class definition, populating a collection of
     * {@link ConfigurationClass} objects (parsing a single Configuration class may result in
     * any number of ConfigurationClass objects because one Configuration class may import
     * another using the {@link Import} annotation).
     *
     * <p>This class helps separate the concern of parsing the structure of a Configuration
     * class from the concern of registering BeanDefinition objects based on the
     * content of that model (with the exception of {@code @ComponentScan} annotations which
     * need to be registered immediately).
     *
     * <p>This ASM-based implementation avoids reflection and eager class loading in order to
     * interoperate effectively with lazy class loading in a Spring ApplicationContext.
     *
     * @author Chris Beams
     * @author Juergen Hoeller
     * @author Phillip Webb
     * @author Sam Brannen
     * @author Stephane Nicoll
     * @since 3.0
     * @see ConfigurationClassBeanDefinitionReader
     */
    class ConfigurationClassParser {
    
        private static final PropertySourceFactory DEFAULT_PROPERTY_SOURCE_FACTORY = new DefaultPropertySourceFactory();
    
        private static final Comparator<DeferredImportSelectorHolder> DEFERRED_IMPORT_COMPARATOR =
                (o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getImportSelector(), o2.getImportSelector());
    
    
        private final Log logger = LogFactory.getLog(getClass());
    
        private final MetadataReaderFactory metadataReaderFactory;
    
        private final ProblemReporter problemReporter;
    
        private final Environment environment;
    
        private final ResourceLoader resourceLoader;
    
        private final BeanDefinitionRegistry registry;
    
        private final ComponentScanAnnotationParser componentScanParser;
    
        private final ConditionEvaluator conditionEvaluator;
    
        private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
    
        private final Map<String, ConfigurationClass> knownSuperclasses = new HashMap<>();
    
        private final List<String> propertySourceNames = new ArrayList<>();
    
        private final ImportStack importStack = new ImportStack();
    
        @Nullable
        private List<DeferredImportSelectorHolder> deferredImportSelectors;
    
    
        /**
         * Create a new {@link ConfigurationClassParser} instance that will be used
         * to populate the set of configuration classes.
         */
        public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
                ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
                BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {
    
            this.metadataReaderFactory = metadataReaderFactory;
            this.problemReporter = problemReporter;
            this.environment = environment;
            this.resourceLoader = resourceLoader;
            this.registry = registry;
            this.componentScanParser = new ComponentScanAnnotationParser(
                    environment, resourceLoader, componentScanBeanNameGenerator, registry);
            this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
        }
    
    
        public void parse(Set<BeanDefinitionHolder> configCandidates) {
            this.deferredImportSelectors = new LinkedList<>();
    
            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);
                }
            }
    
            processDeferredImportSelectors();
        }
    
        protected final void parse(@Nullable String className, String beanName) throws IOException {
            Assert.notNull(className, "No bean class name for configuration class bean definition");
            MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
            processConfigurationClass(new ConfigurationClass(reader, beanName));
        }
    
        protected final void parse(Class<?> clazz, String beanName) throws IOException {
            processConfigurationClass(new ConfigurationClass(clazz, beanName));
        }
    
        protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
            processConfigurationClass(new ConfigurationClass(metadata, beanName));
        }
    
        /**
         * Validate each {@link ConfigurationClass} object.
         * @see ConfigurationClass#validate
         */
        public void validate() {
            for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
                configClass.validate(this.problemReporter);
            }
        }
    
        public Set<ConfigurationClass> getConfigurationClasses() {
            return this.configurationClasses.keySet();
        }
    
    
        protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
            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);
                    }
                    // Otherwise ignore new imported config class; existing non-imported class overrides it.
                    return;
                }
                else {
                    // Explicit bean definition found, probably replacing an import.
                    // Let's remove the old one and go with the new one.
                    this.configurationClasses.remove(configClass);
                    this.knownSuperclasses.values().removeIf(configClass::equals);
                }
            }
    
            // Recursively process the configuration class and its superclass hierarchy.
            SourceClass sourceClass = asSourceClass(configClass);
            do {
                sourceClass = doProcessConfigurationClass(configClass, sourceClass);
            }
            while (sourceClass != null);
    
            this.configurationClasses.put(configClass, configClass);
        }
    
        /**
         * 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
         */
        @Nullable
        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 needed
                    for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                        BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                        if (bdCand == null) {
                            bdCand = holder.getBeanDefinition();
                        }
                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                            parse(bdCand.getBeanClassName(), holder.getBeanName());
                        }
                    }
                }
            }
    
            // Process any @Import annotations
            processImports(configClass, sourceClass, getImports(sourceClass), true);
    
            // Process any @ImportResource annotations
            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);
                }
            }
    
            // Process individual @Bean methods
            Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
            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 != null && !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;
        }
    
        /**
         * Register member (nested) classes that happen to be configuration classes themselves.
         */
        private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
            Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
            if (!memberClasses.isEmpty()) {
                List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
                for (SourceClass memberClass : memberClasses) {
                    if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
                            !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
                        candidates.add(memberClass);
                    }
                }
                OrderComparator.sort(candidates);
                for (SourceClass candidate : candidates) {
                    if (this.importStack.contains(configClass)) {
                        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
                    }
                    else {
                        this.importStack.push(configClass);
                        try {
                            processConfigurationClass(candidate.asConfigClass(configClass));
                        }
                        finally {
                            this.importStack.pop();
                        }
                    }
                }
            }
        }
    
        /**
         * Register default methods on interfaces implemented by the configuration class.
         */
        private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
            for (SourceClass ifc : sourceClass.getInterfaces()) {
                Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
                for (MethodMetadata methodMetadata : beanMethods) {
                    if (!methodMetadata.isAbstract()) {
                        // A default method or other concrete method on a Java 8+ interface...
                        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
                    }
                }
                processInterfaces(configClass, ifc);
            }
        }
    
        /**
         * Retrieve the metadata for all <code>@Bean</code> methods.
         */
        private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
            AnnotationMetadata original = sourceClass.getMetadata();
            Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
            if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
                // Try reading the class file via ASM for deterministic declaration order...
                // Unfortunately, the JVM's standard reflection returns methods in arbitrary
                // order, even between different runs of the same application on the same JVM.
                try {
                    AnnotationMetadata asm =
                            this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
                    Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
                    if (asmMethods.size() >= beanMethods.size()) {
                        Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
                        for (MethodMetadata asmMethod : asmMethods) {
                            for (MethodMetadata beanMethod : beanMethods) {
                                if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
                                    selectedMethods.add(beanMethod);
                                    break;
                                }
                            }
                        }
                        if (selectedMethods.size() == beanMethods.size()) {
                            // All reflection-detected methods found in ASM method set -> proceed
                            beanMethods = selectedMethods;
                        }
                    }
                }
                catch (IOException ex) {
                    logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
                    // No worries, let's continue with the reflection metadata we started with...
                }
            }
            return beanMethods;
        }
    
    
        /**
         * Process the given <code>@PropertySource</code> annotation metadata.
         * @param propertySource metadata for the <code>@PropertySource</code> annotation found
         * @throws IOException if loading a property source failed
         */
        private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
            String name = propertySource.getString("name");
            if (!StringUtils.hasLength(name)) {
                name = null;
            }
            String encoding = propertySource.getString("encoding");
            if (!StringUtils.hasLength(encoding)) {
                encoding = null;
            }
            String[] locations = propertySource.getStringArray("value");
            Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
            boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
    
            Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
            PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
                    DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
    
            for (String location : locations) {
                try {
                    String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
                    Resource resource = this.resourceLoader.getResource(resolvedLocation);
                    addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
                }
                catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
                    // Placeholders not resolvable or resource not found when trying to open it
                    if (ignoreResourceNotFound) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
                        }
                    }
                    else {
                        throw ex;
                    }
                }
            }
        }
    
        private void addPropertySource(PropertySource<?> propertySource) {
            String name = propertySource.getName();
            MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();
    
            if (this.propertySourceNames.contains(name)) {
                // We've already added a version, we need to extend it
                PropertySource<?> existing = propertySources.get(name);
                if (existing != null) {
                    PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource ?
                            ((ResourcePropertySource) propertySource).withResourceName() : propertySource);
                    if (existing instanceof CompositePropertySource) {
                        ((CompositePropertySource) existing).addFirstPropertySource(newSource);
                    }
                    else {
                        if (existing instanceof ResourcePropertySource) {
                            existing = ((ResourcePropertySource) existing).withResourceName();
                        }
                        CompositePropertySource composite = new CompositePropertySource(name);
                        composite.addPropertySource(newSource);
                        composite.addPropertySource(existing);
                        propertySources.replace(name, composite);
                    }
                    return;
                }
            }
    
            if (this.propertySourceNames.isEmpty()) {
                propertySources.addLast(propertySource);
            }
            else {
                String firstProcessed = this.propertySourceNames.get(this.propertySourceNames.size() - 1);
                propertySources.addBefore(firstProcessed, propertySource);
            }
            this.propertySourceNames.add(name);
        }
    
    
        /**
         * Returns {@code @Import} class, considering all meta-annotations.
         */
        private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
            Set<SourceClass> imports = new LinkedHashSet<>();
            Set<SourceClass> visited = new LinkedHashSet<>();
            collectImports(sourceClass, imports, visited);
            return imports;
        }
    
        /**
         * Recursively collect all declared {@code @Import} values. Unlike most
         * meta-annotations it is valid to have several {@code @Import}s declared with
         * different values; the usual process of returning values from the first
         * meta-annotation on a class is not sufficient.
         * <p>For example, it is common for a {@code @Configuration} class to declare direct
         * {@code @Import}s in addition to meta-imports originating from an {@code @Enable}
         * annotation.
         * @param sourceClass the class to search
         * @param imports the imports collected so far
         * @param visited used to track visited classes to prevent infinite recursion
         * @throws IOException if there is any problem reading metadata from the named class
         */
        private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
                throws IOException {
    
            if (visited.add(sourceClass)) {
                for (SourceClass annotation : sourceClass.getAnnotations()) {
                    String annName = annotation.getMetadata().getClassName();
                    if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
                        collectImports(annotation, imports, visited);
                    }
                }
                imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
            }
        }
    
        private void processDeferredImportSelectors() {
            List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
            this.deferredImportSelectors = null;
            if (deferredImports == null) {
                return;
            }
    
            deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
            Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
            Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
            for (DeferredImportSelectorHolder deferredImport : deferredImports) {
                Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
                DeferredImportSelectorGrouping grouping = groupings.computeIfAbsent(
                        (group == null ? deferredImport : group),
                        (key) -> new DeferredImportSelectorGrouping(createGroup(group)));
                grouping.add(deferredImport);
                configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
                        deferredImport.getConfigurationClass());
            }
            for (DeferredImportSelectorGrouping grouping : groupings.values()) {
                grouping.getImports().forEach((entry) -> {
                    ConfigurationClass configurationClass = configurationClasses.get(
                            entry.getMetadata());
                    try {
                        processImports(configurationClass, asSourceClass(configurationClass),
                                asSourceClasses(entry.getImportClassName()), false);
                    }
                    catch (BeanDefinitionStoreException ex) {
                        throw ex;
                    }
                    catch (Throwable ex) {
                        throw new BeanDefinitionStoreException(
                                "Failed to process import candidates for configuration class [" +
                                        configurationClass.getMetadata().getClassName() + "]", ex);
                    }
                });
            }
        }
    
        private Group createGroup(@Nullable Class<? extends Group> type) {
            Class<? extends Group> effectiveType = (type != null ? type
                    : DefaultDeferredImportSelectorGroup.class);
            Group group = BeanUtils.instantiateClass(effectiveType);
            ParserStrategyUtils.invokeAwareMethods(group,
                    ConfigurationClassParser.this.environment,
                    ConfigurationClassParser.this.resourceLoader,
                    ConfigurationClassParser.this.registry);
            return group;
        }
    
        private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                Collection<SourceClass> 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();
                            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();
                }
            }
        }
    
        private boolean isChainedImportOnStack(ConfigurationClass configClass) {
            if (this.importStack.contains(configClass)) {
                String configClassName = configClass.getMetadata().getClassName();
                AnnotationMetadata importingClass = this.importStack.getImportingClassFor(configClassName);
                while (importingClass != null) {
                    if (configClassName.equals(importingClass.getClassName())) {
                        return true;
                    }
                    importingClass = this.importStack.getImportingClassFor(importingClass.getClassName());
                }
            }
            return false;
        }
    
        ImportRegistry getImportRegistry() {
            return this.importStack;
        }
    
    
        /**
         * Factory method to obtain a {@link SourceClass} from a {@link ConfigurationClass}.
         */
        private SourceClass asSourceClass(ConfigurationClass configurationClass) throws IOException {
            AnnotationMetadata metadata = configurationClass.getMetadata();
            if (metadata instanceof StandardAnnotationMetadata) {
                return asSourceClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
            }
            return asSourceClass(metadata.getClassName());
        }
    
        /**
         * Factory method to obtain a {@link SourceClass} from a {@link Class}.
         */
        SourceClass asSourceClass(@Nullable Class<?> classType) throws IOException {
            if (classType == null) {
                return new SourceClass(Object.class);
            }
            try {
                // Sanity test that we can reflectively read annotations,
                // including Class attributes; if not -> fall back to ASM
                for (Annotation ann : classType.getAnnotations()) {
                    AnnotationUtils.validateAnnotation(ann);
                }
                return new SourceClass(classType);
            }
            catch (Throwable ex) {
                // Enforce ASM via class name resolution
                return asSourceClass(classType.getName());
            }
        }
    
        /**
         * Factory method to obtain {@link SourceClass}s from class names.
         */
        private Collection<SourceClass> asSourceClasses(String... classNames) throws IOException {
            List<SourceClass> annotatedClasses = new ArrayList<>(classNames.length);
            for (String className : classNames) {
                annotatedClasses.add(asSourceClass(className));
            }
            return annotatedClasses;
        }
    
        /**
         * Factory method to obtain a {@link SourceClass} from a class name.
         */
        SourceClass asSourceClass(@Nullable String className) throws IOException {
            if (className == null) {
                return new SourceClass(Object.class);
            }
            if (className.startsWith("java")) {
                // Never use ASM for core java types
                try {
                    return new SourceClass(ClassUtils.forName(className, this.resourceLoader.getClassLoader()));
                }
                catch (ClassNotFoundException ex) {
                    throw new NestedIOException("Failed to load class [" + className + "]", ex);
                }
            }
            return new SourceClass(this.metadataReaderFactory.getMetadataReader(className));
        }
    
    
        @SuppressWarnings("serial")
        private static class ImportStack extends ArrayDeque<ConfigurationClass> implements ImportRegistry {
    
            private final MultiValueMap<String, AnnotationMetadata> imports = new LinkedMultiValueMap<>();
    
            public void registerImport(AnnotationMetadata importingClass, String importedClass) {
                this.imports.add(importedClass, importingClass);
            }
    
            @Override
            @Nullable
            public AnnotationMetadata getImportingClassFor(String importedClass) {
                return CollectionUtils.lastElement(this.imports.get(importedClass));
            }
    
            @Override
            public void removeImportingClass(String importingClass) {
                for (List<AnnotationMetadata> list : this.imports.values()) {
                    for (Iterator<AnnotationMetadata> iterator = list.iterator(); iterator.hasNext();) {
                        if (iterator.next().getClassName().equals(importingClass)) {
                            iterator.remove();
                            break;
                        }
                    }
                }
            }
    
            /**
             * Given a stack containing (in order)
             * <ul>
             * <li>com.acme.Foo</li>
             * <li>com.acme.Bar</li>
             * <li>com.acme.Baz</li>
             * </ul>
             * return "[Foo->Bar->Baz]".
             */
            @Override
            public String toString() {
                StringBuilder builder = new StringBuilder("[");
                Iterator<ConfigurationClass> iterator = iterator();
                while (iterator.hasNext()) {
                    builder.append(iterator.next().getSimpleName());
                    if (iterator.hasNext()) {
                        builder.append("->");
                    }
                }
                return builder.append(']').toString();
            }
        }
    
    
        private static class DeferredImportSelectorHolder {
    
            private final ConfigurationClass configurationClass;
    
            private final DeferredImportSelector importSelector;
    
            public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) {
                this.configurationClass = configClass;
                this.importSelector = selector;
            }
    
            public ConfigurationClass getConfigurationClass() {
                return this.configurationClass;
            }
    
            public DeferredImportSelector getImportSelector() {
                return this.importSelector;
            }
        }
    
    
        private static class DeferredImportSelectorGrouping {
    
            private final DeferredImportSelector.Group group;
    
            private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();
    
            DeferredImportSelectorGrouping(Group group) {
                this.group = group;
            }
    
            public void add(DeferredImportSelectorHolder deferredImport) {
                this.deferredImports.add(deferredImport);
            }
    
            /**
             * Return the imports defined by the group.
             * @return each import with its associated configuration class
             */
            public Iterable<Group.Entry> getImports() {
                for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
                    this.group.process(deferredImport.getConfigurationClass().getMetadata(),
                            deferredImport.getImportSelector());
                }
                return this.group.selectImports();
            }
        }
    
    
        private static class DefaultDeferredImportSelectorGroup implements Group {
    
            private final List<Entry> imports = new ArrayList<>();
    
            @Override
            public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
                for (String importClassName : selector.selectImports(metadata)) {
                    this.imports.add(new Entry(metadata, importClassName));
                }
            }
    
            @Override
            public Iterable<Entry> selectImports() {
                return this.imports;
            }
        }
    
    
        /**
         * Simple wrapper that allows annotated source classes to be dealt with
         * in a uniform manner, regardless of how they are loaded.
         */
        private class SourceClass implements Ordered {
    
            private final Object source;  // Class or MetadataReader
    
            private final AnnotationMetadata metadata;
    
            public SourceClass(Object source) {
                this.source = source;
                if (source instanceof Class) {
                    this.metadata = new StandardAnnotationMetadata((Class<?>) source, true);
                }
                else {
                    this.metadata = ((MetadataReader) source).getAnnotationMetadata();
                }
            }
    
            public final AnnotationMetadata getMetadata() {
                return this.metadata;
            }
    
            @Override
            public int getOrder() {
                Integer order = ConfigurationClassUtils.getOrder(this.metadata);
                return (order != null ? order : Ordered.LOWEST_PRECEDENCE);
            }
    
            public Class<?> loadClass() throws ClassNotFoundException {
                if (this.source instanceof Class) {
                    return (Class<?>) this.source;
                }
                String className = ((MetadataReader) this.source).getClassMetadata().getClassName();
                return ClassUtils.forName(className, resourceLoader.getClassLoader());
            }
    
            public boolean isAssignable(Class<?> clazz) throws IOException {
                if (this.source instanceof Class) {
                    return clazz.isAssignableFrom((Class<?>) this.source);
                }
                return new AssignableTypeFilter(clazz).match((MetadataReader) this.source, metadataReaderFactory);
            }
    
            public ConfigurationClass asConfigClass(ConfigurationClass importedBy) throws IOException {
                if (this.source instanceof Class) {
                    return new ConfigurationClass((Class<?>) this.source, importedBy);
                }
                return new ConfigurationClass((MetadataReader) this.source, importedBy);
            }
    
            public Collection<SourceClass> getMemberClasses() throws IOException {
                Object sourceToProcess = this.source;
                if (sourceToProcess instanceof Class) {
                    Class<?> sourceClass = (Class<?>) sourceToProcess;
                    try {
                        Class<?>[] declaredClasses = sourceClass.getDeclaredClasses();
                        List<SourceClass> members = new ArrayList<>(declaredClasses.length);
                        for (Class<?> declaredClass : declaredClasses) {
                            members.add(asSourceClass(declaredClass));
                        }
                        return members;
                    }
                    catch (NoClassDefFoundError err) {
                        // getDeclaredClasses() failed because of non-resolvable dependencies
                        // -> fall back to ASM below
                        sourceToProcess = metadataReaderFactory.getMetadataReader(sourceClass.getName());
                    }
                }
    
                // ASM-based resolution - safe for non-resolvable classes as well
                MetadataReader sourceReader = (MetadataReader) sourceToProcess;
                String[] memberClassNames = sourceReader.getClassMetadata().getMemberClassNames();
                List<SourceClass> members = new ArrayList<>(memberClassNames.length);
                for (String memberClassName : memberClassNames) {
                    try {
                        members.add(asSourceClass(memberClassName));
                    }
                    catch (IOException ex) {
                        // Let's skip it if it's not resolvable - we're just looking for candidates
                        if (logger.isDebugEnabled()) {
                            logger.debug("Failed to resolve member class [" + memberClassName +
                                    "] - not considering it as a configuration class candidate");
                        }
                    }
                }
                return members;
            }
    
            public SourceClass getSuperClass() throws IOException {
                if (this.source instanceof Class) {
                    return asSourceClass(((Class<?>) this.source).getSuperclass());
                }
                return asSourceClass(((MetadataReader) this.source).getClassMetadata().getSuperClassName());
            }
    
            public Set<SourceClass> getInterfaces() throws IOException {
                Set<SourceClass> result = new LinkedHashSet<>();
                if (this.source instanceof Class) {
                    Class<?> sourceClass = (Class<?>) this.source;
                    for (Class<?> ifcClass : sourceClass.getInterfaces()) {
                        result.add(asSourceClass(ifcClass));
                    }
                }
                else {
                    for (String className : this.metadata.getInterfaceNames()) {
                        result.add(asSourceClass(className));
                    }
                }
                return result;
            }
    
            public Set<SourceClass> getAnnotations() throws IOException {
                Set<SourceClass> result = new LinkedHashSet<>();
                for (String className : this.metadata.getAnnotationTypes()) {
                    try {
                        result.add(getRelated(className));
                    }
                    catch (Throwable ex) {
                        // An annotation not present on the classpath is being ignored
                        // by the JVM's class loading -> ignore here as well.
                    }
                }
                return result;
            }
    
            public Collection<SourceClass> getAnnotationAttributes(String annType, String attribute) throws IOException {
                Map<String, Object> annotationAttributes = this.metadata.getAnnotationAttributes(annType, true);
                if (annotationAttributes == null || !annotationAttributes.containsKey(attribute)) {
                    return Collections.emptySet();
                }
                String[] classNames = (String[]) annotationAttributes.get(attribute);
                Set<SourceClass> result = new LinkedHashSet<>();
                for (String className : classNames) {
                    result.add(getRelated(className));
                }
                return result;
            }
    
            private SourceClass getRelated(String className) throws IOException {
                if (this.source instanceof Class) {
                    try {
                        Class<?> clazz = ((Class<?>) this.source).getClassLoader().loadClass(className);
                        return asSourceClass(clazz);
                    }
                    catch (ClassNotFoundException ex) {
                        // Ignore -> fall back to ASM next, except for core java types.
                        if (className.startsWith("java")) {
                            throw new NestedIOException("Failed to load class [" + className + "]", ex);
                        }
                        return new SourceClass(metadataReaderFactory.getMetadataReader(className));
                    }
                }
                return asSourceClass(className);
            }
    
            @Override
            public boolean equals(Object other) {
                return (this == other || (other instanceof SourceClass &&
                        this.metadata.getClassName().equals(((SourceClass) other).metadata.getClassName())));
            }
    
            @Override
            public int hashCode() {
                return this.metadata.getClassName().hashCode();
            }
    
            @Override
            public String toString() {
                return this.metadata.getClassName();
            }
        }
    
    
        /**
         * {@link Problem} registered upon detection of a circular {@link Import}.
         */
        private static class CircularImportProblem extends Problem {
    
            public CircularImportProblem(ConfigurationClass attemptedImport, Deque<ConfigurationClass> importStack) {
                super(String.format("A circular @Import has been detected: " +
                        "Illegal attempt by @Configuration class '%s' to import class '%s' as '%s' is " +
                        "already present in the current import stack %s", importStack.element().getSimpleName(),
                        attemptedImport.getSimpleName(), attemptedImport.getSimpleName(), importStack),
                        new Location(importStack.element().getResource(), attemptedImport.getMetadata()));
            }
        }
    
    }
    View Code

      注意parse方法的最后一句processDeferredImportSelectors方法,在这里将会对DeferredImportSelector进行处理,这样我们就和AutoConfigurationSelectImporter结合到一起了。

      注意processDeferredImportSelectors中的

         Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();这句代码

    这里deferredImport的类型为DeferredImportSelectorHolder:

        private static class DeferredImportSelectorHolder {
    
            private final ConfigurationClass configurationClass;
    
            private final DeferredImportSelector importSelector;
    
            public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) {
                this.configurationClass = configClass;
                this.importSelector = selector;
            }
    
            public ConfigurationClass getConfigurationClass() {
                return this.configurationClass;
            }
    
            public DeferredImportSelector getImportSelector() {
                return this.importSelector;
            }
        }
    View Code

      在这个内部类里持有了一个DeferredImportSelector的引用,至此将会执行自动装配的所有操作

    ㄟ( ▔, ▔ )ㄏ 

  • 相关阅读:
    纯快排
    Quick Sort(快速排序)
    归并排序 ALDS1_5_B:Merge Sort
    单调栈(POJ2559)
    Sequence
    Codeforces Round #503
    度度熊学队列
    Always Online hdu 6350
    Hills And Valleys
    Problem G. Depth-First Search
  • 原文地址:https://www.cnblogs.com/yanfeiLiu/p/9304049.html
Copyright © 2011-2022 走看看