IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringBoot2.5原理解析 -> 正文阅读

[Java知识库]SpringBoot2.5原理解析

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<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);//去除重复配置类信息
		Set<String> 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<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

  	result = new HashMap<>();
try {
	Enumeration<URL> 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<ConfigDataLocation> 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<PropertySource<?>> load(String name, Resource resource) throws IOException {
        if(resource == null || !resource.exists()){
            return Collections.emptyList();
        }

        Map<String, Object> 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 {
				....
			}
		}
	}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-29 12:51:50  更:2021-10-29 12:53:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:58:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码