SpringBoot 2.x 时代 – 基础入门篇

视频学习地址:https://www.bilibili.com/video/BV1Et411Y7tQ?p=112&spm_id_from=pageDriver

1、Spring与SpringBoot

1.1、Spring是什么?Spring能做什么?

Spring 被称为 J2EE 的春天,是一个开源的轻量级的 Java 开发框架, 具有控制反转(IOC)面向切面(AOP)两大核心。Java Spring 框架通过声明式方式灵活地进行事务的管理,提高开发效率和质量。

Spring 框架不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。

那么Spring能做什么呢?在Spring官网介绍得知:

1.2、Spring 5 的重大升级

Spring 5于2017年9月发布了通用版本,它是自2013年12月以来第一 个主要的Spring版本。它提供了一些人们期待已久的改进,还采用了一种全新的编程范例,以反应式原则为基础。

这个版本是很长时间以来最令人激动的版本。Spring 5兼容JavaTM8 和JDK 9,它集成了反应式流,以方便后续提供一种颠覆性方法来实现端点和Web应用程序开发。

spring5带来的特性和改变,主要包含以下关键内容:

  1. JDK 基线和库更新、支持
  2. 使用JDK8和JDK9新特性
  3. 反应式编程模型
  4. 含 Kotlin 在内的函数式编程
  5. 测试改进和提升
  6. spring核心迭代和一般性修订
  7. 中止支持等等

这也导致了SpringBoot2.0在内部设计上比较1.0版本发生了很多改变,所以了解一些Spring5的新特性,对于我们学习Spring2.0有很大的帮助。

1.2.1、响应式编程

Spring 5 Framework 基于一种反应式基础而构建,而且是完全异步和非阻塞的。只需少量的线程,新的事件循环执行模型就可以垂直扩展。

该框架采用反应式流来提供在反应式组件中传播负压的机制。负压是一个确保来自多个生产者的数据不会让使用者不堪重负的概念。

Spring WebFlux 是 Spring 5 的反应式核心,它为开发人员提供了两种为 Spring Web 编程而设计的编程模型:一种基于注解的模型和 Functional Web Framework (WebFlux.fn)。

基于注解的模型是 Spring WebMVC 的现代替代方案,该模型基于反应式基础而构建,而 Functional Web Framework 是基于 @Controller 注解的编程模型的替代方案。这些模型都通过同一种反应式基础来运行,后者调整非阻塞 HTTP 来适应反应式流 API。

所以SpringBoot2.0可以使用两种技术栈实现应用的开发:

  • 传统模式开发(Servlet Stack)
  • 响应式开发(Reactive Stack)。少量线程占有少量资源,更具优势。

1.2.2、内部源码设计

Spring5 的基准版本为8,因此它使用了 Java8 和9的许多新特性。例如:

  1. Spring 接口中的默认方法(JDK9)。

  2. 基于 Java8 反射增强的内部代码改进(JDK8)。

  3. 在框架代码中使用函数式编程 - lambda表达式 和 stream流(JDK8)。

  4. 支持HTTP/2(JDK9)。以下将针对JDK版本内容解释说明。

1、HTTP/2方面的支持

HTTP/2提高了传输性能,减少了延迟并提高了应用程序的吞吐量从而提供了丰富的Web体验。Spring 5提供专门的HTTP/2特性支持(由Tomcat 9.0、Jetty 9.3 和Undertow 1.4提供)。

2、Lambda表达式注册Bean实例

传统注册bean使用XML配置或者javaConfig进行实例,但是这些在5.0后也有新方案,我们可以使用Lambda表达式进行bean的实例处理:

context.registerBean(TestBean.class, () -> newTestBean(context.getBean(Test.class)));

所以在SpringBoot2.0中利用 Java 8 和 Java9 的新特性,大量重构了源码。

1.3、为什么要用SpringBoot ?

在Spring的官网里有这样一句话:

翻译过来就是:

SpringBoot使得创建独立的、生产级的基于Spring的应用程序变得很容易,并且您可以快速运行这些应用程序。

1.3.1、SpringBoot的优点

  • Create stand-alone Spring applications
    创建独立Spring应用
  • Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
    内嵌web服务器
  • Provide opinionated 'starter' dependencies to simplify your build configuration
    自动starter依赖,简化构建配置
  • Automatically configure Spring and 3rd party libraries whenever possible
    自动配置Spring以及第三方功能
  • Provide production-ready features such as metrics, health checks, and externalized configuration
    提供生产级别的监控、健康检查及外部化配置
  • Absolutely no code generation and no requirement for XML configuration
    无代码生成、无需编写XML
  • SpringBoot是整合Spring技术栈的一站式框架。
  • SpringBoot是简化Spring技术栈的快速开发脚手架。

1.3.2、SpringBoot的缺点

  • 人称版本帝、迭代速度快,需要时刻关注变化
  • 封装太深,内部原理复杂,不易精通

1.4、SpringBoot所处的时代背景

1.4.1、微服务

James Lewis and Martin Fowler (2014) 提出微服务完整概念。论文期刊地址:https://martinfowler.com/articles/microservices.html

In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.-- James Lewis and Martin Fowler (2014)

  • 微服务是一种架构风格
  • 一个应用拆分为一组小型服务
  • 每个服务运行在自己的进程内,也就是可独立部署和升级
  • 服务之间使用轻量级HTTP交互
  • 服务围绕业务功能拆分
  • 可以由全自动部署机制独立部署
  • 去中心化,服务自治。服务可以使用不同的语言、不同的存储技术

1.4.2、分布式


分布式的困难

  • 远程调用
  • 服务发现
  • 负载均衡
  • 服务容错
  • 配置管理
  • 服务监控
  • 链路追踪
  • 日志管理
  • 任务调度

分布式问题的解决:

SpringBoot + SpringCloud

1.4.3、云原生

原生应用如何上云。 Cloud Native

上云的困难

  • 服务自愈
  • 弹性伸缩
  • 服务隔离
  • 自动化部署
  • 灰度发布
  • 流量治理等等

上云问题的解决

  • Docker容器化技术
  • 容器编排Kubernetes
  • DevOps
  • Service Mesh与Serverless等等

1.5、如何学习SpringBoot ?

熟悉SpringBoot官网是最好的学习方式!官网地址:https://spring.io/projects/spring-boot

2、SpringBoot 2 入门

2.1、环境要求

  • Java 8 & 兼容 Java 14
  • Maven 3.3 +

修改 maven 全局配置文件(E:\maven\apache-maven-3.6.3\conf\settings.xml)

<!-- 指定本机仓库地址 -->
<localRepository>E:/maven/repository</localRepository><mirrors><mirror><id>alimaven</id><name>aliyun maven</name><url>http://maven.aliyun.com/nexus/content/groups/public/</url><mirrorOf>central</mirrorOf>        </mirror></mirrors><!-- 使用jdk 1.8 编译项目 --><profiles><profile><id>jdk1.8</id><activation><activeByDefault>true</activeByDefault><jdk>1.8</jdk></activation><properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion></properties></profile></profiles>

2.2、SpringBoot的第一个入门程序

2.2.1、实现步骤

1、创建一个maven工程(创建一个pom.xml文件)

2、引入依赖

<?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><groupId>com.laizhenghua</groupId><artifactId>boot-helloworld</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEASE</version></parent><dependencies><!-- web 场景启动器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies></project>

3、创建主程序

/*** @description: 主程序类* @author: laizhenghua* @date: 2021/3/23 21:39*/
@SpringBootApplication // 标注SpringBoot应用
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class,args);}
}

4、编写业务

/*** @description: 控制层* @author: laizhenghua* @date: 2021/3/23 21:44*/
@Controller
public class HelloController {@RequestMapping(value = "/hello",method = RequestMethod.GET)@ResponseBodypublic String hello() {return "hello world";}
}

5、启动主程序并测试

访问:http://localhost:8080/hello

2.2.2、简化配置初体验

resources目录下新建一个文件application.yml,这里使用yaml文件,也是官方推荐使用的,更多yaml的知识后面会涉及到。

server:port: 8888# 指定端口号servlet:context-path: /hello # 指定根路径

启动日志:Tomcat started on port(s): 8888 (http) with context path '/hello'

那么application properties/yaml 都可以配置那些内容呢?官方文档有详细介绍

https://docs.spring.io/spring-boot/docs/2.3.9.RELEASE/reference/html/appendix-application-properties.html#common-application-properties

2.2.3、简化部署

SpringBoot可以编译成可执行的 jar 包来简化部署。

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

把项目打成jar包,直接在目标服务器执行即可。

java -jar boot-helloworld-1.0-SNAPSHOT.jar

3、自动配置初体验

3.1、依赖管理

1、父项目做依赖管理

我们知道每个SpringBoot项目的pom.xml都有父项目依赖:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEASE</version>
</parent>
<!-- 几乎声明了所有开发中常用的依赖的版本号,无需关注版本号,自动版本仲裁机制(引入非版本仲裁的jar,要写版本号) -->

子项目都继承了父项目的依赖,言外之意就是父项目管理了大多数我们需要的依赖,当我们需要其他依赖时,只需要在子项目中引入即可。

当我们需要指定依赖版本号时,只需根据spring-boot-dependencies-2.x.x.RELEASE.pom的版本号标签名,在子项目中创建<properties>标签用于指定依赖版本号 – 就近优先原则。

例如:我们想要在子项目中引入MySQL 5.1.43 的依赖

1、查看spring-boot-dependencies里面规定当前依赖的版本的标签名。

2、在当前项目里面重写配置

 <properties><mysql.version>5.1.43</mysql.version></properties><!-- 注意以下坐标要在dependencies标签内 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>


2、开发导入starter场景启动器

在使用SpringBoot时,我们经常会看到spring-boot-starter-*,这样的引入方式。那么starter到底是什么呢?官方解释为:*就是某种场景,是一组依赖的集合描述!例如,如果要开始使用Spring和JPA进行数据库访问,使用spring-boot-starter-data-jpa在项目中包含依赖项。

只要引入starter,这个场景的所有常规需要的依赖我们都自动引入。SpringBoot所有支持的场景。当然我们也可以自定义自己的starter。

官方地址:https://docs.spring.io/spring-boot/docs/2.3.9.RELEASE/reference/html/using-spring-boot.html#using-boot-starter

见到的 *-spring-boot-starter: 第三方(非官方)为我们提供的简化开发的场景启动器。

所有场景启动器最底层的依赖(自动配置核心依赖):

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.3.9.RELEASE</version><scope>compile</scope>
</dependency>

3.2、自动配置

1、自动配好了Tomcat

  1. 引入依赖
  2. SpringBoot自动配置tomcat(关于自动配置原理,后面会详细介绍)
<!-- tomcat的依赖 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><version>2.3.9.RELEASE</version><scope>compile</scope>
</dependency>

2、自动配好SpringMVC

  1. 引入SpringMVC的全套组件的依赖
  2. 自动配好SpringMVC常用组件(Web常见功能,如:字符编码问题)

例如:我们可以在主程序中,查看SpringBoot自动为我们配好的组件。

/*** @description: 主程序类* @author: laizhenghua* @date: 2021/3/23 21:39*/
@SpringBootApplication // 标注SpringBoot应用
public class MainApplication {public static void main(String[] args) {// 1、返回IOC容器ConfigurableApplicationContext applicationContext = SpringApplication.run(MainApplication.class, args);// 2、查看容器里面的组件(组件名)String[] beanNames = applicationContext.getBeanDefinitionNames();// System.out.println(Arrays.toString(beanNames));for(String name: beanNames) {System.out.println(name);}}
}

打印出的结果我们可以看到:有dispatcherServlet、characterEncodingFilter、beanNameViewResolver、multipartResolver等等,这些组件在以前我们都要在web.xml中逐一配置!现在SpringBoot全部给我们配置好了。

3.3、默认的包结构

  • 重点记忆:主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
  • 无需以前的包扫描配置
  • 想要改变扫描路径,@SpringBootApplication(scanBasePackages="com.atguigu")。或者@ComponentScan指定扫描路径
@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")

3.4、各种配置拥有默认值

1、默认配置最终都是映射到某个类上,如:MultipartProperties.java

/*** Max file size.*/
private DataSize maxFileSize = DataSize.ofMegabytes(1); // 1MB// 文件上传最大可上传默认值(MultipartProperties.java代码节选)

2、配置文件的值最终会绑定每个类上,这个类会在容器中创建对象

# application.properties 配置文件里重新修改文件上传最大值
spring.servlet.multipart.max-file-size=10MB

3、按需加载所有自动配置项

  • 非常多的starter。
  • 引入了哪些场景这个场景的自动配置才会开启(自动配置按需加载)。
  • SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面。

4、容器功能

为了深入理解SpringBoot自动配置原理,我们先要了解SpringBoot底层注解的主要功能与作用!

4.1、添加组件时所用的注解

1、@Configuration 和 @Bean的基本使用与作用

现有一实体类Pet,如下代码所示:

/*** @description: pet实体类* @author: laizhenghua* @date: 2021/3/25 9:23*/
public class Pet {private String name;private Integer age;...// getter and setter// toString()
}

在Spring时,我们要给容器注册一个Pet组件,可以通过配置文件也可以通过Spring的注解(@Component)。如:

bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 向容器里注册一个组件Pet,id为pet --><bean id="pet" class="com.laizhenghua.boot_helloworld.bean.Pet"><property name="name" value="tom"/><property name="age" value="20"/></bean>
</beans>

但是在SpringBoot中,我们有了不同的实现方式,通过编写配置类来实现配置文件的的效果!

/*** @description: 配置类* @author: laizhenghua* @date: 2021/3/25 9:40*/
@Configuration // 标准这个类是一个配置配置类,这个类等同于配置文件
public class MyConfig {// @Bean("tom") 自定义组件id@Bean // 给容器中添加组件,方法名作为组件的id,返回值类型就是组件类型,方法返回值就是组件中的实例!public Pet pet() {Pet pet = new Pet();pet.setName("tom");pet.setAge(20);return pet;}/*<bean id="pet" class="com.laizhenghua.boot_helloworld.bean.Pet"><property name="name" value="tom"/><property name="age" value="20"/></bean>*/
}

主程序中测试组件:

/*** @description: 主程序类* @author: laizhenghua* @date: 2021/3/23 21:39*/
@SpringBootApplication // 标注SpringBoot应用
public class MainApplication {public static void main(String[] args) {// 1、返回IOC容器ConfigurableApplicationContext applicationContext = SpringApplication.run(MainApplication.class, args);// 2、查看容器里面的组件(组件名)String[] beanNames = applicationContext.getBeanDefinitionNames();// System.out.println(Arrays.toString(beanNames));for(String name: beanNames) {if("pet".equals(name)){System.out.println("debug => " + name);Pet pet = (Pet) applicationContext.getBean(name);System.out.println(pet);}}}
}

输出结果:

1、值得注意的是,容器中注册进去的组件默认是 单例模式 的!验证如下:

/*** @description: 主程序类* @author: laizhenghua* @date: 2021/3/23 21:39*/
@SpringBootApplication // 标注SpringBoot应用
public class MainApplication {public static void main(String[] args) {// 1、返回IOC容器ConfigurableApplicationContext applicationContext = SpringApplication.run(MainApplication.class, args);// 2、查看容器里面的组件(组件名)String[] beanNames = applicationContext.getBeanDefinitionNames();// System.out.println(Arrays.toString(beanNames));for(String name: beanNames) {if ("pet".equals(name)) {System.out.println("debug => " + name);Pet pet1 = applicationContext.getBean("pet", Pet.class);Pet pet2 = applicationContext.getBean("pet", Pet.class);System.out.println(pet1 == pet2); // true}}}
}

2、@Configuration标注的类本身也是一个组件

/*** @description: 主程序类* @author: laizhenghua* @date: 2021/3/23 21:39*/
@SpringBootApplication // 标注SpringBoot应用
public class MainApplication {public static void main(String[] args) {// 1、返回IOC容器ConfigurableApplicationContext applicationContext = SpringApplication.run(MainApplication.class, args);// 2、查看容器里面的组件(组件名)MyConfig bean = applicationContext.getBean(MyConfig.class);System.out.println(bean);// com.laizhenghua.boot_helloworld.config.MyConfig$$EnhancerBySpringCGLIB$$30ab059a@6e78fcf5}
}

3、@Configuration(proxyBeanMethods = true)。proxyBeanMethods:代理bean的方式(可以理解为配置类调用内部注册到容器的组件是否为单例)。这里也是与SpringBoot 1.0 不同的地方。

我们可以看到这个属性值的默认值也是true。可点进去查看源码!

关于属性proxyBeanMethods测试与总结:

/*** @description: 主程序类* @author: laizhenghua* @date: 2021/3/23 21:39*/
@SpringBootApplication // 标注SpringBoot应用
public class MainApplication {public static void main(String[] args) {// 1、返回IOC容器ConfigurableApplicationContext applicationContext = SpringApplication.run(MainApplication.class, args);// 2、查看容器里面的组件(组件名)MyConfig bean = applicationContext.getBean(MyConfig.class); // 代理对象Pet pet1 = bean.pet();Pet pet2 = bean.pet();System.out.println(pet1 == pet2); // true// 结论:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册到容器中的单实例对象。/*@Configuration(proxyBeanMethods = true) 调用内部注册的组件的逻辑:1、SpringBoot先判断这个内部方法(注册的组件)是否在容器中存在2、如果存在,则在内存中就不创建新的组件3、如果不存在就创建新的,保证是单例。@Configuration(proxyBeanMethods = false) 即每次调用的创建新的组件!跳过判断检查,运行速度快!*/}
}

小结:

  • @Configuration(proxyBeanMethods = true)Full模式(全模式) – 保证每个@Bean方法被调用多少次返回的组件都是单实例的
  • @Configuration(proxyBeanMethods = false)Lite模式(轻量级模式) – 每个@Bean方法被调用多少次返回的组件都是新创建的
  • 组件依赖必须使用 Full 模式,并且也是默认的。其他默认都是 Lite 模式

最佳实战:

  • 配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
  • 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式

4.2、其他常见注解

@Component、@Controller、@Service、@Repository

以上注解具体的作用和使用方式已在Spring中讲过了。小伙伴们可自行查看!

1、@ComponentScan: 指定扫描包的范围。

加了包扫描@ComponentScan注解后,只要标注了@Controller、@Service、@Repository、@Component注解中的任何一个,其组件都会被自动扫描,加入到容器中。

例如:以前在Spring的配置文件中我们可以这样书写:

<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.howie"/>

使用@ComponentScan代替以上配置文件:

@SpringBootApplication // 标注SpringBoot应用
@ComponentScan(value = "com.howie")
public class MainApplication {...
}

2、@Import:将指定类型的组件导入到当前容器中

/*
@Import({User.class, DBHelper.class}):给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
*/@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = true) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {...
}

测试:

/*** @description: 主程序类* @author: laizhenghua* @date: 2021/3/23 21:39*/
@SpringBootApplication // 标注SpringBoot应用
public class MainApplication {public static void main(String[] args) {// 1、返回IOC容器ConfigurableApplicationContext applicationContext = SpringApplication.run(MainApplication.class, args);// 2、查看容器里面的组件(组件名)DBHelper bean = applicationContext.getBean(DBHelper.class);System.out.println(bean);// ch.qos.logback.core.db.DBHelper@77bb0ab5}
}

@Import 高级用法: https://www.bilibili.com/video/BV1gW411W7wy?p=8

3、@Conditional:条件装配 – 满足Conditional指定的条件,则进行组件注入

组件注入,需要判断Conditional指定的条件,但是大多数都是通过@Conditional的衍生注解去判断:

例如:

/*** @description: 配置类* @author: laizhenghua* @date: 2021/3/25 9:40*/
@Configuration
public class MyConfig {@Beanpublic Dog dog() {return new Dog();}@ConditionalOnBean(name = "dog") // IOC容器中有id为dog的组件,才进行组件注入@Beanpublic Pet pet() {Pet pet = new Pet();pet.setName("tom");pet.setAge(20);return pet;}
}

测试:

/*** @description: 主程序类* @author: laizhenghua* @date: 2021/3/23 21:39*/
@SpringBootApplication // 标注SpringBoot应用
public class MainApplication {public static void main(String[] args) {// 1、返回IOC容器ConfigurableApplicationContext applicationContext = SpringApplication.run(MainApplication.class, args);boolean pet = applicationContext.containsBean("pet");System.out.println("容器中的Pet组件:" + pet); // true}
}

再次修改@ConditionalOnBean(name = "dog666"),此时容器中是没有id=dog666的组件,判断条件不成立,Pet组件也就不注入容器中,重新启动主程序类,输出false

值得注意的是,@Conditional也可以使用在类上!判断的方式是一样的。测试时,注意bean的书写前后位置!!。

4.3、原生配置文件引入@ImportResource

@ImportResource的功能:导入Spring的配置文件,让配置文件里面的内容生效。

Spring Boot里面没有Spring的配置文件,我们自己编写的xml配置文件或是第三方技术使用配置文件描述bean,SpringBoot是不能识别的!

我们想让Spring的配置文件生效,加载进来,@ImportResource标注在一个配置类上,例如:
bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><bean id="haha" class="com.atguigu.boot.bean.User"><property name="name" value="zhangsan"></property><property name="age" value="18"></property></bean><bean id="hehe" class="com.atguigu.boot.bean.Pet"><property name="name" value="tomcat"></property></bean>
</beans>

配置类:

@ImportResource("classpath:beans.xml")
public class MyConfig {...
}

测试:

boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println("haha:"+haha); // true
System.out.println("hehe:"+hehe); // true

4.4、配置绑定

1、使用@ConfigurationProperties注解

如何使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用。在以前我们可能这样写:

public class getProperties {public static void main(String[] args) throws FileNotFoundException, IOException {Properties pps = new Properties();pps.load(new FileInputStream("a.properties"));Enumeration enum1 = pps.propertyNames();//得到配置文件的名字while(enum1.hasMoreElements()) {String strKey = (String) enum1.nextElement();String strValue = pps.getProperty(strKey);System.out.println(strKey + "=" + strValue);//封装到JavaBean。}}
}

但是在 SpringBoot 中,.properties配置文件的加载与绑定都通过@ConfigurationProperties来实现。

为了方便测试,我们新建一个实体类:

Car.java

/*** @description:* @author: laizhenghua* @date: 2021/3/25 14:44*/
public class Car {private String brand;private Integer price;...// getter and setter// toString()
}

application.properties

mycar.brand=aodi
mycar.price=100000

我们再次修改实体类(使用@ConfigurationProperties注解绑定属性):

/*** @description:* @author: laizhenghua* @date: 2021/3/25 14:44*/
@Component
@ConfigurationProperties(prefix = "mycar")
// 注意:只有在容器中的组件,才会拥有SpringBoot提供的强大功能
public class Car {// 属性值与配置文件绑定private String brand;private Integer price;...// getter and setter// toString()
}

编写业务代码测试:

/*** @description:* @author: laizhenghua* @date: 2021/3/25 15:52*/
@RestController
public class MyCarController {@Autowiredprivate Car car;@GetMapping("/car")public Car car() {return car;}
}
// 浏览器访问 http://localhost:8888/car

响应结果:

2、使用@EnableConfigurationProperties注解

值得注意的是:此注解必须在配置类中使用,才能绑定配置!如:

@Configuration
@EnableConfigurationProperties(Car.class)
// 1、开启Car配置绑定功能
// 2、把这个Car组件自动注册到容器中
public class MyConfig {...
}
/*
注释Car类的@Component,并修改配置文件中内容:mycar.brand=maikailun
mycar.price=100000重启,再次向浏览器发送请求 http://localhost:8888/car
*/

响应结果:

小结:

  • 配置绑定的方式有两种:
    1. @Component+ @ConfigurationProperties
    1. @EnableConfigurationProperties + @ConfigurationProperties
  • 以后我们在源码中会经常看到@ConfigurationProperties(prefix = "xxx"),只要有这个注解说名,此类的属性就与SpringBoot的全局配置文件指定的前缀进行绑定!

5、SpringBoot自动配置原理

我们都知道SpringBoot启动的时候先加载主程序类(主程序类也叫主配置类),主程序类被@SpringBootApplication标注,查看此注解源码我们发现,此注解是由:

  1. @SpringBootConfiguration
  2. @EnableAutoConfiguration
  3. @ComponentScan("com.laizhenghua.boot_helloworld")

这三个注解合成,如下所示:


// @SpringBootApplication // 标注SpringBoot应用
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.laizhenghua.boot_helloworld")
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class, args);}
}

因此想要知道 SpringBoot 的自动配置,就需要先从这三个注解下手!

5.1、@SpringBootConfiguration

点进去@SpringBootConfiguration,发现被@Configuration标注,这也说明:主程序类也是一个配置类。

5.2、@ComponentScan

前面已经介绍过了,是一个Spring的注解,用来指定包的扫描范围!

加了包扫描@ComponentScan注解后,只要标注了@Controller、@Service、@Repository、@Component注解中的任何一个,其组件都会被自动扫描,加入到容器中。

例如xml配置文件中我们可能会这也写:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!--开启注解支持--><context:annotation-config/><!--指定要扫描的包,这个包下的注解就会生效--><context:component-scan base-package="com.howie"/>
</beans>

当然源码里是:

@EnableAutoConfiguration
// 自定义了两个扫描器,具体使用可自行学习(Spring注解版),在这里意义不是很大
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {...
}

5.3、@EnableAutoConfiguration – 核心注解

SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration。此注解也是SpringBoot自动配置的核心注解,并且也是一个合成注解!

// 由以下两个注解合成
...
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {...
}

5.3.1、@AutoConfigurationPackage

自动配置包?指定了默认的包规则!

点进去此注解:

...
@Import(AutoConfigurationPackages.Registrar.class) // 给容器中导入一个组件
public @interface AutoConfigurationPackage {...
}// 利用Registrar给容器中导入一系列组件
// 将指定的一个包下的所有组件导入进来?MainApplication 所在包下。

这里就是获取了主配置类的信息,利用Registrar给容器中导入了主配置类子包中声明的所有组件!

这里不太会表达,还是建议多看看视频:https://www.bilibili.com/video/BV1Et411Y7tQ?t=17&p=119

5.3.2、@Import(AutoConfigurationImportSelector.class)

给容器中导入了类型为AutoConfigurationImportSelector的组件,然后我们查看此类到底做了些什么?

  1. 利用getAutoConfigurationEntry(annotationMetadata)方法,给容器中批量导入一些组件。
  2. 调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes),获取到所有需要导入到容器中的配置类。
  3. 利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader),得到所有的组件
  4. META-INF/spring.factories位置来加载一个文件。
    默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
    spring-boot-autoconfigure-2.3.9.RELEASE.jar包里面也有META-INF/spring.factories

127个要给容器中导入全类名组件!

扫描文件地址

spring-boot-autoconfigure-2.3.9.RELEASE.jar里面的spring.factories文件

小结:

  • 通过注解@AutoConfigurationPackage里面合成的注解,加载主配置类下子包中声明的所有组件。例如:使用@Controller、@Service、@Bean、@Mapper、@Configuration等注解标注的类或方法,将类或方法(变成了组件)注册到容器中。
  • 通过注解@Import(AutoConfigurationImportSelector.class)将所有META-INF/spring.factories位置的文件中写死的全类名组件(配置类)都注入容器中。
  • 需要注意的是不一定每一个配置类里或类里面的声明的组件都有用,如果全部都加载了,对内存对资源是一种极大的浪费,所以在SpringBoot里有了按需开启自动配置项 !

5.3.3、按需开启自动配置项

虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration

按照条件装配规则(@Conditional),最终会按需配置。

5.4、修改默认配置

DispatcherServletAutoConfiguration.java配置类中,我们会看到这样一个bean,如下所示:

// 给容器中加入了文件上传解析器(方法参数即为返回的值)
@Bean
@ConditionalOnBean(MultipartResolver.class) // 组件中有这个类型的组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
// 容器中没有这个名字(multipartResolver)的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {// Detect if the user has created a MultipartResolver but named it incorrectly// 给 @Bean 标注的方法传入对象参数,这个参数的值就会从容器中找// SpringMVC multipartResolver。防止有些开发者配置的文件上传解析器不符合规范。return resolver;
}

SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先。

@Bean
@ConditionalOnMissingBean // 判断依据
public CharacterEncodingFilter characterEncodingFilter() {...
}

小结:

  • SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里xxxProperties和全局配置文件进行了绑定
  • 生效的配置类就会给容器中装配很多组件
  • 只要容器中有这些组件,相当于这些功能就有了

定制化配置:

  • 开发者直接自己@Bean替换底层的组件

  • 开发者去看这个组件是获取的配置文件什么值就去修改。

流程:xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 —> application.properties

关于更多的可配置项和场景启动器需要自己去官网熟悉!这样才能事半功倍!

6、SpringBoot开发小技巧

6.1、Lombok

简化JavaBean的开发。Spring里已经介绍过了哦,不知道的小伙伴可自行查阅了解!

1、引入依赖

<!-- lombok -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>

2、idea中搜索安装lombok插件!

3、使用

/*** @description:* @author: laizhenghua* @date: 2021/3/25 13:15*/
@Data
@ToString
public class Dog {private String name;private Integer age;
}
/*
@AllArgsConstructor // 有参构造器(全部属性)
@NoArgsConstructor // 无参构造器
*/

4、简化日志开发

lombok还提供了很有用的功能,就是日志记录!只需使用一个注解@Slf4j,当前类上就自动导入了log对象!

/*** @description: 控制层* @author: laizhenghua* @date: 2021/3/23 21:44*/
@Controller
@Slf4j
public class HelloController {@RequestMapping(value = "/hello",method = RequestMethod.GET)@ResponseBodypublic String hello() {log.info("{}请求进来了","hello");return "hello world";}
}

启动项目进行测试。

6.2、dev tools

热部署工具,在以后我们开发时,经常会修改代码(特别是前端代码),查看效果时,就不需要重新启动项目,只需Ctrl + F9,重新编译一下即可。

<!--引入devtools。作用:改变页面内容时不需要重启服务,就能查看效果-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional>
</dependency>

引入依赖后即可使用!

6.3、Spring Initailizr(初始化向导)

IDE都支持使用Spring的项目创建向导快速创建一个Spring Boot项目;

选择我们需要的模块;向导会联网创建Spring Boot项目;

默认生成的Spring Boot项目;

  • 主程序已经生成好了,我们只需要我们自己的逻辑
  • resources文件夹中目录结构
    • static:保存所有的静态资源; js css images;
    • templates:保存所有的模板页面;(Spring Boot默认jar包使用嵌入式的Tomcat,默认不支持JSP页面);可以使用模板引擎(freemarker、thymeleaf);
    • application.properties:Spring Boot应用的配置文件;可以修改一些默认设置;


选择场景开发:

End

Thank you for watching

End

经典再现,看到就是赚到。尚硅谷雷神 - SpringBoot 2.x 学习笔记 - 基础入门篇相关推荐

  1. 经典再现,看到就是赚到。尚硅谷雷神 - SpringBoot 2.x 学习笔记 -高级与场景整合篇

    SpringBoot 2.x 场景整合 在上一篇核心功能篇里,我们已了解SpringBoot的配置文件.web开发.数据访问.JUnit5单元测试.生产指标监控.SpringBoot启动流程等.然而S ...

  2. 尚硅谷JavaWeb_2020idea_王振国_学习笔记

    文章目录 基本操作 阶段一.使用JS正则表达式检查输入 阶段二.实现登陆和注册功能 阶段三.做一些优化 阶段四.使用EL**表达式修改表单回显** 阶段五.图书模块 阶段五.下.分页的实现 阶段六.登 ...

  3. 【Vue实践】尚硅谷张天禹Vue学习笔记(087-135)-20221212~20221218

    (任意组件通信)084-086_全局事件总线 全局事件总线SOP 086_TodoList案例_事件总线 src/mian.js: import Vue from 'vue' import App f ...

  4. 尚硅谷_JS DOM编程_学习笔记

    DOM DOM:Document Object Model(文本对象模型) D:文档 – html 文档 或 xml 文档 O:对象 – document 对象的属性和方法 M:模型 DOM 是针对x ...

  5. 尚硅谷 天禹老师 Vue学习笔记总计(自己复习用)

    004 Vue环境搭建 如何关掉这2个提示? 关闭第一个提示,下载Vue的开发者工具 安装 - Vue.js Vue开发者工具GitHub下载地址: https://github.com/vuejs/ ...

  6. 【尚硅谷】Vue2.x核心学习笔记--渐进式的JS框架

    Vue核心 在这里插入图片描述 一.Vue的基本认识 1.1 Vue特点 1.2 与其他的前端Js框架的关联 1.3 Vue的扩展插件 二.Vue的基本使用 2.1 效果 2.2 如何引入Vue.js ...

  7. 尚硅谷以太坊区块链学习之NFT智能合约(6)

    尚硅谷以太坊区块链学习之NFT智能合约(6) 前言 一.NFT智能合约 1.智能合约代码 2.智能合约推送 3.具体调用 二.具体使用 三.NFT商家智能合约 前言 提示:服务外包区块链学习 5被ba ...

  8. 尚硅谷大数据技术Zookeeper教程-笔记01【Zookeeper(入门、本地安装、集群操作)】

    视频地址:[尚硅谷]大数据技术之Zookeeper 3.5.7版本教程_哔哩哔哩_bilibili 尚硅谷大数据技术Zookeeper教程-笔记01[Zookeeper(入门.本地安装.集群操作)] ...

  9. 尚硅谷大数据技术Scala教程-笔记04【集合】

    视频地址:尚硅谷大数据技术之Scala入门到精通教程(小白快速上手scala)_哔哩哔哩_bilibili 尚硅谷大数据技术Scala教程-笔记01[Scala课程简介.Scala入门.变量和数据类型 ...

最新文章

  1. 字符编码的前世今生--转
  2. 超哥笔记--linux准备知识(1)
  3. C++ Primer 5th笔记(chap 16 模板和泛型编程)包扩展
  4. 【算法】我面了N+算法岗候选人,这样的给了SSP
  5. java先抽到红球获胜,【图片】红蓝球概率问题,通过程序模拟抽取,计算结果已出,有兴趣来看【非现役文职吧】_百度贴吧...
  6. 本周 火火火火火 的开源项目
  7. QGIS2.18二次开发环境搭建--番外篇
  8. 广义多目标算法探索实践
  9. [转]一个叫你看过后感动想哭的对白
  10. 揭秘孙小小《PPT演示之道》
  11. SpringDataJpa 概述
  12. 疫情期间怎么上班?用电脑或手机远程办公很简单
  13. 全平台视频转GIF软件对比与推荐(iOS/安卓/Windows/Mac)
  14. Intellij idea注册激活码(2017年2月15日亲测可用于最新版)
  15. iOS 增强现实教程:基于位置定位
  16. C语言入门知识集合。
  17. cad边长提取lisp_用lisp怎么提取cad中文字-内容-*通用符匹配(值 :设定)生成excel文件...
  18. hdu2586How far away ?
  19. hpux oracle19c dbca DBT-05509 Failed To Connect To The Specified Database
  20. js获取指定字符前/后的字符串简单实例

热门文章

  1. NB-IoT模块如何发送点到点短信?
  2. RFID智能仓储方案
  3. STP、RSTP、MSTP协议
  4. Arcmap10.0 提取单个流域范围
  5. 一个开发周期为6个月的中小型软件开发项目成本预算大致表
  6. DES算法代码实现(C语言)
  7. 5G:4G到5G的演进,NSA和SA两种组网方式
  8. cnpm 网络不能连接_移动站网络的另一种方式——移动站手机网络模式
  9. 4.SolidWorks中的工程图,出图时公差怎么标?
  10. linux下使用ffmpeg将flv、mp4、rmvb转换为libx264的mp4