SpringBoot基础学习之原理初探

前言

小伙伴们,大家好,我是狂奔の蜗牛rz,当然你们可以叫我蜗牛君,我是一个学习Java半年多时间的小菜鸟,同时还有一个伟大的梦想,那就是有朝一日,成为一个优秀的Java架构师。
这个SpringBoot基础学习系列用来记录我学习SpringBoot框架基础知识的全过程 (这个系列是参照B站狂神的SpringBoot最新教程来写的,由于是之前整理的,但当时没有发布出来,所以有些地方可能有错误,希望大家能够及时指正!)
之后我将会以一天一更的速度更新这个系列,还没有学习SpringBoot的小伙伴可以参照我的博客学习一下;当然学习过的小伙伴,也可以顺便跟我一起复习一下基础。
最后,希望能够和大家一同进步吧!加油吧!少年们!
废话不多说,让我们开始今天的学习内容吧,今天我们来到了SpringBoot基础学习的第三站:原理初探!

3.原理初探

3.1 自动配置

3.1.1 查看pom.xml配置文件

  • spring-boot-dependencies:核心依赖在父工程中

在这里插入图片描述

  • 点击spring-boot-starter-parent后:

在这里插入图片描述

  • 引入SpringBoot依赖时,不需要指定版本,因为有这些版本仓库

在这里插入图片描述

3.1.2 启动器

<!--spring-boot-starter-web:用于实现HTTP接口(该依赖中包含了Spring MVC)
    官方解释:使用SpringMVC构建Web(包括RestFul)应用程序的入门者,使用Tomcat作为默认嵌入式容器-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

启动器其实就是SpringBoot的启动场景

  • spring-boot-starter-web,它会帮我们自动导入web环境所有的依赖
  • SpringBoot会将所有的功能场景,都变成一个个的启动器
  • 要使用什么功能,只需要找到对应的启动器即可

3.1.3 主程序

1.查看HelloworldApplication主程序
//@SpringBootApplication注解本身就是Spring的一个组件
//标注这个类是一个springboot的应用
//程序的主入口
@SpringBootApplication
public class HelloworldApplication {
    public static void main(String[] args) {
        //将Springboot应用启动
        SpringApplication.run(HelloworldApplication.class, args);
    }
}
2.了解@SpringBootApplication注解
2-1 查看@SpringBootApplication注解源码
  • @SpringBootConfiguration@EnableAutoConfiguration两个核心注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration //Springboot的配置
@EnableAutoConfiguration //能够自动注解
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ......
}
2-2 查看@SpringBootConfiguration注解源码
  • 发现@SpringBootConfiguration有一个@Configuration 注解,即Spring配置类
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration //Spring配置类
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}
  • 继续查看@Configuration注解,发现有一个@Component注解,即组件
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component //组件
public @interface Configuration {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";

    boolean proxyBeanMethods() default true;
}
  • 再接着查看@Component注解,发现其有一个@Indexed注解,即索引
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
    String value() default "";
}
  • 然后再查看@Indexed注解,发现有一个@Documented注解,即文档
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Indexed {
}
2-3 查看@EnableAutoConfiguration注解源码
  • 发现里面有两个核心注解@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)
@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注解源码:

  • 发现其中有一个@Import(AutoConfigurationPackages.Registrar.class),即导入选择器
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class) //导入选择器(包注册)
public @interface AutoConfigurationPackage {

	String[] basePackages() default {};

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

}
  • 继续查看Registrar源代码,观察其 registerBeanDefinitions方法有一个参数metadata,表示数据源,其中register方法作用是注册到数据源
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
//selector和register这两个类就是手动往容器中注入类的
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
 //注册到源数据,其中metadata表示源数据   
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}

@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
    return Collections.singleton(new PackageImports(metadata));
}

}

查看@Import(AutoConfigurationImportSelector.class)注解源码

  • 查看AutoConfigurationImportSelector类,即自动配置导入选择器,其有一个selectImports方法,即选择pom.xml配置文件中的组件
//自动配置导入选择器
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();//获取自动化配置数组
    ......
    //选择组件,导入pom.xml配置文件中的组件
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
  • AutoConfigurationImportSelector类还有一个getAutoConfigurationEntry,激活去自动配置数组的方法,其中有一个getCandidateConfiguration方法来获取候选的配置
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    //获取候选的配置
    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);
}
  • 继续查看getCandidateConfiguration方法是如何来获取候选的配置的,发现使用了getSpringFactoriesLoaderFactoryClass获取Spring工厂的加载器和getBeanClassLoader获取Bean对象的加载器两个方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    //通过SpringFactoriesLoader加载器来获取Spring工厂,然后通过getBeanClassLoader类加载器来获取Bean对象
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                                                                         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;
}
  • 我们来查看getBeanClassLoader方法的源码,发现其返回了一个类加载器
private ClassLoader beanClassLoader;
//当前类的加载器
protected ClassLoader getBeanClassLoader() {
    return this.beanClassLoader;
}
  • 我们再查看另一个getSpringFactoriesLoaderFactoryClass方法,其返回了一个EnableAutoConfiguration类,即标注这个类的所有包,它被SpringBootApplication集成
//getCandidateConfigurations:获取候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    //getSpringFactoriesLoaderFactoryClass获取工厂,getBeanClassLoader获取Bean对象
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                                                                         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;
}
//EnableAutoConfiguration:标注这个类的所有包,它被SpringBootApplication集成了
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}
  • 再次返回到刚开始HelloworldApplication类,我们对@SpringBootApplication注解有了更深层的理解,使用该注解,标注该类是SpringBoot的应用,启动类下的所有资源被导入
//标注这个类是一个springboot的应用:启动类下的所有资源被导入
@SpringBootApplication
public class HelloworldApplication {
    public static void main(String[] args) {
        //将Springboot应用启动
        SpringApplication.run(HelloworldApplication.class, args);
    }
}
  • 继续查看getCandidateConfigurations方法后,发现在通过SpringFactoriesLoader加载器来获取工厂,然后通过getBeanClassLoader加载器获取类后,有一个断言非空方法:其中包含有一个META-INF/spring.factorie文件,那么它到底是什么呢?
//getCandidateConfigurations:获取候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    //getSpringFactoriesLoaderFactoryClass:加载类的class
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                                                                         getBeanClassLoader());
    //断言非空: META-INF/spring.factorie是一个自动配置的核心文件
    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;
}
//EnableAutoConfiguration:标注这个类的所有包,它被SpringBootApplication集成了
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}
  • 通过一番查找后,我们最终在spring-boot-autoconfigure.jar包下的META-INF文件下找到了spring.factorie,点击进去后,我们发现它实际上是一个自动配置的核心文件:

在这里插入图片描述

  • spring.factorie的详细信息如下:
# Initializers 初始化
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners 应用监听器
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners 自动配置导入监听器
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters 自动配置导入过滤器
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# Auto Configure 自动配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
# .....(中间省略部分内容)
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

# Failure analyzers 失败分析器
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.data.redis.RedisUrlSyntaxFailureAnalyzer,\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
# 数据源Bean创建失败分析器
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

# Template availability providers 模板的可用性提供者
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
# FreeMarker模板
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
# Thymeleaf模板
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
# JSP模板
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

3.1.4 结论

总结

SpringBoot所有自动配置都是在启动的时候扫描并加载,spring.factories所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了相应的starter,就有对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功!

  • SpringBoot在启动的时候,从类路径下/META/spring.factories 获取指定的值
  • 将这些自动配置的类导入容器,自动配置就会生效,帮我们进行自动配置
  • 以前我们需要自动配置的东西,现在SpringBoot帮我们做了
  • 整合JavaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.2.0.RELEASE.jar这个包下
  • 它会把所有需要导入的主键,以类名的方式返回,这些组件就会被添加到容器
  • 容器中也会存在非常多的xxxAutoConfiguration的文件 (@Bean),就是这些类给容器中导入了这个场景需要的所有组件,并自动配置,@Configuration,@JavaConfig
  • 有了自动配置类,免去了我们手动编写配置文件的工作

3.2 了解主启动类如何运行

3.2.1 查看HelloworldApplication主启动类

  • 本来以为主启动类只是运行了一个main方法,没想到却开启了一个服务
package com.kuang.helloworld;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//@SpringBootApplication注解本身就是Spring的一个组件
//标注这个类是一个springboot的应用:启动类下的所有资源被导入
//程序的主入口
@SpringBootApplication
public class HelloworldApplication {
    public static void main(String[] args) {
        //将Springboot应用启动
        //通过调用SpringApplication类的run方法
        //本来以为只是运行了一个main方法,没想到却开启了一个服务
        SpringApplication.run(HelloworldApplication.class, args);
    }
}

因此我们可以从两方面进行分析:一是SpringApplication类的实例化,二是run方法的执行

3.2.2 SpringApplication类的实例化

1.SpringApplication类作用

SpringApplication类主要做了以下四件事:

  • 推断应用的类型是否是普通项目还是Web项目
  • 查找并加载所有可用初始化器,设置到 initializers属性中
  • 找出所有的应用程序监听器,设置到 listeners属性中
  • 推断并设置main方法的定义类,找到其运行的主类
2.查看SpringApplication类的有参构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.sources = new LinkedHashSet();
    this.bannerMode = Mode.CONSOLE;
    this.logStartupInfo = true;
    this.addCommandLineProperties = true;
    this.addConversionService = true;
    this.headless = true;
    this.registerShutdownHook = true;
    this.additionalProfiles = Collections.emptySet();
    this.isCustomEnvironment = false;
    this.lazyInitialization = false;
    this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
    this.applicationStartup = ApplicationStartup.DEFAULT;
    this.resourceLoader = resourceLoader; //resourceLoader:资源加载器
    //断言初始资源(primarySources)是否为空
    Assert.notNull(primarySources, "PrimarySources must not be null");
    //获取初始资源(primarySources)
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
    //判断应用类型是否是web项目
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //调用getSpringFactoriesInstances方法(即获取Spring工厂实例)来获取引导(启动)类加载器对象(bootstrapper)
    this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
//调用获取工厂实例(getSpringFactoriesInstances)方法(通过反射机制)将上下文中可用的初始化器设置到初始化器(Initializers)里
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//从上下文中获取可用的监听器设置到Listeners中(同样利用了反射机制)   
 this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    //通过推断来获取运行的主程序类
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

3.2.3 查看run方法的执行

1.查看run方法源码
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class[]{primarySource}, args);
}
2.继续查看run方法源码
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return (new SpringApplication(primarySources)).run(args);
}

JavaConfig的核心是:@Configuration (配置) 和 @Bean (组件)

关于SpringBoot,谈谈你的理解:

  • 自动装配
  • run方法

好了,今天的有关SpringBoot原理初探的学习就到此结束啦,欢迎小伙伴们积极学习和讨论,喜欢的可以给蜗牛君点个关注,顺便来个一键三连,我们下期见,拜拜啦!


参考视频链接:https://www.bilibili.com/video/BV1PE411i7CV(【狂神说Java】SpringBoot最新教程IDEA版通俗易懂)

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狂奔の蜗牛rz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值