spring cloud,sping boot,微服务,tomcat容器关系及创建执行顺序详解

1、spring cloud 父子容器整体关系

由于在spring cloud启动源码加载过程中,没太弄清楚tomcat容器,spring 容器,spring cloud容器整体的加载顺序以及关系,所以想分析下这个流程,先不多说,上图
在这里插入图片描述
容器大致分为三层:

BootStrap Spring 容器:由SpringCloud 监听器创建,用来初始化 SpringCloud 上下文
SpringBoot Spring 容器:由SpringBoot创建,也是项目中常用的Spring容器。
微服务 Spring相关容器:Feign和Ribbon配置类对应的上下文,由配置容器抽象工厂 NamedContextFactory 创建,用于容器隔离。
先说spring cloud容器bootstrap,在容器启动时,会先读取boostrap.xml文件,进行基本配置的加载,随后才会加载application.xml,这其实也说明了bootstrap容器是先于spring boot容器的,本质其实是spring 容器的环境配置是依赖于bootstrap的,bootstrap上下文是主应用程序的父上下文共享一个 Environment,它是任何Spring应用程序的外部属性的来源。要注意的是,bootstrap容器的配置优先级要高于spring boot,这种优先级不但体现于加载顺序,还有就是当俩者都存在某一项配置,boostrap配置是不会被覆盖,即以bootstrap配置为主

废话不多说,先看源码
SpringBoot 在启动时,会触发相关一系列监听器,监听器各司其职,做一些初始化预处理操作。SpringCloud 实现了自己的监听器:BootstrapApplicationListener,来初始化SpringCloud上下文环境。

@Override
	public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
   
		ConfigurableEnvironment environment = event.getEnvironment();
		//如果未开启SpringCloud,直接返回
		if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,
				true)) {
   
			return;
		}
		// don't listen to events in a bootstrap context
		//判断该监听器是否已经执行过,如果执行过,直接返回
		if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
   
			return;
		}
		//这里返回了一个 Spring 容器
		ConfigurableApplicationContext context = bootstrapServiceContext(environment,
				event.getSpringApplication());
		apply(context, event.getSpringApplication(), environment);
	}

bootstrapServiceContext方法创建了一个 Spring 容器:ConfigurableApplicationContext:

private ConfigurableApplicationContext bootstrapServiceContext(
			ConfigurableEnvironment environment, final SpringApplication application) {
   
		StandardEnvironment bootstrapEnvironment = new StandardEnvironment();
		MutablePropertySources bootstrapProperties = bootstrapEnvironment
				.getPropertySources();
		for (PropertySource<?> source : bootstrapProperties) {
   
			bootstrapProperties.remove(source.getName());
		}
		//设置读取 bootstrap 文件
		String configName = environment
				.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
		//设置 bootstrap 文件路径
		String configLocation = environment
				.resolvePlaceholders("${spring.cloud.bootstrap.location:}");
		Map<String, Object> bootstrapMap = new HashMap<>();
		bootstrapMap.put("spring.config.name", configName);
		if (StringUtils.hasText(configLocation)) {
   
			bootstrapMap.put("spring.config.location", configLocation);
		}
		//设置是否已经初始化BootStrap环境
		bootstrapProperties.addFirst(
				new MapPropertySource(BOOTSTRAP_PROPERTY_SOURCE_NAME, bootstrapMap));
		for (PropertySource<?> source : environment.getPropertySources()) {
   
			bootstrapProperties.addLast(source);
		}
			//......
			//加载BootstrapConfiguration 配置类
			List<String> names = SpringFactoriesLoader
				.loadFactoryNames(BootstrapConfiguration.class, classLoader);
			for (String name : StringUtils.commaDelimitedListToStringArray(
					environment.getProperty("spring.cloud.bootstrap.sources", ""))) {
   
				names.add(name);
			}
		//创建 Spring 容器
		SpringApplicationBuilder builder = new SpringApplicationBuilder()
				.profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF)
				.environment(bootstrapEnvironment)
				.properties("spring.application.name:" + configName)
				.registerShutdownHook(false)
				.logStartupInfo(false)
				.web(false);
		List<Class<?>> sources = new ArrayList<>();

		builder.sources(sources.toArray(new Class[sources.size()]));
		AnnotationAwareOrderComparator.sort(sources);
		final ConfigurableApplicationContext context = builder.run();
		//创建祖先容器
		addAncestorInitializer(application, context);
		bootstrapProperties.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
		mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties);
		return context;
	}

首先,SpringBoot项目是通过SpringApplicationBuilder启动,在上述逻辑中又构建了一个SpringApplicationBuilder对象,再次执行run方法:final ConfigurableApplicationContext context = builder.run();
所以启动流程会执行两遍,只是读取的配置文件和配置类不同。
同样的,当第二次创建SpringApplicationBuilder并启动时,会不会再次出发监听器,然后接着创建SpringApplicationBuilder呢?
肯定不会。否则就是死循环了。上面已经提到了,SpringCloud通过标识符BOOTSTRAP_PROPERTY_SOURCE_NAME来判断。监听器执行之后,会设置该变量对应值,下次启动前如果有值,表明已经执行。

上面有一行关键的代码:addAncestorInitializer(application, context);
ancestor 祖先的意思,来看一下:

private void addAncestorInitializer(SpringApplication application,
			ConfigurableApplicationContext context) {
   
		boolean installed = false;
		//遍历所有的initializer,判断是否已经存在 祖先initializer
		for (ApplicationContextInitializer<?> initializer : application
				.getInitializers()) {
   
			if (initializer instanceof AncestorInitializer) {
   
				installed = true;
				// 如果存在,则设置 bootStrapApplication
				((AncestorInitializer) initializer)
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring BootSpring Cloud是两个不同的框架,它们都是基于Spring Framework的。Spring Boot主要是用于快速构建单个微服务,而Spring Cloud则是用于构建分布式系统中的多个微服务。 下面是Spring CloudSpring Boot的优缺点比较: Spring Boot优点: 1. 简单易用:Spring Boot提供了自动配置和快速开发的能力,使得开发人员可以快速地构建和运行Spring应用程序。 2. 强大的开发工具:Spring Boot提供了强大的开发工具,比如Spring Boot CLI和Spring Boot Starter,使得开发人员可以轻松地创建和部署应用程序。 3. 集成了大量的第三方库:Spring Boot集成了大量的第三方库,比如Hibernate、Thymeleaf、Jackson等,使得开发人员可以轻松地使用这些库来处理不同的业务需求。 4. 适用于小型应用程序:Spring Boot适用于构建小型的应用程序,可以快速地实现业务需求。 Spring Boot缺点: 1. 不适用于大型应用程序:Spring Boot不适用于构建大型的应用程序,因为它缺乏分布式系统的支持。 2. 缺乏服务治理:Spring Boot缺乏服务治理的能力,因此在构建分布式系统时需要使用Spring CloudSpring Cloud优点: 1. 服务治理:Spring Cloud提供了服务注册、发现、负载均衡和断路器等服务治理功能,使得开发人员可以构建分布式系统中的多个微服务。 2. 分布式配置管理:Spring Cloud提供了分布式配置管理的功能,可以快速地更新应用程序的配置。 3. 分布式追踪:Spring Cloud提供了分布式追踪的功能,可以快速地定位应用程序的异常。 Spring Cloud缺点: 1. 复杂度高:Spring Cloud的复杂度很高,需要开发人员具备分布式系统的技术知识。 2. 性能问题:Spring Cloud会增加系统的复杂度,可能会影响系统的性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值