03、容器创建准备前期工作

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class)

一:这行代码为我们做了什么?

首先AnnotationConfigApplicationContext 继承了GenericApplicationContext,所以AnnotationConfigApplicationContext 初始化的时候会走一下GenericApplicationContext的构造函数。去创建一个叫做this.beanFactory =new DefaultListableBeanFactory();这样的默认Bean工厂。

父类的无参构造器

public GenericApplicationContext() {
        //创建IOC容器
        this.beanFactory = new DefaultListableBeanFactory();
    }

这里为什么会new一个DefaultListableBeanFactory,因为,DefaultListableBeanFactory这个类是BeanFactory下实现功能最多的一个类。故此来构建它。

二、AnnotationConfigApplicationContext 构造方法都干了些什么?

首先看一下AnnotationConfigApplicationContext 的构造函数

/**
    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        //调用无参构造函数,会调用父类的无参构造器
        this();
        //注册配置类
        register(componentClasses);
        //容器刷新
        refresh();
    }

第一步:调用自己的无参构造

/**
 * Create a new AnnotationConfigApplicationContext that needs to be populated
 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
 */
    public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

这里有两个东西,第一个是AnnotatedBeanDefinitionReader。注解Bean定义的读取器,下图中的构造器有个getOrCreateEnvironment方法,是获取或者创建一个环境,并且加入缓存。

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    this(registry, getOrCreateEnvironment(registry));
}

回过头点开this,其中ConditionEvaluator 是@Condition注解的一个解析器。这个东西很重要。AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)很重要,重要的不能在重要,敲黑板,划重点。。。。。

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
        this.beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
        this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        Assert.notNull(environment, "Environment must not be null");
        this.registry = registry;
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, (ResourceLoader)null);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

点进去看一下

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
        registerAnnotationConfigProcessors(registry, (Object)null);
    }

registerAnnotationConfigProcessors是注解的配置处理器,点进去看一下public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, Object source) {}如下图可知,这个类主要的作用是,将各种各样不同类型的类定义,注入到容器当中,注意,此时是Bean的定义并不是真正的创建Bean的实例到IOC容器中。就比如,洗浴中心要招一批小姐姐,规定身高180以上,体重120以下,只是定义。仅此而已。如下图可知,第一个Bean的定义ConfigurationClassPostProcessor.class。它是通过internalAutowiredAnnotationProcessor名字进行判断,注入的类型是ConfigurationClassPostProcessor。

        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet(8);
        RootBeanDefinition def;
        if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor")) {
            def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));
        }

        if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalAutowiredAnnotationProcessor")) {
            def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));
        }

        if (jsr250Present && !registry.containsBeanDefinition("org.springframework.context.annotation.internalCommonAnnotationProcessor")) {
            def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalCommonAnnotationProcessor"));
        }

通过如下代码把BeanDefinition注册到容器中去:

beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));

还有如下下图所示,是解析Autowired自动配的

        if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalAutowiredAnnotationProcessor")) {
            def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));
        }

总结:
registerAnnotationConfigProcessors(registry, (Object)null);的作用就是处理各种内部的组件。比如,AutoWired、Required、jsr250标准,JPA等等等。。。Bean定义它是用来描述Bean的,是否是懒加载等等等。

回过头在看看第二个东西AnnotationConfigApplicationContext(类路径下Bean扫描器),它的构造方法中的第二句话this.scanner =new ClassPathBeanDefinitionScanner(this);这句话就比较牛逼了。

如下图所示,我们一直进入方法最后一层在类:ClassPathBeanDefinitionScanner下的ClassPathBeanDefinitionScanner方法中可以看到useDefaultFilters为true执行this.registerDefaultFilters();加载默认的配置策略。这也是之前的文章讲过的。在包扫描中如果使用includeFilters包含条件的话如果useDefaultFilters设为false就只会采用自定义的包扫描规则,如果为true是全量加载。

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) {
        this.beanDefinitionDefaults = new BeanDefinitionDefaults();
        this.beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
        this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
        this.includeAnnotationConfig = true;
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;
        if (useDefaultFilters) {
            this.registerDefaultFilters();
        }

        this.setEnvironment(environment);
        this.setResourceLoader(resourceLoader);
    }

进入this.registerDefaultFilters()方法中
如下图所示,我的默认扫描规则是包含@Component注解的类。比如@Controller、比如@Service、比如@Confingration等等等等注解,如果不符合JSR-250、JSR-330标准就会抛出异常。

protected void registerDefaultFilters() {
        this.includeFilters.add(new AnnotationTypeFilter(Component.class));
        ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();

        try {
            this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.annotation.ManagedBean", cl), false));
            this.logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
        } catch (ClassNotFoundException var4) {
            ;
        }

        try {
            this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.inject.Named", cl), false));
            this.logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
        } catch (ClassNotFoundException var3) {
            ;
        }

    }

至此如下图的两端代码分析结束,第一个的主要作用是,注册内部的组件(比如:注解配置的处理器)Bean定义到容器中。第二个是扫描策略。

public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

第二步:第二个方法this.register(annotatedClasses);

/**
    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        //调用无参构造函数,会调用父类的无参构造器
        this();
        //注册配置类
        register(componentClasses);
        //容器刷新
        refresh();
    }

抛出结论:这段代码就是将我们自己传入进来的MainConfig类注册到容器中去。如以下代码所示,进入方法最后找到类AnnotatedBeanDefinitionReader中的registerBean方法。前面大概的意思就是说看我们的类上有没有@Primary、@Lazy、这些个东西。最后通过BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);这个方法,将我们的自己配置的类(跟容器内部的类区别开)注册到容器中。

    private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
        if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            abd.setInstanceSupplier(supplier);
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
            abd.setScope(scopeMetadata.getScopeName());
            String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);
            AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
            int var10;
            int var11;
            if (qualifiers != null) {
                Class[] var9 = qualifiers;
                var10 = qualifiers.length;

                for(var11 = 0; var11 < var10; ++var11) {
                    Class<? extends Annotation> qualifier = var9[var11];
                    if (Primary.class == qualifier) {
                        abd.setPrimary(true);
                    } else if (Lazy.class == qualifier) {
                        abd.setLazyInit(true);
                    } else {
                        abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                    }
                }
            }

            if (customizers != null) {
                BeanDefinitionCustomizer[] var13 = customizers;
                var10 = customizers.length;

                for(var11 = 0; var11 < var10; ++var11) {
                    BeanDefinitionCustomizer customizer = var13[var11];
                    customizer.customize(abd);
                }
            }

            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
            definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
        }
    }

以上this()、register(componentClasses)这两个方法分析完毕。

三:this.refresh()

最重要,也是最难理解的一个方法。无论是Spring还是SpringBoot都是通过这个方法去带动的。故此非常非常之重要。并且这里面的功能多的吓死人。下面逐一分析。

    public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }
1,上面说过ConfigurationClassPostProcessor这个类非常的重要,一定要记住它。点进来看一下,如下图所示。他是BeanDefinitionRegistryPostProcessor类型,我们先记住这个接口
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
    public static final AnnotationBeanNameGenerator IMPORT_BEAN_NAME_GENERATOR = new FullyQualifiedAnnotationBeanNameGenerator();
    private static final String IMPORT_REGISTRY_BEAN_NAME = ConfigurationClassPostProcessor.class.getName() + ".importRegistry";
    private final Log logger = LogFactory.getLog(this.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;
    private BeanNameGenerator componentScanBeanNameGenerator;
    private BeanNameGenerator importBeanNameGenerator;
}
2,回到refresh()方法中来,看一下如下图所示,调用了一个Bean工厂的后置处理器invokeBeanFactoryPostProcessors(beanFactory);
3,点进这个方法可以看一下,如下图所示,看第一个if判断的是beanFactory是不是Bean的注册器。其实这个 beanFactory就是我们一开始构建的那个DefaultListableBeanFactory类。那么点进这个类,会发现它属于bean的注册器。
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
        Set<String> processedBeans = new HashSet();
        ArrayList regularPostProcessors;
        ArrayList registryProcessors;
        int var9;
        ArrayList currentRegistryProcessors;
        String[] postProcessorNames;
        if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
            regularPostProcessors = new ArrayList();
            registryProcessors = new ArrayList();
            Iterator var6 = beanFactoryPostProcessors.iterator();

            while(var6.hasNext()) {
                BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var6.next();
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor)postProcessor;
                    registryProcessor.postProcessBeanDefinitionRegistry(registry);
                    registryProcessors.add(registryProcessor);
                } else {
                    regularPostProcessors.add(postProcessor);
                }
            }
    }
}

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable

4,既然是Bean的注册器,那么就会进入第一个if判断,然后将beanFactory转成Bean的注册器,下面有两个list。第一个list可以解释为普通的PostProcessors,就是非BeanDefinitionRegistryPostProcessor类型的list。此时看while循环,这个循环根本就不会进来,因为传入的beanFactoryPostProcessors是一个半成品,并未有值。是一个空对象而已。while循环里只是做了,对两种类型的分类。并且放到regularPostProcessors和registryProcessors里面去。
if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
            regularPostProcessors = new ArrayList();
            registryProcessors = new ArrayList();
            Iterator var6 = beanFactoryPostProcessors.iterator();

            while(var6.hasNext()) {
                BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var6.next();
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor)postProcessor;
                    registryProcessor.postProcessBeanDefinitionRegistry(registry);
                    registryProcessors.add(registryProcessor);
                } else {
                    regularPostProcessors.add(postProcessor);
                }
            }
5,再往下看代码,如图所示,红框1内表示创建一个(当前正在注册的一个处理器)。再往下看,红框2,实际上postProcessorNames数组就是我们之前在this()中加载的Bean的注册器BeanDefinitionRegistryPostProcessor。红框三中的currentRegistryProcessors.add表示往容器中第一次调用,放入了一个Bean并且放入单例缓存池中具体细节其他章节阐述。processedBeans.add(ppName);这句话代表的是将Bean的注册器放入方法第一行定义的Set中。其次后面的代码不重要,重要的是invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);这句话
6,如果没invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);这句话,我们自定义的Bean根本就不会被注册进来。点击进入方法内。可以看到postProcessors他的类型就是前面讲的最重要的那个类型ConfigurationClassPostProcessor

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {

private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
        Iterator var2 = postProcessors.iterator();

        while(var2.hasNext()) {
            BeanDefinitionRegistryPostProcessor postProcessor = (BeanDefinitionRegistryPostProcessor)var2.next();
            postProcessor.postProcessBeanDefinitionRegistry(registry);
        }

    }
7,同样点进去看看方法内,找到ConfigurationClassPostProcessor类中postProcessBeanDefinitionRegistry方法看看如何做的。我们主要看最后一行,处理配置Bean定义信息。直接点进去
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);
        } else if (this.factoriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
        } else {
            this.registriesPostProcessed.add(registryId);
            this.processConfigBeanDefinitions(registry);
        }
    }
9,看下图中第二个红框内的代码,其他的看不懂不要紧,但至少能看懂两个东西,第一个是包扫描的生成器,起一个名字。第二个通过import注解导入的也要起个名字。
            //@Order注解的排序
            configCandidates.sort((bd1, bd2) -> {
                int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
                int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
                return Integer.compare(i1, i2);
            });
            SingletonBeanRegistry sbr = null;
            if (registry instanceof SingletonBeanRegistry) {
                sbr = (SingletonBeanRegistry)registry;
                if (!this.localBeanNameGeneratorSet) {
                    BeanNameGenerator generator = (BeanNameGenerator)sbr.getSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator");
                    if (generator != null) {
                        this.componentScanBeanNameGenerator = generator;
                        this.importBeanNameGenerator = generator;
                    }
                }
            }

10,接着往下看,如下图所示通过注释可知,这段代码是对Bean的配置类的解析,创建一个Bean的解析器。这里使用了一个do-while循环,其中candidates集合表示候选的,alreadyParsed集合表示已解析的,但是长度设为了1.其作用就是使用了do-while循环,肯定先执行一次。节省内存。那么最核心的解析代码是parser.parse(candidates);点进去看一下。
            ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);
            Set<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);
            HashSet alreadyParsed = new HashSet(configCandidates.size());

            do {
                parser.parse(candidates);
                parser.validate();
                Set<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());
                configClasses.removeAll(alreadyParsed);
                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();
                    Iterator var12 = alreadyParsed.iterator();

                    while(var12.hasNext()) {
                        ConfigurationClass configurationClass = (ConfigurationClass)var12.next();
                        alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
                    }

                    String[] var23 = newCandidateNames;
                    int var24 = newCandidateNames.length;

                    for(int var14 = 0; var14 < var24; ++var14) {
                        String candidateName = var23[var14];
                        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());
11,点进parse方法,我们的MainClass是通过注解的形式定义的。所以走AnnotatedBeanDefinition条件的parse方法。点进去。
public void parse(Set<BeanDefinitionHolder> configCandidates) {
        Iterator var2 = configCandidates.iterator();

        while(var2.hasNext()) {
            BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
            BeanDefinition bd = holder.getBeanDefinition();

            try {
                if (bd instanceof AnnotatedBeanDefinition) {
                    this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
                } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
                    this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
                } else {
                    this.parse(bd.getBeanClassName(), holder.getBeanName());
                }
            } catch (BeanDefinitionStoreException var6) {
                throw var6;
            } catch (Throwable var7) {
                throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
            }
        }

        this.deferredImportSelectorHandler.process();
    }
12,解析配置类
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
        this.processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
    }
13,点进去以后,其他的都不用看直接看下面,doProcessConfigurationClass这个代码。为什么?因为Spring真正干活的类,基本都是以do开头的方法名(小技巧)点进去
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
        if (!this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
            ConfigurationClass existingClass = (ConfigurationClass)this.configurationClasses.get(configClass);
            if (existingClass != null) {
                if (configClass.isImported()) {
                    if (existingClass.isImported()) {
                        existingClass.mergeImportedBy(configClass);
                    }

                    return;
                }

                this.configurationClasses.remove(configClass);
                this.knownSuperclasses.values().removeIf(configClass::equals);
            }

            ConfigurationClassParser.SourceClass sourceClass = this.asSourceClass(configClass, filter);

            do {
                sourceClass = this.doProcessConfigurationClass(configClass, sourceClass, filter);
            } while(sourceClass != null);

            this.configurationClasses.put(configClass, configClass);
        }
    }
14,点进去我们发现AnnotationConfigUtils.attributesForRepeatable这个方法,他是用来进行解析我们的Component注解的。将这个注解解析成一个对象如下图所示。
protected final ConfigurationClassParser.SourceClass doProcessConfigurationClass(ConfigurationClass configClass, ConfigurationClassParser.SourceClass sourceClass, Predicate<String> filter) throws IOException {
        if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
            this.processMemberClasses(configClass, sourceClass, filter);
        }

        Iterator var4 = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, PropertySource.class).iterator();

        AnnotationAttributes importResource;
        while(var4.hasNext()) {
            importResource = (AnnotationAttributes)var4.next();
            if (this.environment instanceof ConfigurableEnvironment) {
                this.processPropertySource(importResource);
            } else {
                this.logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment");
            }
        }

        Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
        if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
            Iterator var14 = componentScans.iterator();

            while(var14.hasNext()) {
                AnnotationAttributes componentScan = (AnnotationAttributes)var14.next();
                Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                Iterator var8 = scannedBeanDefinitions.iterator();

                while(var8.hasNext()) {
                    BeanDefinitionHolder holder = (BeanDefinitionHolder)var8.next();
                    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                    if (bdCand == null) {
                        bdCand = holder.getBeanDefinition();
                    }

                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                        this.parse(bdCand.getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }

        this.processImports(configClass, sourceClass, this.getImports(sourceClass), filter, true);
        importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
        if (importResource != null) {
            String[] resources = importResource.getStringArray("locations");
            Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
            String[] var20 = resources;
            int var22 = resources.length;

            for(int var23 = 0; var23 < var22; ++var23) {
                String resource = var20[var23];
                String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
                configClass.addImportedResource(resolvedResource, readerClass);
            }
        }

        Set<MethodMetadata> beanMethods = this.retrieveBeanMethodMetadata(sourceClass);
        Iterator var18 = beanMethods.iterator();

        while(var18.hasNext()) {
            MethodMetadata methodMetadata = (MethodMetadata)var18.next();
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
        }

        this.processInterfaces(configClass, sourceClass);
        if (sourceClass.getMetadata().hasSuperClass()) {
            String superclass = sourceClass.getMetadata().getSuperClassName();
            if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
                this.knownSuperclasses.put(superclass, configClass);
                return sourceClass.getSuperClass();
            }
        }

        return null;
    }
15,下面这段代码才是真正的对你的包扫描进行解析。上面那点,就好比,你发现了她是一个小姐姐,下面红框下的代码才是真正的对这个小姐姐进行分析,底盘扎实不扎实,发动机是否好用,变速箱是否换挡顺畅等等等一系列的信息。然后我们直接点进parse方法看一下
        if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
            Iterator var14 = componentScans.iterator();

            while(var14.hasNext()) {
                AnnotationAttributes componentScan = (AnnotationAttributes)var14.next();
                Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                Iterator var8 = scannedBeanDefinitions.iterator();

                while(var8.hasNext()) {
                    BeanDefinitionHolder holder = (BeanDefinitionHolder)var8.next();
                    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                    if (bdCand == null) {
                        bdCand = holder.getBeanDefinition();
                    }

                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                        this.parse(bdCand.getBeanClassName(), holder.getBeanName());
                    }
                }
            }
        }

Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

16,进入parse方法以后可以看到创建了一个扫描器。ClassPathBeanDefinitionScanner scanner =new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);然后,把上面解析的Component的值搂出来,逐一的给扫描器赋值进行初始化,真正干活的方法是最后的的这句:return scanner.doScan(StringUtils.toStringArray(basePackages));
17,通过下面的代码可知找到候选的一个组件。并且给我们拼接路径,找到这个包下所有子包的类,并且转换成Resource,并且里面存储的就是我们自己想要的组件。然后循环resource,判断是不是可读的,然后转换成一个原信息的读取器。到这里仅仅是将我们的Bean定义扫描到容器中去,并不是Bean的实例化。接着判断是否有包含或者排除的组件。接下来往下执行,如果遇到@Controller的组件,就会进行赋值。因为@Controller是可读的。此方法执行完毕以后回到doScan方法。进行循环


18,此时可以看到容器中并没有我们自己的组件,但是解析包扫描是找到的。然后接着往下看。原来是6个。现在还是6个
19,执行完registerBeanDefinition(definitionHolder, this.registry);注册Bean扫描器以后我们自己定义的组件就被扫描出来了。doScan执行完以后回到this.componentScanParser.parse这个地方。
20,在this.componentScanParser.parse的最下面又执行了一次parse,它作用是扫描比如在@Controller注解上有没有其他ComponentScan注解。正常的逻辑是不会有的。所以这个功能有点儿多余,不清楚为什么要这么设计。
21,代码继续往下走,执行这句话processImports。解析完可读的注解以后,在继续扫描类上面有没有import注解,如果有,就进去,并且找到import注解的value值。并且判断是否是导入的ImportSelector或者是ImportBeanDefinitionRegistrar。或者是DeferredImportSelector这种类型(这个东西很重要,自动注入,SpringBoot进行自动注入就是通过这个东西进行处理的)进行保存。保存之后就会有调用
22,processImports执行完以后往下看找到// Process individual @Bean methods,点击去之后发现,这个段代码的意思是,是解析@Bean标注的方法。最后执行完,回到parse方法。
23,这是我们新扫描出来的两个Bean的定义接着往下看
24,这个方法很重要。如果说在你的@Bean注解标注的方法内创建了一个类的实例,在未执行此方法的时候,那么那个实例是不会被加入到Bean定义注册器的,只有执行了这个方法以后才会在Bean的注册器中被注册。可以推断,这个方法就是用来将@Bean标注的方法内实例化的对象搂出来,放入Bean自定义的注册器中。并且如果是Import导入的类,也会将该类加入Bean的自定注册器中去,点开源码看。
25,this.reader.loadBeanDefinitions(configClasses);点开源码发现。通过import注解导入的类会通过红框内的方法进行注册,点进去看一下
26,进入这个方法以后,这个方法获取了你的方法名,这也是为什么Bean的依赖注入如果不指定别名,就是默认的方法名的原因。还进行了一系列的判断,接着往下看。
27,在方法的最后调用了this.registry.registerBeanDefinition(beanName, beanDefToRegister);方法。这段代码最关键。执行完以后会发现,@Bean注解标注的方法内,如果通过new关键字实例化的对象,此时已经被加入Bean定义注册器当中了。是不是很神奇?
image

28,回过头总结一下

  • parser.parse(candidates);这句话仅仅是注册包扫描的。
  • this.reader.loadBeanDefinitions(configClasses);这段代码是加载通过@import、@ Bean倒进来的。同理,SpringBoot也是通过这个东东来扫描各大装配种类的。

后面的代码是判断有没有解析完。看看有没有,没有解析的类。一笔带过了。如果都解析过,do-while循环就结束了。至此下图所示的一个方法就分析完毕了。


refresh中的 invokeBeanFactoryPostProcessors(beanFactory);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351