转载

SpringBoot BeanDefinitions 解析过程(等待更新)

Spring 解析和注册 BeanDefinitions 有两种方式,一种XML,大部分的参考博客和文档都用自己作为解析的方法,另外一种是基于注解的扫描方法。SpringBoot 在初始化Context前,会先自己定义源,然后由 invokeBeanFactoryPostProcessors() 作为入口,进而协助解析和注册,即使是最简单的 Spring Boot 程序,这部分也比较耗时间。

源码

/**
	 * 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) {
		... 省略
		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 会帮助保存source,bean的源
			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 ... 省略异常处理
		return context;
	}
复制代码

BeanFacotry.primarySources

SpringBoot 会以我们定义的主类作为 primarySources 去扫描 Beans。

SpringBoot BeanDefinitions 解析过程(等待更新)
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		... 省略对context的初始化,和几个单例的注册
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		// load
		load(context, sources.toArray(new Object[0]));
		listeners.contextLoaded(context);
	}
复制代码

// SpringApplication.java:677

/**
	 * 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) {
		// BeanDefinitionLoader 把加载的逻辑代码独立委托给这个类(BeanDefinitions 加载器)
		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();
	}
复制代码

// BeanDefinitionLoader.java

/**
	 * 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) {
			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) {
		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)) {
		    // 把源放进 Reader
			this.annotatedReader.register(source);
			return 1;
		}
		return 0;
	}
复制代码

扫描加载的过程是由一个 BeanFactoryPostProcessor 接口的实现类进行的。

  • 加载的时候,默认在 Main 类的包中开始进行,这是为什么我们有时候需要设置 @ComponentScan 接口。
    SpringBoot BeanDefinitions 解析过程(等待更新)

// 等待更新

原文  https://juejin.im/post/5e782bb4518825493b240ee2
正文到此结束
Loading...