Spring boot源码分析-BeanDefinitionLoader(7)

本文深入剖析了Spring Boot中BeanDefinitionLoader的工作原理,详细介绍了如何通过不同的方式(如Java配置、XML配置、包扫描等)来注册Bean,并探讨了其在Spring Boot应用启动过程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring boot源码分析-BeanDefinitionLoader(7)

BeanDefinitionLoader用来注册xml或者javaConfig中的bean,是AnnotatedBeanDefinitionReader的一个简单的外观模式,主要做的工作就是注册bean
该类在Springboot主函数准备Context容器的prepareContext的方法中被调用

private void prepareContext(ConfigurableApplicationContext context,
                                ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
                                ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        //设置获取
        postProcessApplicationContext(context);
        //对context进行initializer操作
        applyInitializers(context);
        //在springboot初始化的时候   没有针对context的Prepared做任何的操作
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }

        // Add boot specific singleton beans
        // DefaultListableBeanFactory
        // 注册springApplicationArguments的bean  用来存放启动时候的Arguments
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }

        // Load the sources
        // 获取启动参数里面的sources  一般就是Configuration的配置类
        Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        //load就是加载配置的类
        load(context, sources.toArray(new Object[sources.size()]));
        //容器准备完成  还没有调reflash方法的时候,主要可以对容器设置context.addBeanFactoryPostProcessor(),用于对BeanFactory进行一些设置
        listeners.contextLoaded(context);
    }
  • 首先看这个BeanDefinitionLoader的成员变量,BeanDefinitionLoader持有了各种类型的BeanDefinitionReader,都是用来注册bean用的
class BeanDefinitionLoader {
    private final Object[] sources;
    private final AnnotatedBeanDefinitionReader annotatedReader;
    private final XmlBeanDefinitionReader xmlReader;
    private BeanDefinitionReader groovyReader;
    private final ClassPathBeanDefinitionScanner scanner;
    private ResourceLoader resourceLoader;

    }

可以根据各种传入的参数处理,注册bean,有一下三种情况:

1.处理javaConfig,当传入的是一个ChapterProfilesApplication.class的bean的时候,会使用AnnotatedBeanDefinitionReader去处理参数

    SpringApplication.run(ChapterProfilesApplication.class, args);
    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);
            }
        }
        if (isComponent(source)) {
            this.annotatedReader.register(source);
            return 1;
        }
        return 0;
    }

2.处理Package,当传入的是一个Package的bean的时候,会使用ClassPathBeanDefinitionScanner去处理参数

        Package aPackage =Package.getPackage("com.leone.chapter.profiles");
        SpringApplication.run(aPackage, args);
    private int load(Package source) {
        return this.scanner.scan(source.getName());
    }

3.处理Resource类型的配置,会使用XmlBeanDefinitionReader去处理注册bean

        SpringApplication.run(new ClassPathResource("applicationContext.xml"), args);
    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);
        }
        return this.xmlReader.loadBeanDefinitions(source);
    }

4.处理String类型的配置,会按照class,Resource,Package的顺序尝试去解析String串进行加载

SpringApplication.run("classpath:/applicationContext.xml", args);
private int load(CharSequence source) {
        String resolvedSource = this.xmlReader.getEnvironment()
                .resolvePlaceholders(source.toString());
        // Attempt as a Class
        try {
            return load(ClassUtils.forName(resolvedSource, null));
        }
        catch (IllegalArgumentException ex) {
            // swallow exception and continue
        }
        catch (ClassNotFoundException ex) {
            // swallow exception and continue
        }
        // Attempt as resources
        Resource[] resources = findResources(resolvedSource);
        int loadCount = 0;
        boolean atLeastOneResourceExists = false;
        for (Resource resource : resources) {
            if (isLoadCandidate(resource)) {
                atLeastOneResourceExists = true;
                loadCount += load(resource);
            }
        }
        if (atLeastOneResourceExists) {
            return loadCount;
        }
        // Attempt as package
        Package packageResource = findPackage(resolvedSource);
        if (packageResource != null) {
            return load(packageResource);
        }
        throw new IllegalArgumentException("Invalid source '" + resolvedSource + "'");
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值