SpringBoot 源码分析准备应用上下文(2)-prepareContext

一、入口

/**
	 * 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 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);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, 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;
	}
prepareContext(context, environment, listeners, applicationArguments, printedBanner);

这个方法主要是一些准备工作,用来进行一些赋值操作,在上一步中已经把应用上下文创建出来了,这里就是赋值,会去创建一些 bean 对象存于 IOC容器中,会完成主类(启动类)对象的创建并添加到 IOC 容器中 ,接着看 prepareContext方法的具体实现

二、prepareContext 方法实现

截图:

SpringBoot 源码分析准备应用上下文(2)-prepareContext_第1张图片

代码:

 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();
        // 将 main 主函数中的 args 参数封装成单例 bean ,注册进容器
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        if (this.lazyInitialization) {
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }
        // Load the sources
        Set sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        //加载我们的启动类,将启动类注入容器
        load(context, sources.toArray(new Object[0]));
        //发布容器已加载事件通知
        listeners.contextLoaded(context);
    } 
  

 接着看  applyInitializers 方法实现

2.1 applyInitializers 方法实现

引:applyInitializers(context);

截图:

SpringBoot 源码分析准备应用上下文(2)-prepareContext_第2张图片代码:

/**
     * Apply any {@link ApplicationContextInitializer}s to the context before it is
     * refreshed.
     * @param context the configured ApplicationContext (not refreshed yet)
     * @see ConfigurableApplicationContext#refresh()
     */
    // 之前在 new SpringApplication() 中创建的初始化容器的启动
    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected void applyInitializers(ConfigurableApplicationContext context) {
        // 就是把之前创建出来的初始化容器进行启动
        for (ApplicationContextInitializer initializer : getInitializers()) {
            Class requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
                    ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            // 启动之前创建的初始化容器
            initializer.initialize(context);
        }
    }

 

initializer.initialize(context);这个方法就会启动一些上下文

2.2 load 方法实现

引:load(context, sources.toArray(new Object[0]));

截图:

SpringBoot 源码分析准备应用上下文(2)-prepareContext_第3张图片

代码:


    /**
     * 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));
        }
        // 创建 BeanDefinitionLoader
        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);
        }
        loader.load();
    }

 点击loader.load()方法,又调用了load()方法:

截图:

SpringBoot 源码分析准备应用上下文(2)-prepareContext_第4张图片

代码:

 /**
     * Load the sources into the reader.
     * @return the number of loaded beans
     */
    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) {
            // 从 Class 加载
            return load((Class) source);
        }
        if (source instanceof Resource) {
            // 从 Resource 加载
            return load((Resource) source);
        }
        if (source instanceof Package) {
            // 从 Package 加载
            return load((Package) source);
        }
        if (source instanceof CharSequence) {
            // 从 CharSequence 加载
            return load((CharSequence) source);
        }
        throw new IllegalArgumentException("Invalid source type " + source.getClass());
    }

 接着看 从 Class 加载  load((Class) source)

SpringBoot 源码分析准备应用上下文(2)-prepareContext_第5张图片

 代码:

 private int load(Class source) {
        if (isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            // Any GroovyLoaders added in beans{} DSL can contribute beans here
            BeanDefinitionLoader.GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
            load(loader);
        }
        // 判断核心启动类 是否标注了 @Component 注解
        if (isComponent(source)) {
            // 将启动类的 BeanDefinition 注册进 beanDefinitionMap 中
            this.annotatedReader.register(source);
            return 1;
        }
        return 0;
    }

2.3  register 方法实现

引:this.annotatedReader.register(source);

截图:

SpringBoot 源码分析准备应用上下文(2)-prepareContext_第6张图片

2.4 registerBean 方法实现

引:registerBean(componentClass);

截图:

2.4  doRegisterBean 方法实现

引:doRegisterBean(beanClass, null, null, null, null);

截图:

SpringBoot 源码分析准备应用上下文(2)-prepareContext_第7张图片

代码:

 /**
     * Register a bean from the given bean class, deriving its metadata from
     * class-declared annotations.
     * @param beanClass the class of the bean
     * @param name an explicit name for the bean
     * @param qualifiers specific qualifier annotations to consider, if any,
     * in addition to qualifiers at the bean class level
     * @param supplier a callback for creating an instance of the bean
     * (may be {@code null})
     * @param customizers one or more callbacks for customizing the factory's
     * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
     * @since 5.0
     */
    private  void doRegisterBean(Class beanClass, @Nullable String name,
                                    @Nullable Class[] qualifiers, @Nullable Supplier supplier,
                                    @Nullable BeanDefinitionCustomizer[] customizers) {

        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
        if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            return;
        }

        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);
        if (qualifiers != null) {
            for (Class qualifier : qualifiers) {
                if (Primary.class == qualifier) {
                    abd.setPrimary(true);
                }
                else if (Lazy.class == qualifier) {
                    abd.setLazyInit(true);
                }
                else {
                    abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                }
            }
        }
        if (customizers != null) {
            for (BeanDefinitionCustomizer customizer : customizers) {
                customizer.customize(abd);
            }
        }

        // BeanDefinitionHolder 就是针对 BeanDefinition 的一个持有对象,里面有两个内容,分别是 BeanDefinition 和 BeanName
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }

 2.5 接着 registerBeanDefinition 方法实现

引:BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

截图:

SpringBoot 源码分析准备应用上下文(2)-prepareContext_第8张图片

代码:


    /**
     * Register the given bean definition with the given bean factory.
     * @param definitionHolder the bean definition including name and aliases
     * @param registry the bean factory to register with
     * @throws BeanDefinitionStoreException if registration failed
     */
    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // Register bean definition under primary name.
        String beanName = definitionHolder.getBeanName(); //获取 beanName
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // 注册 BeanDefinition

        // Register aliases for bean name, if any.
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

 2.6 接着看 registerBeanDefinition 方法实现

引:registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

截图:

SpringBoot 源码分析准备应用上下文(2)-prepareContext_第9张图片

 这是一个接口,接着看其具体实现类:

SpringBoot 源码分析准备应用上下文(2)-prepareContext_第10张图片

 找到其默认实现类 DefaultListableBeanFactory

这就回到第一步的 registerBeanDefinition 方法

截图:

SpringBoot 源码分析准备应用上下文(2)-prepareContext_第11张图片 代码:

//---------------------------------------------------------------------
	// Implementation of BeanDefinitionRegistry interface
	//---------------------------------------------------------------------
 
	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
 
		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");
 
		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}
        //在注册 bd 的时候判断该名字有没有被注册
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        //该名字已经被注册
        //spring 默认支持覆盖 bd,但是 spring 会输入一些日志
        //1、两个 bd 相同的情况下
        //2、两个 bd 不同的情况 role 不同
        //3、两个 bd 不相同但是 role 相同
		if (existingDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
            //优先级
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
            //判断我们的 spring 容器是否开启实例化 bean了
            //如果为null,set 为空,没有开始就创建 bean 不会进入 if
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
                    //一个 map 一个 list ,list里面方法的 map 的 key,也就是 beanName
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
                    //如果注册了 beanDefinition 的名字和手工注册的 bd 集合当中某个相同则删除手动注册的 beanName
					removeManualSingletonName(beanName);
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}
        //判断注册的 bd 以及 beanName 是否存在
		if (existingDefinition != null || containsSingleton(beanName)) {
            //清除 allBeanNameByType
            //把单例池当中的 bean 也 remove
			resetBeanDefinition(beanName);
		}
	}
总结:prepareContext()的主要工作:
1、向context完成一些属性的设置
2、将主类生成实例对象,存到容器中。

参考文章:SpringBoot源码深度剖析——@SpringBootApplication注解和new SpringApplication().run()方法深度解密_生活,没那么矫情的博客-CSDN博客

 

 

 

你可能感兴趣的:(spring,boot,spring,java)