SpringBoot&SpringCloud兼容原理

Spring Boot 基于 SpringApplication 启动时,通过 监听器 监听对应的事件,执行相关的动作。
众所周知,我们可以在 Spring Boot 项目中引入 Spring Cloud 相关依赖。 Spring Cloud 实际上就是 Spring Boot 基于 监听器 拓展的,该监听器就是 Spring Cloud 子项目 spring-cloud-commons 下 spring-cloud-context 模块提供的 BootstrapApplicationListener,配置在spring.factories 文件中由 Spring Boot 应用加载,监听对应的事件后启动 Spring Cloud 容器。

非web环境下,一般来说常用的就两类ApplicationContext:

  • 配置形式为XML的:ClassPathXmlApplicationContext、FileSystemXmlApplicationContext。
  • 配置形式为注解的:AnnotationConfigApplicationContext。

web环境下默认的上下文ApplicationContext:

  • AnnotationConfigServletWebServerApplicationContext:

1、BootstrapApplicationListener

监听器的加载&调用参考。该监听器绑定于SpringCloud微服务的依赖。并且位于SpringBoot中众多应用监听器集合的首位。

public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
    
    
	//StandardServletEnvironment
	ConfigurableEnvironment environment = event.getEnvironment();
	...
	ConfigurableApplicationContext context = bootstrapServiceContext(environment, event.getSpringApplication(),
				configName);
	...
}
...
private ConfigurableApplicationContext bootstrapServiceContext(
		ConfigurableEnvironment environment, final SpringApplication application,
		String configName) {
    
    
	StandardEnvironment bootstrapEnvironment = new StandardEnvironment();
	...
	SpringApplicationBuilder builder = new SpringApplicationBuilder()
			.profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF)
			.environment(bootstrapEnvironment)
			// Don't use the default properties in this builder
			.registerShutdownHook(false).logStartupInfo(false)
			.web(WebApplicationType.NONE);
	final SpringApplication builderApplication = builder.application();
	...
	final ConfigurableApplicationContext context = builder.run();
	return context;
}
  1. WebApplicationType.NONE:表示加载的ConfigurableApplicationContext为AnnotationConfigApplicationContext。
  2. builder.run():重新触发SpringApplication#run方法执行实现容器的刷新。
  3. 通常情况下AnnotationConfigApplicationContext触发容器刷新之后,会继续生成web环境下上下文之AnnotationConfigServletWebServerApplicationContext并再次刷新容器。
protected ConfigurableApplicationContext createApplicationContext() {
    
    
	Class<?> contextClass = this.applicationContextClass;
	switch (this.webApplicationType) {
    
    
		case SERVLET://AnnotationConfigServletWebServerApplicationContext
			contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
			break;
		case REACTIVE:
			contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
			break;
		default://AnnotationConfigApplicationContext
			contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
		}
	//通过反射方式实例化对应的ConfigurableApplicationContext
	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

AnnotationConfigApplicationContext、AnnotationConfigServletWebServerApplicationContext其共同父类均为GenericWebApplicationContext、BeanDefinitionRegistry。

2、ConfigurableApplicationContext

接口ConfigurableApplicationContext的子类在实例化过程中都会触发其父类GenericWebApplicationContext的实例化。GenericWebApplicationContext实例化都会创建Spring中核心容器DefaultListableBeanFactory。由此得知ConfigurableApplicationContext的子类拥有独立的IOC容器之DefaultListableBeanFactory。

接口ConfigurableApplicationContext的子类在实例化过程中会触发预发性的PostProcessor后置处理器作为普通bean注册其定义信息【DefaultListableBeanFactory#registerBeanDefinition】。主要包括:ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、EventListenerMethodProcessor等最早的后置处理器。

这些后置处理器本身也是普通类,也需要遵循Spring IOC容器中bean的加载过程,即类信息包装为RootBeanDefinition并注册、实例化、初始化等过程。

registerBeanDefinition其实就是将之后bean实例化得到的bean名称以及RootBeanDefinition的对应关系暂时存储在JVM内存中

2.1、AnnotationConfigApplicationContext

public AnnotationConfigApplicationContext() {
    
    
	//注册当前类的RootBeanDefinition信息以及部分BeanPostProcessor的RootBeanDefinition信息
	this.reader = new AnnotatedBeanDefinitionReader(this);
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

2.3、AnnotationConfigServletWebServerApplicationContext

public AnnotationConfigServletWebServerApplicationContext() {
    
    
	//注册当前类的RootBeanDefinition信息以及部分BeanPostProcessor的RootBeanDefinition信息
	this.reader = new AnnotatedBeanDefinitionReader(this);
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

猜你喜欢

转载自blog.csdn.net/qq_36851469/article/details/128873727