栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot2.5原理解析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot2.5原理解析

文章目录
  • SpringBoot原理讲解
    • 一、SpringBoot是什么?
    • 二、SpringBoot自动装配原理?
    • 三、SpringBoot配置文件加载顺序?
    • 四、SpringBoot是如何解析yaml、properties文件?以及如何自定义解析配置文件?
      • 解析yaml、properties文件
      • 自定义解析文件
    • 五、SpringBoot启动顺序?
      • 刷新上下文

SpringBoot原理讲解

一、SpringBoot是什么?

Spring Boot是Spring公司的一个顶级项目,和Spring framework是一个级别的。

Spring Boot实际上是利用Spring framework 自动配置特性完成。编写项目时不需要编写xml文件。发展到现在,Spring Boot已经具有很很大的生态圈,各种主流技术已经都提供了Spring Boot的启动器。

​ Spring Boot 利用Spring framework 自动配置特性完成,多数xml不需要配置,整合其他技术,使用起来更加方便,组装完整环境的一个开发平台

Spring Boot的出现使我们能够将侧重点放在开发上。

Spring Boot启动器帮我们解决了繁琐的导jar包的时间,以及jar包之间存在的冲突问题

在Spring Boot 还没出现前,我们开发时需要对项目环境搭建配置繁琐的xml文件。SpringBoot的自动装配恰好解决了这问题。

SpringBoot的出现让部署web项目变得相对简单。

二、SpringBoot自动装配原理?

我们都知道要启动Springboot应用,在SpringBoot启动类上添加**@SpringBootApplication注解**

那么@SpringBootApplication注解跟SpringBoot的自动装配密切相关。

@SpringBootApplication注解下有几个重要注解:

  • @SpringBootConfiguration 实际就是上封装了@Configuration注解

  • @EnableAutoConfiguration 开启自动装配

  • @ComponentScan 组件扫秒

这里重点关注@EnableAutoConfiguration 注解,那么@EnableAutoConfiguration 下有注解

有个注解@import 注解上声明类AutoConfigurationimportSelector.class

我们点进去 找到selectimports(Annotationmetadata annotationmetadata) 方法

	protected AutoConfigurationEntry getAutoConfigurationEntry(Annotationmetadata annotationmetadata) {
		if (!isEnabled(annotationmetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationmetadata);
        //加载jar中/meta-INF/spring.factores配置类
		List configurations = getCandidateConfigurations(annotationmetadata, attributes);
		configurations = removeDuplicates(configurations);//去除重复配置类信息
		Set exclusions = getExclusions(annotationmetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationimportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}
//加载Factories
private static Map> loadSpringFactories(ClassLoader classLoader) {
		Map> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

  	result = new HashMap<>();
try {
	Enumeration urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			UrlResource resource = new UrlResource(url);
            //加载Factories
			Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					String[] factoryImplementationNames =
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
					for (String factoryImplementationName : factoryImplementationNames) {
                        ....
					}
				}
			}

			// Replace all lists with unmodifiable lists containing unique elements
			....
		}
		catch (IOException ex) {
			....
		}
		return result;
	}
三、SpringBoot配置文件加载顺序?

关于配置文件加载顺序具体可看实现类:

  • org.springframework.boot.context.config.ConfigFileApplicationListener弃用

  • org.springframework.boot.context.config.ConfigDataEnvironment

static final ConfigDataLocation[] DEFAULT_SEARCH_LOCATIONS;
//初始化文件加载顺序
static {
	List locations = new ArrayList<>();
  locations.add(ConfigDataLocation.of("optional:classpath:/;optional:classpath:/config/"));
	locations.add(ConfigDataLocation.of("optional:file:./;optional:file:./config/;optional:file:./config/*/"));
		DEFAULT_SEARCH_LOCATIONS = locations.toArray(new ConfigDataLocation[0]);
	}
四、SpringBoot是如何解析yaml、properties文件?以及如何自定义解析配置文件? 解析yaml、properties文件

首先SpringBoot启动时候会加载 SpringBoot包下 meta-INF/spring.factories,其中跟加载解析文件相关的类

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=
org.springframework.boot.env.PropertiesPropertySourceLoader,
org.springframework.boot.env.YamlPropertySourceLoader

# ConfigData Loaders
org.springframework.boot.context.config.ConfigDataLoader=
org.springframework.boot.context.config.ConfigTreeConfigDataLoader,
org.springframework.boot.context.config.StandardConfigDataLoader

然后通过springboot 监听器监听事件***EnvironmentPostProcessorApplicationListener***

调用***ConfigDataLoaders.load()***方法一层一层的调用方法, 最终调用到***PropertySourceLoader.load()***方法

调用过程

  • ConfigDataimporter.resolveAndLoad(…)

  • ConfigDataLoaders.load()

  • YamlPropertySourceLoader.load(…)或PropertiesPropertySourceLoader.load(…)

自定义解析文件
  1. 创建类实现接口 PropertySourceLoader
package com.any;
public class JSONPropertySourceLoader implements PropertySourceLoader {
    @Override
    public String[] getFileExtensions() {
        return new String[]{"json"};
    }

    @Override
    public List> load(String name, Resource resource) throws IOException {
        if(resource == null || !resource.exists()){
            return Collections.emptyList();
        }

        Map configs = JSON.parseObject(resource.getInputStream(), Map.class);

        return Collections.singletonList(
                new MapPropertySource(name, configs)
        );
    }
  1. 创建spring.factories文件

org.springframework.boot.env.PropertySourceLoader=
com.any.JSonPropertySourceLoader #指定SourceLoader类
五、SpringBoot启动顺序?
  • 开启计时器 stopWatch.start()

  • 开启监听器 listeners.starting

  • 初始化配置文件 prepareEnvironment

  • 打印Banner printBanner(environment)

  • 创建上下文 createApplicationContext()

  • 刷新上下文 refreshContext(context)

  • 停止计时器 stopWatch.stop()

  • 启动完成

    • listeners.started(context);
    • listeners.running(context)
	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch(); //创建计时器,记录一些启动信息
		stopWatch.start();//开始计时
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args); 
		listeners.starting(bootstrapContext, this.mainApplicationClass); //开启监听器
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);//初始化配置并绑定到环境
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);//打印Banner
			context = createApplicationContext();//创建上下文
			context.setApplicationStartup(this.applicationStartup);
			prepareContext(bootstrapContext, 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); 
			....
		}
		....
		try {
			listeners.running(context); //启动完成通知
		}
		....
		return context;
	}
刷新上下文
public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
			// 为刷新上下文做准备
			prepareRefresh();
			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// 配置BeanFactory
			prepareBeanFactory(beanFactory);
			try {
				......
				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// 实例化和调用所有已注册的Bean
				invokeBeanFactoryPostProcessors(beanFactory);
				//实例化和注册所有Bean
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();
				// 初始化此上下文的消息源。
				initMessageSource();
				// 初始化此上下文的事件多播程序
				initApplicationEventMulticaster();
				// 初始化一些与上下文有特别关系的bean对象(如创建tomcat)
				onRefresh();
				// 检查监听器bean并注册
				registerListeners();
				// 完成此上下文bean工厂的初始化,初始化所有剩余的非懒汉式单例bean
				finishBeanFactoryInitialization(beanFactory);
				// 通知完成此上下文的刷新
				finishRefresh();
			}
			catch (BeansException ex) {
				....
			}

			finally {
				....
			}
		}
	}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/355927.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号