『SpringBoot 源码分析』run() 方法执行流程:(2)刷新应用上下文-准备阶段

『SpringBoot 源码分析』run() 方法执行流程:(2)刷新应用上下文-准备阶段

  • 基于 2.2.9.RELEASE
  • 问题:当方法进行了注释标记之后,springboot 又是怎么注入到容器中并创建类呢?
  1. 首先创建测试主程序
package com.lagou;

@SpringBootApplication//标注在类上说明这个类是`SpringBoot`的主配置类
public class SpringBootMytestApplication{

	public static void main(String[] args) {
		SpringApplication.run(SpringBootMytestApplication.class, args);
	}
}
  1. 创建测试 Controller
package com.lagou.controller;

@RestController
public class TestController {

	@RequestMapping("/test")
	public String test(){
		System.out.println("源码环境构建成功...");
		return "源码环境构建成功";
	}
}

准备阶段

  1. 当准备完成应用上下文环境,以及应用上下文以后,需要为应用上下文做个准备阶段,简单来说其实就是要配置应用上下文,把需要的类装配上
public class SpringApplication {
	...
	public ConfigurableApplicationContext run(String... args) {
		...
		try {
			// 将运行时参数封装
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 构造应用上下文环境
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			// 处理需要忽略的 Bean
			configureIgnoreBeanInfo(environment);
			// 打印 banner
			Banner printedBanner = printBanner(environment);
			// 刷新应用上下文前的准备阶段
			context = createApplicationContext();
			// 实例化 SpringBootExceptionReporter.class,用来支持报告关于启动的错误
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			// 1. 刷新应用上下文前的准备阶段
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			...
		}
		catch (Throwable ex) {
			...
		}
		...
	}
}
  1. 在对应用上下文进行处理时,主要执行了下面几步的装配
  • 把上下文环境设置到应用上下文中
  • 执行容器后置处理
  • 把应用上下文交给 SpringApplication 初始化收集的 org.springframework.context.ApplicationContextInitializer 所有实现类进行初始化工作
  • 利用 org.springframework.boot.context.event.EventPublishingRunListenerorg.springframework.context.ApplicationListener 发布容器准备好事件
public class SpringApplication {
	...
	// 完成属性设置 bean对象创建
	private void  prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		// 1. 设置容器环境
		context.setEnvironment(environment);
		// 2. 执行容器后置处理
		postProcessApplicationContext(context);
		// 3. 执行一些初始化器
		applyInitializers(context); 
		// 4. 向各个监听器发送容器已经准备好的事件
		listeners.contextPrepared(context);
		...
	}
}
  • 执行容器后置处理:其实只是往 BeanFactory 添加了基础的转换器
public class SpringApplication {

	private BeanNameGenerator beanNameGenerator;
	private ResourceLoader resourceLoader;
	private boolean addConversionService = true;
	...
	protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
		if (this.beanNameGenerator != null) {
			context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
					this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			if (context instanceof GenericApplicationContext) {
				((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
			}
			if (context instanceof DefaultResourceLoader) {
				((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
			}
		}
		
		if (this.addConversionService) { 
			// 1. 设置了转换器,例如平时能把整数字符串转换为整形,设置转换器
			context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
		}
	}
}
  • 执行一些初始化器:就是遍历 org.springframework.context.ApplicationContextInitializer 执行 initialize() 方法
public class SpringApplication {
	...
	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);
		}
	}
}
  • 向各个监听器发送容器已经准备好的事件:就是 org.springframework.boot.context.event.EventPublishingRunListenerorg.springframework.context.ApplicationListener 发布容器准备好事件
public class SpringApplication {
	...
	// 1. 当 ApplicationContext 构建完成时,该方法被调用
	void contextPrepared(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextPrepared(context);
		}
	}
}
  1. 发布完监听之后,从上下文中获取 IOC 工厂,并设置允许 bean 定义被覆盖参数
public class SpringApplication {
	...
	// 完成属性设置 bean 对象创建
	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);
		}
		// 1. 获取 IOC 容器
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		// 将 main() 函数中的 args 参数封装成单例 Bean,注册进容器
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			// 将 printedBanner 也封装成单例,注册进容器
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		// 2. 设置允许 bean 定义被覆盖参数
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		...
	}
}
  1. 然后加载启动类,并将启动类注入到容器当中,然后发布容器已加载事件
public class SpringApplication {
	...
	// 完成属性设置 bean 对象创建
	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);
		}
		// 获取 IOC 容器
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		// 将 main() 函数中的 args 参数封装成单例 Bean,注册进容器
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			// 将 printedBanner 也封装成单例,注册进容器
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		// 设置允许 bean 定义被覆盖参数
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.lazyInitialization) { // 是否需要进行懒加载,这里不是
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// 1. 加载源,这里拿到的是主类,com.lagou.SpringBootMytestApplication
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		// 2. 加载我们的启动类,将启动类注入容器 重点关注
		load(context, sources.toArray(new Object[0]));// 取出第一个元素,就是主类,要先实例化主类,灌入容器中
		// 3. 发布容器已加载事件
		listeners.contextLoaded(context);
	}
}
  • 其中将启动类注入到容器当中是比较关键的一步,首先先把 ApplicationContext 转换成 BeanDefinitionRegistry,然后创建 bean 定义加载器
public class SpringApplication {
	...
	protected void load(ApplicationContext context, Object[] sources) {
		if (logger.isDebugEnabled()) {
			logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
		}
		// 2. 创建 BeanDefinitionLoader
		BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
		...
	}
	
	private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
		// 1. 将 ApplicationContext 转换成 BeanDefinitionRegistry
		if (context instanceof BeanDefinitionRegistry) {
			return (BeanDefinitionRegistry) context;
		}
		if (context instanceof AbstractApplicationContext) {
			return (BeanDefinitionRegistry) ((AbstractApplicationContext) context).getBeanFactory();
		}
		throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
	}
}
  • 创建 BeanDefinitionLoader 主要是把 BeanDefinitionRegistry 以及主类的 sources 进行赋值初始化
public class SpringApplication {

	private final Object[] sources;
	private final AnnotatedBeanDefinitionReader annotatedReader;
	private final XmlBeanDefinitionReader xmlReader;
	private BeanDefinitionReader groovyReader;
	private final ClassPathBeanDefinitionScanner scanner;
	private ResourceLoader resourceLoader;
	...
	protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
		// 1. 创建 bean 定义加载器
		return new BeanDefinitionLoader(registry, sources);
	}

	BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
		// 其中,sources 就是主类 com.lagou.SpringBootMytestApplication
		Assert.notNull(registry, "Registry must not be null");
		Assert.notEmpty(sources, "Sources must not be empty");
		this.sources = sources;
		// 2. 注解形式的 Bean 定义读取器 比如:@Configuration @Bean @Component @Controller @Service等等
		this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
		// 3. XML 形式的 Bean 定义读取器
		this.xmlReader = new XmlBeanDefinitionReader(registry);
		if (isGroovyPresent()) {
			this.groovyReader = new GroovyBeanDefinitionReader(registry);
		}
		// 4. 类路径扫描器
		this.scanner = new ClassPathBeanDefinitionScanner(registry);
		// 5. 扫描器添加排除过滤器
		this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
	}
}
  1. 创建 BeanDefinitionLoader 成功后,就可以开始执行 load(),这里主要是先把主类注册到 IOC 容器中去
public class SpringApplication {

	private BeanNameGenerator beanNameGenerator;
	...
	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);
		}
		// 1. 执行 load()
		loader.load();
	}
}
  • 其中 load() 通过 AnnotatedBeanDefinitionReader 将主类 source 注册进 beanDefinitionMap
class BeanDefinitionLoader {
	
	private final AnnotatedBeanDefinitionReader annotatedReader;
	...
	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");
		// 1. 从 Class 加载
		if (source instanceof Class<?>) {
			return load((Class<?>) source);
		}
		...
	}

	private int load(Class<?> source) {
		// source 就是 class com.lagou.SpringBootMytestApplication
		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)) { // 判断方法有没有标记 Component 注解
			// 1. 将启动类的 BeanDefinition 注册进 beanDefinitionMap
			this.annotatedReader.register(source);
			return 1;
		}
		return 0;
	}
}
  • 调用 register() 方法时,真正会传到 doRegisterBean() 进行执行。首先会把主类转换成 AnnotatedGenericBeanDefinition,然后获取主类的名称,把名称和 AnnotatedGenericBeanDefinition 封装成 BeanDefinitionHolder 后,注册到上下文中
public class AnnotatedBeanDefinitionReader {
	...
	public void register(Class<?>... componentClasses) {
		for (Class<?> componentClass : componentClasses) {
			registerBean(componentClass);
		}
	}

	public void registerBean(Class<?> beanClass) {
		doRegisterBean(beanClass, null, null, null, null);
	}

	private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {
		// 1. 把主类转换成 AnnotatedGenericBeanDefinition,其中 beanClass 为 com.lagou.SpringBootMytestApplication
		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());
		// 2. 获取类名 springBootMytestApplication
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		if (qualifiers != null) {
			for (Class<? extends Annotation> 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);
			}
		}
		// 3. 封装成 BeanDefinitionHolder 
		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		// 4. 注册到容器中		
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}
}
  • 注册到容器中,简单而言就是调用 BeanDefinitionRegistryBeanDefinitionHolder 的 name 和 AnnotatedGenericBeanDefinition 装配进去
public abstract class BeanDefinitionReaderUtils {
	...
    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
    	// 1. 获取名称 springBootMytestApplication
        String beanName = definitionHolder.getBeanName();
        // 2. 注册到 IOC 容器中
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            String[] var4 = aliases;
            int var5 = aliases.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String alias = var4[var6];
                registry.registerAlias(beanName, alias);
            }
        }
    }
}
  • 最后会把 name 和 AnnotatedGenericBeanDefinition 存入到 beanDefinitionMap
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
	...
    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");
        // 1. 先校验 beanDefinition 是否合法
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition)beanDefinition).validate();
            } catch (BeanDefinitionValidationException var8) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
            }
        }

        BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            if (!this.isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }

            if (existingDefinition.getRole() < beanDefinition.getRole()) {
                if (this.logger.isInfoEnabled()) {
                    this.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 (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
                }
            } else if (this.logger.isTraceEnabled()) {
                this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
            }

            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
            if (this.hasBeanCreationStarted()) {
                synchronized(this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    this.removeManualSingletonName(beanName);
                }
            } else {
                // 2. 再把 beanDefinition 放到 beanDefinitionMap 中
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.removeManualSingletonName(beanName);
            }

            this.frozenBeanDefinitionNames = null;
        }

        if (existingDefinition == null && !this.containsSingleton(beanName)) {
            if (this.isConfigurationFrozen()) {
                this.clearByTypeCache();
            }
        } else {
            this.resetBeanDefinition(beanName);
        }
    }	
}
  1. 总结
    『SpringBoot 源码分析』run() 方法执行流程:(2)刷新应用上下文-准备阶段_第1张图片

你可能感兴趣的:(『后端』,spring,boot,java,后端)