SpringBoot学习笔记

本文较长,可以根据目录选择自己需要的部分进行阅读

目录

  • 基础使用
  • 源码分析
  • 数据访问
  • 视图技术
  • 缓存管理

1. 基础使用

1.1 SpringBoot的优点

  • 起步依赖
    • 只需引入一个starter就包含了特定场景所需的依赖,如 spring-boot-starter-web 内包含了tomcat、spring-web、spring-webmvc
    • 父项目统一管理依赖版本,子项目引入时不需要关心版本号,通过依赖传递获取,spring-boot-dependencies 内可以看见许多常见技术框架的依赖版本
  • 自动装配
    • 添加依赖后,能自动配置组件的配置,使用时可以不配或者少量配置就能运行项目,如添加了 spring-boot-starter-web 之后,不需要配置视图解析器、前端控制器等

1.2 单元测试

  • SpringBoot 推荐使用 JUint5 进行测试,使用IDEA 创建项目时就剔除了对JUint3、4的依赖
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
  • 非 web 下,单元测试只需要使用 @SpringBootTest 和 @Test 即可

1.3 配置文件

  • 配置文件的加载顺序
    • spring-boot-starter-parent 可以查阅到加载顺序:application*.yml => application*.yaml => application*.propertis
    • 因此,如果出现相同属性,属性值会被后面加载的配置文件覆盖
  • 配置文件格式
    • propertie
      # 简单数据类型直接赋值
      person.id=1
      person.name=1
      
      # 数组或者集合用逗号分隔,前后的中括号会自动补全
      person.hobby=吃饭,睡觉,打豆豆
      person.family=father,mother
      
      # map形式
      person.map.k1=v1
      person.map.k2=v2
      
      # 对象用 对象名称.属性名=xx
      person.pet.type=dog
      person.pet.name=旺财
      
    • yaml
      person:
        id: 2
        name: 2
        hobby: 吃饭,睡觉,打豆豆
        family: father,mother
        map: {k1: v1,k2: v2}
        pet:
          type: dog
          name: 旺财
      
  • 配置文件属性值的注入方式
    • @Comfiguration + @ConfigurationProperties(prefix = “xx”),会按照前缀注入,支持的类型多
    • @Comfiguration + @Value("${xx.xx}"),只适合简单数据类型注入,优点是可以设置默认值,如 @Value("${xx.xx : 233}")
    • tips:加入下面的依赖,编写配置文件时会有书写提示和跳转到配置类
      <dependency>
      	<groupId>org.springframework.boot</groupId>
      	<artifactId>spring-boot-configuration-processor</artifactId>
      	<optional>true</optional>
      </dependency>
      
  • 自定义配置文件
    • @Configuration // 表明为配置类
    • @PropertySource(“classpath:test.properties”) // 指定自定义文件文件位置和名称
    • @EnableConfigurationProperties(MyProperties.class) // 开启对应配置类的属性注入功能
    • @ConfigurationProperties(prefix = “test”) // 按前缀注入
  • 随机参数和参数间引用
    # 表达式里的值都来源于RandomValuePropertySource
    my.secret=${random.value} 随机值
    my.number=${random.int} // 随机整数
    my.bignumber=${random.long} // 随机长整数
    my.uuid=${random.uuid} // 随机uuid
    my.number.less.than.ten=${random.int(10)} // 小于10的随机整数
    my.number.in.range=${random.int[1024,65536]} // [1024,65536]之间的随机整数
    
    # 参数引用
    my.money.copy=${my.money}
    

2. 源码分析

2.1 依赖管理

  • 父项目管理依赖版本,子项目引入依赖时不需要指定版本
    • 在子项目的 pom.xml 可以看到 parent 标签,里面是 spring-boot-starter-parent,底层还有一个父依赖 spring-boot-dependencies,里面的 properties 属性管理了一些常用技术框架的依赖版本
  • 子项目引入父项目 spring-boot-starter-parent 之后,通过 maven的 依赖传递 方式引入依赖,不仅不需要关心版本号,也不需要关心依赖之间存在版本冲突的问题

2.2 自动配置

首先,启动类 @SpringBootApplication 包含了3个重要的注解
在这里插入图片描述

2.2.1 @SpringBootConfiguration

@SpringBootConfiguration 的内部有一个 @Configuration 注解,该注解由 Spring 提供,表明是一个配置类,代替 XML,可以被组件扫描器扫描

2.2.2 @EnableAutoConfiguration

表示开启自动配置功能,内部包含了 @AutoConfiguration 和 @Import 两个重要的注解
在这里插入图片描述

  • @AutoConfigurationPackage 的作用是将主程序类所在的包及所有子包下的组件扫描到 Spring 容器,因此启动类的配置应该在项目做外层的根目录,@AutoConfigurationPackage 的内部还导入了一个组件类 Registrar ,该类做了以下几件事
    • 1.读取启动类所在的包名
      在这里插入图片描述
    • 2.将AutoConfigurationPackages 注册 beanDefinitionMap中
      在这里插入图片描述
  • @Import(AutoConfigurationImportSelector.class) 的作用是将 AutoConfigurationImportSelector 导入到 Spring 容器,该类可以将所有符合条件的 @Configuration 配置都加载到当前 SpringBoot 创建的 IoC 容器,具体步骤如下
    在这里插入图片描述
    • 1.selectImports 是告诉 SpringBoot 需要导入哪些组件的入口方法
    • 2.loadMetadata 负责加载 META-INF/spring-autoconfigure-metadata.properties ,获取所有支持自动配置类的条件,内容格式为 自动配置的类全名.条件=值,当符合条件时就会加载该类,比如:org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.ConditionalOnClass=Servlet,WebMvcConfigurer,DispatcherServlet,ConditionalOnClass 表示如果Servlet、WebMvcConfigurer、DispatcherServlet等类在当前classpatch路径下,那么就会加载 WebMvcAutoConfiguration,里面就有我们的视图解析器在这里插入图片描述
    • 3.getAutoConfigurationEntry 里面有个 getCandidateConfigurations 方法,通过调用工具类 SpringFactoriesLoaderloadFactoryNames 方法,加载 META-INF/spring.factories,获取默认支持的自动配置类名列表(即key为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的value),最后导入事件通知监听器,SpringBootApplication 调用 run 方法时就生效了
      在这里插入图片描述META-INF/spring.factories 截取的片段可以看到 EnableAutoConfiguration 默认支持这些自动配置类

总的来说,SpringBoot 底层实现自动配置的步骤是:

  1. SpringBoot 应用启动
  2. @SpringBootApplication 起作用
  3. @EnableAutoConfiguration 包含两个核心注解
  4. @AutoConfigurationPackage 通过导入 Registrar 扫描主程序类所在的包及所有子包下的组件扫描到 Spring 容器
  5. @Import 导入 AutoConfigurationimportSelector ,将所有符合条件的 @Configuration 配置都加载到当前 SpringBoot 创建的 IoC 容器

2.2.3 @ComponentScan

根据 @AutoConfigurationPackage 获取的包路径从中找出标识了需要装配的类自动装配到Spring容器中,如常用的@Controller、@Service、@Repository

2.3 自定义starter

  1. 新建maven工程,根据命名规范,工程名为 zdy-spring-boot-starter,并引入依赖 spring-boot-autoconfigure
    <groupId>org.example</groupId>
    <artifactId>zdy-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>
    </dependencies>
    
  2. 编写配置类 SimpleBean,贴上注解 @EnableConfigurationProperties 和 @ConfigurationProperties
    @EnableConfigurationProperties(SimpleBean.class)
    @ConfigurationProperties(prefix = "simpleBean")
    public class SimpleBean {
        private int id;
        private String name;
        // setter/getter/toString
    }
    
  3. 编写自动配置类 MyAutoConfiguration,贴上注解 @Configuration 和 @ConditionalOnClass
    @Configuration
    @ConditionalOnClass // 当类路径classpath下有指定的类的情况下进行自动配置
    public class MyAutoConfiguration {
        @Bean
        public SimpleBean simpleBean() {
            return new SimpleBean();
        }
    }
    
  4. 在 resources 下创建 META-INF/spring.factories,内容为
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=MyAutoConfiguration类的路径
    
  5. 在另一个工程引入 zdy-spring-boot-starter
    <dependency>
        <groupId>org.example</groupId>
        <artifactId>zdy-spring-boot-starter</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    
  6. 在全局配置文件中配置属性值
    simpleBean.id=666
    simpleBean.name=自定义stater
    
  7. 编写测试方法
    @SpringBootTest
    public class CustomTest {
        @Autowired
        private SimpleBean simpleBean;
        
        @Test
        public void zdy() {
            System.out.println(simpleBean);
            // 预期:SimpleBean{id=666, name='自定义stater'}
        }
    }
    

2.4 启动原理

SpringBootApplication.run 做了两件事:SpringBootApplication的实例化以及调用 run 方法

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

2.4.1 SpringBootApplication的实例化

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	// 1.把项目启动类的class对象设置属性
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	// 2.推断并设置应用类型(查看 classpath 类路径下面是否存在某个特征类,是SERVLET应用还是REACTIVE应用)
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	// 3.设置初始化器
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	// 4.设置监听器
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	// 5.推断并设置项目 main 方法的启动类(从堆栈中查找包含 main 方法的栈)
	this.mainApplicationClass = deduceMainApplicationClass();
}
  • getSpringFactoriesInstances
    调用工具类 SpringFactoriesLoaderloadFactoryNames 方法,加载 META-INF/spring.factories,获取对应key的value

2.4.2 调用 run 方法

public ConfigurableApplicationContext run(String... args) {
	...
	// 1.获取并启动监听器
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		// 2.根据 SpringApplicationRunListeners 和参数准备环境
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		// 3.创建Spring容器
		context = createApplicationContext();
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
		// 4.Spring容器前置处理
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
		// 5.刷新容器
		refreshContext(context);
		// 6.Spring容器后置处理
		afterRefresh(context, applicationArguments);
		...
		// 7.发出结束执行的事件(后续的处理有自动配置)
		listeners.started(context);
		callRunners(context, applicationArguments);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}

	try {
		// 8.执行Runners(自定义执行器)
		listeners.running(context);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

最后一张流程图描述启动原理
在这里插入图片描述

3. 数据访问

3.1 SpringBoot 集成 MyBatis

3.2 SpringBoot 集成 JPA

3.1 SpringBoot 集成 Redis

4. 视图技术

4.1 SpringBoot支持哪些视图

4.2 为什么SpringBoot不支持JSP

4.3 Tymeleaf

5. 缓存管理

5.1 默认缓存

5.2 集成 Redis

5.3 自定义 Redis 缓存序列化机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

火车站卖橘子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值