• springboot加载bean过程探索


    springboot一般通过以下main方法来启动项目

    @SpringBootApplication
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }

    查看源码发现加载的主要逻辑写在了

    具体逻辑如下:
    /**
         * Run the Spring application, creating and refreshing a new
         * {@link ApplicationContext}.
         * @param args the application arguments (usually passed from a Java main method)
         * @return a running {@link ApplicationContext}
         */
        public ConfigurableApplicationContext run(String... args) {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            ConfigurableApplicationContext context = null;
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
            configureHeadlessProperty();
            SpringApplicationRunListeners listeners = getRunListeners(args);
            listeners.starting();
            try {
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                        args);
                ConfigurableEnvironment environment = prepareEnvironment(listeners,
                        applicationArguments);
                configureIgnoreBeanInfo(environment);
                Banner printedBanner = printBanner(environment);
    //1.创建容器 context
    = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);
    //2.把bean装载进容器context中去 prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop();
    if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }

    下面重点讲"把bean装载进容器context中去"的这个方法prepareContext(context, environment, listeners, applicationArguments, printedBanner)的逻辑

     方法的代码实现逻辑如下:

    private void prepareContext(ConfigurableApplicationContext context,
                ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
                ApplicationArguments applicationArguments, Banner printedBanner) {
            context.setEnvironment(environment);
            postProcessApplicationContext(context);
            applyInitializers(context);
            listeners.contextPrepared(context);
            if (this.logStartupInfo) {
                logStartupInfo(context.getParent() == null);
                logStartupProfileInfo(context);
            }
            // Add boot specific singleton beans
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
            if (printedBanner != null) {
                beanFactory.registerSingleton("springBootBanner", printedBanner);
            }
            if (beanFactory instanceof DefaultListableBeanFactory) {
                ((DefaultListableBeanFactory) beanFactory)
                        .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
            }
            // Load the sources 也就要加载的声明配置的类,这里是声明了@SpringBootApplication的DemoApplication
            Set<Object> sources = getAllSources();
            Assert.notEmpty(sources, "Sources must not be empty");
    //把声明了@SpringBootApplication的类加载进容器的具体实现 load(context, sources.toArray(
    new Object[0])); listeners.contextLoaded(context); }

    load方法的具体实现:

    /**
         * Load beans into the application context.
         * @param context the context to load beans into
         * @param sources the sources to load
         */
        protected void load(ApplicationContext context, Object[] sources) {
            if (logger.isDebugEnabled()) {
                logger.debug(
                        "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
            }
    //这个BeanDefinationLoader的实现类为
    org.springframework.boot.BeanDefinitionLoader,为springboot自定义的一个beanDefination的加载器,专门用来加载配置声明的类的
            BeanDefinitionLoader loader = createBeanDefinitionLoader(
                    getBeanDefinitionRegistry(context), sources);
            if (this.beanNameGenerator != null) {
                loader.setBeanNameGenerator(this.beanNameGenerator);
            }
            if (this.resourceLoader != null) {
                loader.setResourceLoader(this.resourceLoader);
            }
            if (this.environment != null) {
                loader.setEnvironment(this.environment);
            }
    //
    org.springframework.boot.BeanDefinitionLoader把beanDefination加载进spring的BeanDefinationRegistry中的方法
         loader.load();

    }

    以下为org.springframework.boot.BeanDefinitionLoader的loan方法实现逻辑:

    private int load(Class<?> source) {
            if (isGroovyPresent()
                    && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
                // Any GroovyLoaders added in beans{} DSL can contribute beans here
                GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
                        GroovyBeanDefinitionSource.class);
                load(loader);
            }
            if (isComponent(source)) {
    //通过
    org.springframework.context.annotation.AnnotatedBeanDefinitionReader.AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry)来注册注解扫描的类定义
            this.annotatedReader.register(source);
            return 1;
            }
            return 0;
        }
    org.springframework.context.annotation.AnnotatedBeanDefinitionReader的作用是啥呢?来看看
    AnnotatedBeanDefinitionReader类的注释:
    /**
     * Convenient adapter for programmatic registration of annotated bean classes.
     * This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying
     * the same resolution of annotations but for explicitly registered classes only.
     *
     * @author Juergen Hoeller
     * @author Chris Beams
     * @author Sam Brannen
     * @author Phillip Webb
     * @since 3.0
     * @see AnnotationConfigApplicationContext#register
     */
    public class AnnotatedBeanDefinitionReader

    意思就是:

    用于声明bean类的编程注册的方便的适配器,
    这是ClassPathBeanDefinitionsCanner的替代方法,应用
    声明类解析,但仅限于显式注册的类。

  • 相关阅读:
    将Excel文件.xls导入SQL Server 2005
    linux mount命令
    python write file
    vim visual模式 复制
    chef简介
    录音整理文字工具otranscribe简介
    ftp put get 的使用方法
    yum lock 解决方法
    phalcon builder get raw sql
    centos7安装VirtualBox
  • 原文地址:https://www.cnblogs.com/swave/p/10966156.html
Copyright © 2020-2023  润新知