首页 > 其他分享 >SpringBoot——核心原理入门

SpringBoot——核心原理入门

时间:2023-01-14 18:32:05浏览次数:58  
标签:SpringBoot spring 配置 boot Boot Spring 原理 public 入门

Spring Boot 概述

Build Anything with Spring Boot:**Spring Boot is the starting point for building all Spring-based applications. Spring Boot is designed to get you up and running as quickly as possible, with minimal upfront configuration of Spring.

上面是引自官网的一段话,大概是说: Spring Boot 是所有基于 Spring 开发的项目的起点。Spring Boot 的设计是为了让你尽可能快的跑起来 Spring 应用程序并且尽可能减少你的配置文件。

什么是 Spring Boot

  • 它使用 “习惯优于配置” (项目中存在大量的配置,此外还内置一个习惯性的配置,让你无须手动配置)的理念让你的项目快速运行起来。
  • 它并不是什么新的框架,而是默认配置了很多框架的使用方式,就像 Maven 整合了所有的 jar 包一样,Spring Boot 整合了所有框架

使用 Spring Boot 有什么好处

回顾我们之前的 SSM 项目,搭建过程还是比较繁琐的,需要:

  • 1、配置 web.xml,加载 spring 和 spring mvc
  • 2、配置数据库连接、配置日志文件
  • 3、配置家在配置文件的读取,开启注解
  • 4、配置mapper文件

而使用 Spring Boot 来开发项目则只需要非常少的几个配置就可以搭建起来一个 Web 项目,并且利用 IDEA 可以自动生成生成

  • 划重点:简单、快速、方便地搭建项目;对主流开发框架的无配置集成;极大提高了开发、部署效率。

spring boot工程需要导入依赖spring boot相关的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.10.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.yibo</groupId>
    <artifactId>springboot-source-code</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

编写主程序

/**
 * @SpringBootApplication来标注一个主程序类,说明这是一个SpringBoot应用
 */
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
		//Spring应用启动
        SpringApplication.run(Application.class,args);
    }
}

Springboot探究

POM文件

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.1.10.RELEASE</version>
	<relativePath/> <!-- lookup parent from repository -->
</parent>

父项目

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.1.10.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
  </parent>

该父项目是真正管理Spring Boot应用里面的所有依赖的版本:Spring Boot的版本仲裁中心,所以以后导入的依赖默认是不需要版本号。如下

  <properties>
    <activemq.version>5.15.10</activemq.version>
    <antlr2.version>2.7.7</antlr2.version>
    <appengine-sdk.version>1.9.76</appengine-sdk.version>
    <artemis.version>2.6.4</artemis.version>
    <aspectj.version>1.9.4</aspectj.version>
    <assertj.version>3.11.1</assertj.version>
    <atomikos.version>4.0.6</atomikos.version>
    <bitronix.version>2.1.4</bitronix.version>
    <build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version>
    <byte-buddy.version>1.9.16</byte-buddy.version>
    <caffeine.version>2.6.2</caffeine.version>
    <cassandra-driver.version>3.6.0</cassandra-driver.version>
    <classmate.version>1.4.0</classmate.version>
    <commons-codec.version>1.11</commons-codec.version>
    <commons-dbcp2.version>2.5.0</commons-dbcp2.version>
    <commons-lang3.version>3.8.1</commons-lang3.version>
    <commons-pool.version>1.6</commons-pool.version>
    <commons-pool2.version>2.6.2</commons-pool2.version>
    <couchbase-cache-client.version>2.1.0</couchbase-cache-client.version>
    <couchbase-client.version>2.7.9</couchbase-client.version>
    <dependency-management-plugin.version>1.0.8.RELEASE</dependency-management-plugin.version>
    ......
  </properties>

启动器

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

spring-boot-starter: spring boot场景启动器;帮助导入web模块正常运行所依赖的组件;

 

Spring Boot将所有的功能场景抽取出来,做成一个个的starter(启动器),只需要在项目中引入这些starter,那么相关的场景的所有依赖都会导入进项目中。要用什么功能就导入什么场景的启动器。

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.1.10.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-json</artifactId>
      <version>2.1.10.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.1.10.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.18.Final</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.1.11.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.11.RELEASE</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

添加spring-boot-starter-web 依赖,会自动添加 Tomcat 和 Spring MVC等依赖,并且spring-boot-starter-web中又引入了spring-boot-starter-tomcat

主程序类(主入口类)

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

@SpringBootApplication Spring Boot应用标注在某个类上,说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用。 注解定义如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}

@SpringBootConfiguration

  • Spring Boot的配置类
  • 标注在某个类上,表示这是一个Spring Boot的配置类 注解定义如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

其实就是一个Configuration配置类,意思是Application最终会被注册到Spring容器中

@EnableAutoConfiguration

  • 开启自动配置功能
  • 以前使用Spring需要配置的信息,Spring Boot帮助自动配置;
  • @EnableAutoConfiguration通知SpringBoot开启自动配置功能,这样自动配置才能生效。 注解定义如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

@AutoConfigurationPackage

  • 自动配置包注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}

@Import(AutoConfigurationPackages.Registrar.class):默认将主配置类(@SpringBootApplication)所在的包及其子包里面的所有组件扫描到Spring容器中。如下

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
	Registrar() {
	}

	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        //默认将会扫描@SpringBootApplication标注的主配置类所在的包及其子包下所有组件
		AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
	}

	public Set<Object> determineImports(AnnotationMetadata metadata) {
		return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
	}
}

@Import({AutoConfigurationImportSelector.class}) AutoConfigurationImportSelector: 导入哪些组件的选择器,将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中。

AutoConfigurationImportSelector{
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!this.isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		} else {
			AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
			AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
			return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
		}
	}

	protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
		if (!this.isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		} else {
			AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
			List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
			configurations = this.removeDuplicates(configurations);
			Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
			this.checkExcludedClasses(configurations, exclusions);
			configurations.removeAll(exclusions);
			configurations = this.filter(configurations, autoConfigurationMetadata);
			this.fireAutoConfigurationImportEvents(configurations, exclusions);
			return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
		}
	}
}

我们主要看List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);attributes);会给容器中注入众多的自动配置类(xxxAutoConfiguration),就是给容器中导入这个场景需要的所有组件,并配置好这些组件。我们跟进去看看

public class AutoConfigurationImportSelector{
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
	List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
	Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
	return configurations;
}

    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }

    protected ClassLoader getBeanClassLoader() {
        return this.beanClassLoader;
    }
}

public final class SpringFactoriesLoader{
	public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		//获取缓存中的配置
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
				//从类路径的META-INF/spring.factories中加载所有默认的自动配置类
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryClassName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryName = var9[var11];
                            result.add(factoryClassName, factoryName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }
}

SpringBoot启动的时候通过SpringFactoriesLoader从类路径下的 META-INF/spring.factories中获取EnableAutoConfiguration指定的值,并将这些值作为自动配置类导入到容器中,自动配置类就会生效,最后完成自动配置工作。EnableAutoConfiguration默认在spring-boot-autoconfigure这个包中,如下图: 最终有96个自动配置类被加载并注册进Spring容器中

 

J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-xxx.jar中。在这些自动配置类中会通过@ConditionalOnClass等条件注解判断是否导入了某些依赖包,从而通过@Bean注册相应的对象进行自动配置。

 

参考: https://www.cnblogs.com/java-chen-hao/p/11829056.html

标签:SpringBoot,spring,配置,boot,Boot,Spring,原理,public,入门
From: https://blog.51cto.com/u_14014612/6007650

相关文章

  • SpringBoot——初始化器解析
    初始化器Spring是一个扩展性很强的容器框架,为开发者提供了丰富的扩展入口,其中一个扩展点便是ApplicationContextInitializer(应用上下文初始化器)。 ApplicationConte......
  • SpringBoot——监听器解析
    监听器模式监听器模式有要素事件监听器广播器触发机制系统监听器监听器ApplicationListener@FunctionalInterfacepublicinterfaceApplicationListener<Eext......
  • Web安全入门与靶场实战(5)- 安装DVWA
    搭建好LAMP环境之后,我们再继续通过安装一个真实的网站,从而更加真切地了解网站的整体架构,这里我们要安装的网站是DVWA。DVWA(DamnVulnerableWebApp)是用PHP+MySQL编写的一个......
  • winsock编程:基于select的I/O复用模型的原理及编程
       大家好,我是一多,今天是东北的小年(2023/1/14),发一篇随笔证明我还活着吧(好久没更新了)     本文讲的是windows上的套接字编程中的基于select的I/O复用模型的......
  • QML入门教程(1): Qt Quick与QML介绍
    1什么是QtQucik?         QtQuick是QtSDK4.7中引入的一种新的界面开发框架,使用QtQuick,你可以快速、轻松地创建供移动和嵌入式设备使用的动态触摸式......
  • leetcode算法入门 Day5 双指针(四)
    876.链表的中间结点给定一个头结点为head的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。输入:[1,2,3,4,5]输出:此列表中的结点3(序......
  • 鸿蒙系统应用开发之入门解说
    Hi,欢迎大家在有空的时候做客【江涛学编程】,这里是2023年的第11篇原创文章,同学,我们又见面啦,今天我们继续聊下上一期讲的那个话题------鸿蒙系统应用开发入门解说老规矩,......
  • 230113_50_SpringBoot入门
    EnableAutoConfiguration详解​ SpringBoot可以实现自动配置;@EnableAutoConfiguration注解用于告知springboot开启自动配置功能,这样自动配置才能生效。@AutoConfigura......
  • jQuery入门
    jQuery入门1、基础语法jQuery语法是通过选取HTML元素,并对选取的元素执行某些操作。基础语法:$(selector).action()美元符号定义jQuery选择符(selector)"查询"和"查......
  • 说说开发中常用的USART的协议和工作原理
    1、什么是串口USART?USART是全双工通用同步/异步收发器,是一种串行的通信设备。在嵌入式开发设计中经常被使用到,广泛的被应用于主机与外围设备的通信交互中,应用相当的广泛。​......