SpringBoot是为了简化SSM框架开发过程中繁琐的XML配置,并且SpringBoot内置了小型的Tomcat服务器和相应的jar包,这也解决了我们配置tomcat环境的麻烦。

SpringBoot文档

一切以SpringBoot的官方文档为主,因为SpringBoot的更新迭代快,所以需要关注Spring官网来学习他的新特性,在一些企业中,已经开始使用SpringBoot来代替SSM框架开发流程。
SpringBoot - 图1

SpringBoot入门

1、环境要求

  • jdk8及以上
  • Maven3.3以上
  • idea(推荐使用)

    Maven配置

    conf/setting.xml文件
    1. <!-- 最新阿里云镜像-->
    2. <mirror>
    3. <id>aliyunmaven</id>
    4. <mirrorOf>*</mirrorOf>
    5. <name>aliyunmaven</name>
    6. <url>https://maven.aliyun.com/repository/public</url>
    7. </mirror>
    8. <!-- 使用jdk设置 -->
    9. <profile>
    10. <id>jdk-1.8</id>
    11. <activation>
    12. <activeByDefault>true</activeByDefault>
    13. <jdk>1.8</jdk>
    14. </activation>
    15. <properties>
    16. <maven.compiler.source>1.8</maven.compiler.source>
    17. <maven.compiler.target>1.8</maven.compiler.target>
    18. <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
    19. </properties>
    20. </profile>
    21. <!-- 设置本地仓库 -->
    22. <localRepository>D:\enviroment\apache-maven-3.6.3\maven-repo</localRepository>

    2、项目搭建

    创建Maven项目,在porm.xml中配置以下依赖 ```xml org.springframework.boot spring-boot-starter-parent 2.4.1

org.springframework.boot spring-boot-starter-web

  1. <a name="eY5H7"></a>
  2. ## 3、创建主程序
  3. 在java文件夹下创建主程序,作为springboot项目启动的开关
  4. ```java
  5. //这是一个Springboot应用
  6. @SpringBootApplication
  7. public class MainApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(MainApplication.class,args);
  10. }
  11. }

4、编写Controller业务类

原先的注解配置

  1. @Controller
  2. public class HelloController {
  3. @ResponseBody
  4. @RequestMapping("/")
  5. public String handle01(){
  6. return "Hello,SpringBoot!";
  7. }
  8. }

Controller:返回的是页面,用于处理请求
Spring4以后,后来的注解

  1. @RestController
  2. public class HelloController {
  3. @RequestMapping("/")
  4. public String handle01(){
  5. return "Hello,SpringBoot!";
  6. }
  7. }

引入了新注解RestController,它是Controller和ReSponseBody配合使用的自定义注解

5、结果

运行main函数,获得结果
image.png

SpringBoot简化配置

可以在配置文件中,修改springboot的配置,以键值对的形式来改变,极大的简化了我们的配置。
image.png
在SpringBoot官方文档中,我们可以设置以下的配置信息
image.png

SpringBoot简化部署

以jar打包方式进行目标服务器运行

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-maven-plugin</artifactId>
  6. </plugin>
  7. </plugins>
  8. </build>

clean+pakeger
image.png
image.png

SpringBoot特性

依赖管理

父项目依赖管理

子项目如果依赖父项目的依赖,则会继承父项目的依赖

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.4.1</version>
  5. </parent>

spring-boot-starter-parent依赖的父依赖为spring-boot-dependencies

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-dependencies</artifactId>
  4. <version>2.4.1</version>
  5. </parent>

spring-boot-starter-parent中声明了各种版本号的依赖,自动版本仲裁机制

starter场景启动器

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. </dependency>
  6. </dependencies>

在springboot中配置了各种场景启动器:如jdbc,消息队列,redis等,引入依赖的格式是spring-boot-starter-*
各种场景启动器都会依赖于

  1. spring-boot-starter

第三方starter

  1. *-spring-boot-starter:如这样格式的starter,则为第三方简化开发的场景启动器

修改版本号

由于spring-boot-dependencies中声明了各版本的依赖,所以一般不需要声明版本依赖,如果是非版本仲裁的依赖,则需要自己声明。
如果声明的版本号不是自己需要的,则可以通过maven仓库修改版本号,如修改mysql驱动版本

  1. <properties>
  2. <mysql.vesrion>5.1.47</mysql.vesrion>
  3. </properties>

自动配置

  • starter-web中自动引入tomcat

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-tomcat</artifactId>
    4. <version>2.4.1</version>
    5. <scope>compile</scope>
    6. </dependency>
  • 自动引入了springmvc的全套主键

    1. <dependency>
    2. <groupId>org.springframework</groupId>
    3. <artifactId>spring-web</artifactId>
    4. <version>5.3.2</version>
    5. <scope>compile</scope>
    6. </dependency>
    7. <dependency>
    8. <groupId>org.springframework</groupId>
    9. <artifactId>spring-webmvc</artifactId>
    10. <version>5.3.2</version>
    11. <scope>compile</scope>
    12. </dependency>
  • springboot配好了所有web场景的组件

    • 如文件上传,编码方式,视图解析等常用组件
  • 默认包结构:主程序所在的包及其所有子包的组件都会被扫描进来

    • 改变扫描路径,设置@SpringBootApplication(scanBasePackages = “com.learn”)
    • 或者使用ComponentScan
      1. @SpringBootApplication(scanBasePackages = "com.learn")
      2. 等同于
      3. @SpringBootConfiguration
      4. @EnableAutoConfiguration
      5. @ComponentScan("com.learn")
      正常配置下
      image.png
      报错
      image.png
      改变扫描路径
      image.png
  • 各种配置都有默认值

    • 默认的最终配置的都是映射到某个类上
    • 而配置文件中配置的值都会绑定到相应类上,这个类最终会在容器中创建对象
  • 按需加载自动配置项
    • 只有引入了相应的场景启动器,springboot才会把相应场景加载进来

底层注解

spring配置

实体类

  1. package com.learn.springboot.bean;
  2. public class User {
  3. private String name;
  4. private int age;
  5. public String getName() {
  6. return name;
  7. }
  8. public void setName(String name) {
  9. this.name = name;
  10. }
  11. public int getAge() {
  12. return age;
  13. }
  14. public void setAge(int age) {
  15. this.age = age;
  16. }
  17. @Override
  18. public String toString() {
  19. return "User{" +
  20. "name='" + name + '\'' +
  21. ", age=" + age +
  22. '}';
  23. }
  24. }

容器配置bean对象信息:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="User" class="com.learn.springboot.bean.User">
  6. <property name="name" value="张三"></property>
  7. <property name="age" value="18"></property>
  8. </bean>
  9. </beans>

这是以前spring给容器赋值的过程。

SpringBoot配置

  1. package com.learn.springboot.config;
  2. import com.learn.springboot.bean.User;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. @Configuration //告诉SpringBoot这是一个配置类
  6. public class MyConfig {
  7. @Bean //给容器添加组件,以方法名作为id,以返回类型作为class。
  8. public User user01(){
  9. //返回的容器实例
  10. return new User("张三",18);
  11. }
  12. }

这是SpringBoot添加组件的过程:

  • Configuration申明配置类
  • Bean申明配置bean对象函数
  • 返回相应类型示例

注:
默认是单实例。

Configuration注解

  1. @Configuration(proxyBeanMethods = true)

proxyBeanMethods属性表示是否开启代理对象。

  • 如果为true,则上文中的MyConfig类是spring中的cglib代理的增强类,因此我们获取到的bean对象的代理对象,是单实例的。
  • 如果是false,则MyConfig类是默认类型,我们获得的bean是多实例的。
  1. public class MainApplication {
  2. public static void main(String[] args) {
  3. //IOC容器
  4. ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
  5. MyConfig bean = run.getBean(MyConfig.class);
  6. System.out.println(bean);
  7. User user = bean.user01();
  8. User user1 = bean.user01();
  9. System.out.println(user==user1);
  10. }
  11. }

当proxyBeanMethods = true时
image.png
当proxyBeanMethods = false时

image.png
可以看到,我们两次比较user和user1对象,得到的结果都是不同的,并且,bean对象相应class也是不同的。

全配置和轻量配置

  • Full(proxyBeanMethods = true)
  • Lite(proxyBeanMethods = false)

注:全配置和轻量配置主要解决的是JaveBean依赖问题,如果是true,是单实例情况,这被依赖的组件不会被多次创建,是多实例的。
如果User中有其他类,例如
image.png

  1. @Configuration(proxyBeanMethods = true) //告诉SpringBoot这是一个配置类
  2. public class MyConfig {
  3. @Bean //给容器添加组件,以方法名作为id,以返回类型作为class。
  4. public User user01(){
  5. User user = new User("张三", 18);
  6. user.setPet(tom());
  7. //返回的容器实例
  8. return user;
  9. }
  10. @Bean
  11. public Pet tom(){
  12. return new Pet("tom");
  13. }
  14. }

主程序

  1. public class MainApplication {
  2. public static void main(String[] args) {
  3. //IOC容器
  4. ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
  5. MyConfig bean = run.getBean(MyConfig.class);
  6. System.out.println(bean);
  7. User user = bean.user01();
  8. Pet tom = bean.tom();
  9. System.out.println(user.getPet()==tom);
  10. }
  11. }

当proxyBeanMethods = true,结果
image.png
当proxyBeanMethods = false,结果
image.png
可以看到,全配置和轻量配置的结果是不同的。
全配置和轻量配置的使用时间:

  • 当存在bean依赖时,使用full模式,保证依赖的正确性。
  • 当配置类中,没有bean依赖时,用lite模式,容器能够快速启动,减少判断

    Import注解

    给容器创建bean实例。
    注解内容 ```java @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import { Class<?>[] value(); }
  1. Import注解中的value属性,是一个class对象的数组。
  2. <a name="Bmdkp"></a>
  3. #### 实例展示
  4. **配置类**
  5. ```java
  6. @Import({User.class})
  7. @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类
  8. public class MyConfig {
  9. @Bean //给容器添加组件,以方法名作为id,以返回类型作为class。
  10. public User user01(){
  11. User user = new User("张三", 18);
  12. //返回的容器实例
  13. return user;
  14. }
  15. }

主程序

  1. @SpringBootApplication(scanBasePackages = "com.learn")
  2. public class MainApplication {
  3. public static void main(String[] args) {
  4. //IOC容器
  5. ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
  6. MyConfig bean = run.getBean(MyConfig.class);
  7. String[] user = run.getBeanNamesForType(User.class);
  8. for (String use : user) {
  9. System.out.println(use);
  10. }
  11. }
  12. }

结果
image.png
我们可以看到,我们使用@Import({User.class}),在lite模式下,自动为我们创建了一个全类名的bean。
注:实测,采用@Import({User.class,User.class})方式,或proxyBeanMethods = true 这样都只会创建一个全类名的bean。

Conditional注解

条件注解:当满足什么条件时,注解生效。
image.png

实例演示

ConditionalOnBean

  1. @Configuration(proxyBeanMethods = true) //告诉SpringBoot这是一个配置类
  2. public class MyConfig {
  3. @Bean
  4. public Pet tom(){
  5. return new Pet("tom");
  6. }
  7. @ConditionalOnBean(name="tom")
  8. @Bean //给容器添加组件,以方法名作为id,以返回类型作为class。
  9. public User user01(){
  10. User user = new User("张三", 18);
  11. //返回的容器实例
  12. return user;
  13. }
  14. }

如果配置类中没有name=tom的bean实例的话,则user01也不初始化。
主程序

  1. @SpringBootApplication(scanBasePackages = "com.learn")
  2. public class MainApplication {
  3. public static void main(String[] args) {
  4. //IOC容器
  5. ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
  6. boolean user01 = run.containsBean("user01");
  7. System.out.println("容器中是否有user01:"+user01);
  8. }
  9. }

结果
image.png
注:配置类是从上往下顺序生成bean实例的,ConditionalOnBean查找标注类的上方是否存在name=tom的bean实例,因此,如果tom实例函数定义在user01下方的话,也会找不到tom实例,从而不生成user01实例。
ConditionalOnClass不需要按顺序编写。

ImportResource注解

导入xml文件,获取bean实例。

实例演示

在resources文件夹下写入一个xml文件。
image.png
beans.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="user02" class="com.learn.springboot.bean.User">
  6. <property name="name" value="张三"></property>
  7. <property name="age" value="18"></property>
  8. </bean>
  9. </beans>

有个user02的bean实例。
配置类

  1. @ImportResource("classpath:beans.xml")
  2. @Configuration(proxyBeanMethods = true) //告诉SpringBoot这是一个配置类
  3. public class MyConfig {
  4. @Bean //给容器添加组件,以方法名作为id,以返回类型作为class。
  5. public User user01(){
  6. User user = new User("张三", 18);
  7. //返回的容器实例
  8. return user;
  9. }
  10. }

在配置类中申明注解@ImportResource(“classpath:beans.xml”)。
主程序

  1. @SpringBootApplication(scanBasePackages = "com.learn")
  2. public class MainApplication {
  3. public static void main(String[] args) {
  4. //IOC容器
  5. ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
  6. String[] user = run.getBeanNamesForType(User.class);
  7. for (String use : user) {
  8. System.out.println(use);
  9. }
  10. }
  11. }

结果
image.png
可以看到beans.xml中的user02也在容器实例化了。

ConfigurationProperties注解

将properties文件中的信息加入到bean中,并实现实例化。

实例演示

properties文件

  1. myuser.name = springboot
  2. myuser.age = 17

实体类

实体类写入注解加入到容器中,并且去配置文件中寻找前缀为myuser的变量

  1. @Component
  2. @ConfigurationProperties(prefix="myuser")
  3. public class User {
  4. private String name;
  5. private int age;
  6. private Pet pet;
  7. public Pet getPet() {
  8. return pet;
  9. }
  10. public void setPet(Pet pet) {
  11. this.pet = pet;
  12. }
  13. public User() {
  14. }
  15. public User(String name, int age) {
  16. this.name = name;
  17. this.age = age;
  18. }
  19. public String getName() {
  20. return name;
  21. }
  22. public void setName(String name) {
  23. this.name = name;
  24. }
  25. public int getAge() {
  26. return age;
  27. }
  28. public void setAge(int age) {
  29. this.age = age;
  30. }
  31. @Override
  32. public String toString() {
  33. return "User{" +
  34. "name='" + name + '\'' +
  35. ", age=" + age +
  36. '}';
  37. }
  38. }

控制类

  1. @RestController
  2. public class HelloController {
  3. @Autowired
  4. User user;
  5. @RequestMapping("/user")
  6. public User user01(){
  7. return user;
  8. }
  9. }

在服务器页面中查看信息
image.png
可以看到,配置文件中的信息添加到容器中去了。

第二种实现方式

使用EnableConfigurationProperties和ConfigurationProperties来实现读取配置类信息
实体类

  1. @ConfigurationProperties(prefix="myuser")
  2. public class User {
  3. private String name;
  4. private int age;
  5. private Pet pet;
  6. public Pet getPet() {
  7. return pet;
  8. }
  9. public void setPet(Pet pet) {
  10. this.pet = pet;
  11. }
  12. public User() {
  13. }
  14. public User(String name, int age) {
  15. this.name = name;
  16. this.age = age;
  17. }
  18. public String getName() {
  19. return name;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. public int getAge() {
  25. return age;
  26. }
  27. public void setAge(int age) {
  28. this.age = age;
  29. }
  30. @Override
  31. public String toString() {
  32. return "User{" +
  33. "name='" + name + '\'' +
  34. ", age=" + age +
  35. '}';
  36. }
  37. }

配置类

  1. @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类
  2. @EnableConfigurationProperties(User.class)
  3. public class MyConfig {
  4. }

:发现一个很怪的问题,当容器中有两个User时,自动装配无法装配上的,且如果能装配上,则需要在@Autowired
@Qualifier(“myuser-com.learn.springboot.bean.User”)
下声明该bean的名字。暂时还没找到解决方法,无法对EnableConfigurationProperties下的bean重新命名。