Spring Boot源码简析(二)

 2019-11-23 11:13  阅读(1053)
文章分类:Spring Cloud

Spring Boot源码简析(二)

load 资源过程

在上一篇博客中我们说了SpringApplication的主要启动逻辑,其中context创建之后第一步就是执行

load(context, sources.toArray(new Object[sources.size()]));

load主要就是把我们传入的资源生成相应的BeanDefinition。

protected void load(ApplicationContext context, Object[] sources) {
        //创建一个BeanDefinitionLoader,看名字就知道使用来加载Bean信息的
        BeanDefinitionLoader loader = createBeanDefinitionLoader(
                getBeanDefinitionRegistry(context), sources);
                //塞一个beanNameGenerator
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        //塞一个resourceLoader,用来先加载资源然后再解析
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
        //开始加载
        loader.load();
    }

这里主要是先创建了一个BeanDefinitionLoader并在加载前做了一些准备工作,然后执行加载操作。

public int load() {
        int count = 0;
        for (Object source : this.sources) {
            count += load(source);
        }
        return count;
    }

    private int load(Object source) {
        Assert.notNull(source, "Source must not be null");
        if (source instanceof Class<?>) {
            return load((Class<?>) source);
        }
        if (source instanceof Resource) {
            return load((Resource) source);
        }
        if (source instanceof Package) {
            return load((Package) source);
        }
        if (source instanceof CharSequence) {
            return load((CharSequence) source);
        }
        throw new IllegalArgumentException("Invalid source type " + source.getClass());
    }

此处是根据传入的资源类型来加载资源,下面根据具体的资源类型来查看资源加载资源

Load class

private int load(Class<?> source) {
        if (isGroovyPresent()) {
            // Any GroovyLoaders added in beans{} DSL can contribute beans here
            if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
                GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
                        GroovyBeanDefinitionSource.class);
                load(loader);
            }
        }
        //查看元素是否有@Component注解
        if (isComponent(source)) {
        //将source对应的类型注册一个beanDefinition
            this.annotatedReader.register(source);
            return 1;
        }
        return 0;
    }

这里就是将我们传入的类创建对应的beanDefinition并注册到registry中去。
Load resource

private int load(Resource source) {
        if (source.getFilename().endsWith(".groovy")) {
            if (this.groovyReader == null) {
                throw new BeanDefinitionStoreException(
                        "Cannot load Groovy beans without Groovy on classpath");
            }
            return this.groovyReader.loadBeanDefinitions(source);
        }
        //调用xmlReader来加载beanDefinition
        return this.xmlReader.loadBeanDefinitions(source);
    }

这里可以很明显看到,通过资源加载其实也就是我们平时使用xml配置,springboot是可以支持像spring一样的通过配置文件配置bean的方式。

Load package

private int load(Package source) {
        //调用扫描器来扫描package下所有类文件
        return this.scanner.scan(source.getName());
    }

这里是我比较感兴趣的地方,因为在spring没有配置文件的情况下,主要的bean加载的方式就应该是通过这个方法实现

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {

        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
        //遍历所有的包
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidates =
            //扫描该包下的所有文件,包含componet注解的类将会创建对应的BeanDefinition
            findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                //获取bean的scope信息,主要是是否是singleton、是否需要代理
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                //创建beanName
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                if (candidate instanceof AbstractBeanDefinition) {
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                if (checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }

总体来说,load的操作就是把用户传入的各种资源对应的bean的beanDefinition信息到注册中心。


来源:http://ddrv.cn/a/88268

点赞(1)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Spring Boot源码简析(二)

相关推荐