SpringBoot源码(十): prepareContext

介绍

前面一章介绍了创建ApplicationContext,这章将会介绍ApplicationContext的一些处理工作。

源码

	private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
        // 处理ApplicationContext
		postProcessApplicationContext(context);
        // 初始化器对context进行初始化处理
		applyInitializers(context);
        // 发送事件
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}

		// 注册bean到spring容器中
		context.getBeanFactory().registerSingleton("springApplicationArguments",
				applicationArguments);
		if (printedBanner != null) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}

		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
        // 加载启动类类,如果被@Component注解修饰,加到bean定义的map中
		load(context, sources.toArray(new Object[0]));
        // 发送事件
		listeners.contextLoaded(context);
	}

这边整体的逻辑就是,对ApplicationContext进行一些准备工作。我们看下初始化器的初始化工作的代码。

	@SuppressWarnings({ "rawtypes", "unchecked" })
	protected void applyInitializers(ConfigurableApplicationContext context) {
        // 拿到SpringApplication初始化时候创建的初始化器
		for (ApplicationContextInitializer initializer : getInitializers()) {
            // 判断泛型是否匹配
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
					initializer.getClass(), ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            // 执行初始化
			initializer.initialize(context);
		}
	}

初始化器初始化比较简单,就是执行初始化的方法,对于初始化器怎么来的,在第一章时候说了,从META-INF/spring.factories中获取的。

这边挑一个初始化器说下:ContextIdApplicationContextInitializer

public class ContextIdApplicationContextInitializer implements
		ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {

	private int order = Ordered.LOWEST_PRECEDENCE - 10;

	public void setOrder(int order) {
		this.order = order;
	}

	@Override
	public int getOrder() {
		return this.order;
	}

	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		ContextId contextId = getContextId(applicationContext);
		applicationContext.setId(contextId.getId());
		applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(),
				contextId);
	}

	private ContextId getContextId(ConfigurableApplicationContext applicationContext) {
		ApplicationContext parent = applicationContext.getParent();
		if (parent != null && parent.containsBean(ContextId.class.getName())) {
			return parent.getBean(ContextId.class).createChildId();
		}
		return new ContextId(getApplicationId(applicationContext.getEnvironment()));
	}
    
    // 从配置中获取spring.application.name值
	private String getApplicationId(ConfigurableEnvironment environment) {
		String name = environment.getProperty("spring.application.name");
		return StringUtils.hasText(name) ? name : "application";
	}

	/**
	 * The ID of a context.
	 */
	class ContextId {

		private final AtomicLong children = new AtomicLong(0);

		private final String id;

		ContextId(String id) {
			this.id = id;
		}

		ContextId createChildId() {
			return new ContextId(this.id + "-" + this.children.incrementAndGet());
		}

		String getId() {
			return this.id;
		}

	}

}

ContextIdApplicationContextInitializer的作用就是从environment中获取spring.application.name的值,如果有就设置成applicationContext的id,如果没有就默认application。

比如我们在配置文件application.yml中设置spring.application.name=spring-boot,那么这个程序的ApplicationContext的id就是spring-boot。

 

接着看主流程:context.getBeanFactory().registerSingleton则是把springApplicationArguments和springBootBanner加到spring容器中,这里把对象加到容器中,不是加到bean定义的map中。加到bean定义的map中的话还是得生成对象,加到容器中的,这些后面会说到,现在只是有这样的概念就好。

接下来说load方法:

	public Set<Object> getAllSources() {
		Set<Object> allSources = new LinkedHashSet<>();
		if (!CollectionUtils.isEmpty(this.primarySources)) {
			allSources.addAll(this.primarySources);
		}
		if (!CollectionUtils.isEmpty(this.sources)) {
			allSources.addAll(this.sources);
		}
		return Collections.unmodifiableSet(allSources);
	}

	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方法主要是创建一个BeanDefinitionLoader,然后对于sources解析。这个sources就是我们的启动的Application类的class。

接下来看BeanDefinitionLoader的解析方法:

class BeanDefinitionLoader {

	private final Object[] sources;

	private final AnnotatedBeanDefinitionReader annotatedReader;

	private final XmlBeanDefinitionReader xmlReader;

	private BeanDefinitionReader groovyReader;

	private final ClassPathBeanDefinitionScanner scanner;

	private ResourceLoader resourceLoader;

	BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
		Assert.notNull(registry, "Registry must not be null");
		Assert.notEmpty(sources, "Sources must not be empty");
		this.sources = sources;
		this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
		this.xmlReader = new XmlBeanDefinitionReader(registry);
		if (isGroovyPresent()) {
			this.groovyReader = new GroovyBeanDefinitionReader(registry);
		}
		this.scanner = new ClassPathBeanDefinitionScanner(registry);
		this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
	}

	public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
		this.annotatedReader.setBeanNameGenerator(beanNameGenerator);
		this.xmlReader.setBeanNameGenerator(beanNameGenerator);
		this.scanner.setBeanNameGenerator(beanNameGenerator);
	}


	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
		this.xmlReader.setResourceLoader(resourceLoader);
		this.scanner.setResourceLoader(resourceLoader);
	}

	public void setEnvironment(ConfigurableEnvironment environment) {
		this.annotatedReader.setEnvironment(environment);
		this.xmlReader.setEnvironment(environment);
		this.scanner.setEnvironment(environment);
	}

	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());
	}

	private int load(Class<?> source) {
        // Groovy是否存在
		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);
		}
        // 如果被@Component修饰
		if (isComponent(source)) {
            // 注册到容器的bean定义的beanDefinitionMap的map中
			this.annotatedReader.register(source);
			return 1;
		}
		return 0;
	}

    /**
    * 省略其他代码
    */
}

BeanDefinitionLoader主要负责对于bean的解析,并且加入到bean定义beanDefinitionMap中去。由于我们的启动类的对象是class,所以直接调用load(Class<?> soruce)的方法。这个方法主要去判断class是否有@Component修饰或者注解的注解有没有@Component修饰,如果有就加入到beanDefinitionMap中。

像我们的启动类一般都是加入@SpringBootApplication注解。而@SpringBootApplication注解又有@SpringBootConfiguration注解,@SpringBootConfiguration注解又有@Configuration注解,@Configuration注解是有@Component注解。这样我们的启动类就加入到spring的beanDefinitionMap中去了。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration

至此load的逻辑就结束了。BeanDefinitionLoader还有其他很多的方法,但是暂时先不看,用到时候再慢慢看,看多了也不清楚做什么的。

再向下prepareContext的逻辑就是发送事件了,就不再讲了。

总结

prepareContext主要就是准备ApplicationContext,对ApplicationContext进行一些初始化处理,然后把启动类加入到BeanDefinition中去,后面解析用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值