SpringBoot2-1入门篇

SpringBoot-1入门

尚硅谷 SpringBoot2 学习笔记,官方连接

一、构建一个 SpringBoot 项目,浏览器发送 /hello 请求,响应 Hello,SpringBoot2!

1. 创建 Maven 工程,不使用骨架

image-20220717165905740

image-20220717165954559

2.pom.xml 文件中添加父工程
<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.3.4.RELEASE</version>
</parent>
3.pom.xml 文件中添加 web 项目依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.3.4.RELEASE</version>
    </dependency>
</dependencies>
4.创建项目包和 SpringBoot 应用程序的主类 com.atguigu.boot.MainApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/**
 * @Classname MainApplication
 * @Description SpringBoot 项目的主程序类
 @SpringBootApplication 此注解表示类是 SpringBoot 项目的主类
 */
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class,args);
    }
}
5.创建一个 controller
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @Classname HelloController
 * @Description 
 @ResponseBody 此注解表示直接返回数据给浏览器,boot2 中还可以使用 @RestController 注解代替 @Controller 和 @ResponseBody
 */

@Controller
public class HelloController {

    @ResponseBody
    @RequestMapping("/hello")
    public String hello() {
        return "hello,SpringBoot2!";
    }
}
6.运行 SpringBoot 应用程序并测试效果

image-20220717181342555

二、application.properties

SpringBoot 程序中的所有配置信息都可以写在此文件中,不必像 SSM 阶段那样配置好几个 xml 文件了,体现了 SpringBoot 简化配置的特性。例如:

更改项目的端口号

resources 包下新建 application.properties , 更改端口号为 8888

server.port=8888
重启 SpringBoot 服务器测试效果

image-20220717182903073

image-20220717182006130

配置不会写可以参照官方文档

三、将 SpringBoot 应用程序打 jar 包并运行

1.pom 文件中设置打包方式,添加 maven 插件(打包用的)
<packaging>jar</packaging>
...
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
2.打包

image-20220717183650082

image-20220717183722665

四、自动版本仲裁和自动配置原理

1.依赖管理
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.4.RELEASE</version>
</parent>
<!--它的父项目-->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.3.4.RELEASE</version>
</parent>
<!--依赖管理和自动版本仲裁,几乎声明了开发中所有依赖的版本号-->
<!--如果真的需要自定义的版本或者使用自定义的类库,可以使用如下方法-->
<!--
	1.查看 spring-boot-dependencies 里面规定当前以来的版本,用的 key。
	2.在当前项目里面重写配置
-->
<properties>
    <mysql.version>5.4.1</mysql.version>
    <xxx.version>1.0.0</xxx.version>
</properties>
<dependencies>
    <dependency>
        <groupId>com.xxx.xxx</groupId>
        <artifactId>xxx</artifactId>
    </dependency>
</dependencies>

2. spring-boot-start 场景启动器(一组依赖的集合)
  1. 官方很多启动器命名为:spring-boot-start-* *就是某种场景

    例如:spring-boot-start-web spring-boot-start-amqp

    所有官方场景启动器参见官方文档

  2. 只要项目中引入了场景启动器,启动器中的依赖都会自动引入项目

  3. 官方推荐自定义的场景启动器(包括第三方场景启动器)命名格式为:xxx-spring-boot-start

  4. 所有场景启动器都依赖 spring-boot-start (SpringBoot自动配置的核心依赖)

    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter</artifactId>
       <version>2.3.4.RELEASE</version>
       <scope>compile</scope>
    </dependency>
    
  5. 使用 boot 时,引入依赖一般可以不写版本号,因为有自动版本仲裁机制,但是引入的不是 spring 官方支持的 jar 时还是需要自定义版本号。

3.自动配置
  1. 自动配置好了 Tomcat

  2. 自动配好了 SpringMVC

    • 引入 SpringMVC 全套组件

    • 自动配好 SpringMVC 常用组件(常用功能)

      image-20220718162219880

  3. 自动配好了 web 开发常见的功能,如:字符编码问题

    • SpringBoot 帮我们配置好了所有 web 开发的常见场景
  4. 默认的包结构

    • 主程序类所在的包及其子包都在扫描范围内

    • 不需要配置包扫描了(SpringMVC 中的 @ComponentScan 注解或者 xml 文件中的 bean 标签等)

    • 可以在核心注解 @SpringBootApplication 的属性中指定扫描包

      @SpringBootApplication(scanBasePackages="com.xxx")
      
    • 还可以使用

      @SpringBootConfiguration
      @EnableAutoConfiguration
      @ComponentScan("com.xxx")
      // 上面三个注解就相当于
      @SpringBootApplication
      
  5. 各种配置拥有默认值

    • 默认配置最终都映射到 MultipartProperties
    • 配置文件的值最终会绑定到每个类上,这个类会在容器中创建对象
  6. 按需加载所有自动配置项

    • 引入了哪些 starter (场景),就启动这个场景的自动配置

    • SpringBoot 所有的自动配置功能都在 spring-boot-autoconfigure 包里面

      image-20220718164208693

五、容器功能

1.组件添加

原来在 Spring 中配置一个组件要写一个 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/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user01" class="com.atguigu.boot.bean.User">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="14"></property>
    </bean>
    <bean id="user02" class="com.atguigu.boot.bean.User">
        <property name="name" value="lisi"></property>
        <property name="age" value="15"></property>
    </bean>
</beans>

在 SpringBoot 中可以使用 @Configuration 注解使一个类变成配置类

import com.atguigu.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Classname MyConfig
 * @Description TODO
 */
@Configuration // 告诉 SpringBoot 这是一个配置类,以前的 xml 配置文件
public class MyConfig {
    @Bean // 给容器中添加组件,以方法名作为组件的 id。返回值就是组件类型,返回的是容器中的实例
    public User user01() {
        return new User("zhangsan",18);
    }
    @Bean("tom")
    public Pet tomcat() {
        return new Pet("tomcat");
    }
    // 从容器中获取组件,能看到上面的两个自定义组件
}

组件默认是单例模式的,不管获取多少次,都是同一个对象。

System.out.println("======================");
// 下面是两种获取方法
Object user01 = run.getBean("user01", String.class, Integer.class); // 指定参数
Object user02 = run.getBean("user01", User.class); // 指定类型
System.out.println(user01==user02);
  • 配置类本身也是一个组件!
2. @Configuration 注解
  1. @Configuration(proxyBeanMethod = true) 代理 bean 的方法。 SpringBoot 总会检查这个组件是否在容器中存在(保持组件单实例)。
    • Full(proxyBeanMethod = true)
    • Lite(proxyBeanMethod = false)
  2. 使用场景:
    1. 配置类组件之间无依赖关系可以使用 Lite 模式,此时 SpringBoot 启动运行时不会检查容器中的所有组件,因此启动速度更快
    2. 配置类组件之间有依赖关系时,需要使用 Full 模式,保证容器中的组件是单例模式
3. @Bean @Component @Controller @Service @Repository
  • 以前 Spring 中的注解都能用。
4. @Import
  • 用法:@Import({User.class,DBHelper.class})
  • 作用:给容器中自动创建这两个类型的组件,组件默认的名字是类的全限定名
5. @Conditional
  • 条件装配:满足 Conditional 指定的条件,则进行条件注入

  • @Conditional 注解有很多派生注解(idea中按H查看类的继承树)

    image-20220727193608389

    比如:

    • ConditionalOnBean 当容器中存在指定组件时,做 … 事情
    • ConditionalOnMissingBean 当容器中不存在指定组件时,做 … 事情
    • ConditionalOnBeClass 当容器中存在某个类时,做 … 事情
    • ConditionalOnMissingClass 当容器中不存在某个类时,做 … 事情

    示例:

    @Configuration // 告诉 SpringBoot 这是一个配置类,以前的 配置文件
    public class MyConfig {
        @Bean // 给容器中添加组件,以方法名作为组件的 id。返回值就是组件类型,返回的是容器中的实例
        @ConditionalOnBean(name = "tom") // 如果容器中有这个组件,就将 user01 注入容器
        public User user01() {
            User user = new User("zhangsan",18);
            user.setCat(tomcat());
            return user;
        }
    //    @Bean("tom") // 普通方法,不注册进入容器
        public Pet tomcat() {
            return new Pet("tomcat");
        }
    }
    
    @SpringBootApplication()
    public class MainApplication {
    	public static void main(String[] args) {
            // 返回 IOC 容器
            ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
            boolean tom = run.containsBean("tom"); // 看看容器中有没有 tom 这个组件
            System.out.println("容器中是否有tom组件:" + tom);
            boolean user01 = run.containsBean("user01"); // 看看容器中有没有 user01 这个组件
            System.out.println("容器中是否有user01组件:" + user01);
        }
    }
    

    结果:

    image-20220727205000826

  • @Conditional 注解及其派生注解可以标注在方法和类上

    • 标注在方法上表示要满足某些条件这个组件才会注入容器

    • 标注在类上表示要满足这个条件类中的所有组件才会注入容器

    • 示例:

      @Configuration // 告诉 SpringBoot 这是一个配置类,以前的 配置文件
      @ConditionalOnBean(name = "tom22") // 如果容器中有这个组件,就将类中的 注入容器
      public class MyConfig {
          @Bean // 给容器中添加组件,以方法名作为组件的 id。返回值就是组件类型,返回的是容器中的实例
          public User user01() {
              User user = new User("zhangsan",18);
              user.setCat(tomcat());
              return user;
          }
          @Bean("tom22")
          public Pet tomcat() {
              return new Pet("tomcat");
          }
      
          // 从容器中获取组件,能看到上面的两个自定义组件
      }
      
      @SpringBootApplication()
      public class MainApplication {
      	public static void main(String[] args) {
              // 返回 IOC 容器
              ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
              boolean tom = run.containsBean("tom"); // 看看容器中有没有 tom 这个组件
              System.out.println("容器中是否有tom组件:" + tom);
              boolean user01 = run.containsBean("user01"); // 看看容器中有没有 user01 这个组件
              System.out.println("容器中是否有user01组件:" + user01);
              boolean tom22 = run.containsBean("tom22"); // 看看容器中有没有 tom22 这个组件
              System.out.println("容器中是否有tom22组件:" + tom22);
          }
      }
      

      结果:

      image-20220727210514485

      SpringBoot 先按条件装配检查了容器中没有 tom22 这个组件,然后下面的自动装配 tom22 的 @Bean 注解就不生效了。

      如果将 @ConditionalOnBean 改成 @ConditionalOnMissingBean,那么 user01 和 tom22 组件将被装配进入容器。

6. @ImportResources(“classpath:beans.xml”)

此注解允许我们使用 Spring 中 xml 文件配置组件的方式注入容器。

7. @ConfigurationProperties

只有在容器中的组件,才能使用 SpringBoot 提供的功能!

首先创建实体类 Car

/**
 * @Classname Car
 * @Description 测试 @ConfigurationProperties 注解,此注解是 SpringBoot 提供的功能,只对容器中的组件生效。
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component // 注入容器
@ConfigurationProperties(prefix = "mycar") // prefix 属性用于设置配置文件的前缀
public class Car {
    private String brand; // 品牌
    private Integer price; // 价格
}

在 application.properties 配置文件中配置如下属性:

mycar.brand=BYD
mycar.price=100

测试:

@RestController
public class HelloController {

    @Autowired
    private Car car;

    @RequestMapping("/car")
    public Car car() {
        return car;
    }
    @RequestMapping("/hello")
    public String hello() {
        return "hello,SpringBoot2!";
    }
}

image-20220806095634597

注意:修改配置文件后要重启项目。

8. @EnableConfigurationProperties(Car.class)
  1. 可以开启实体类的属性配置功能(将组件直接注入容器也能达到同样的效果),相当于在 Car 类上使用注解 @Component
  2. 把 Car 这个组件自动注册到容器中

六、自动配置原理

6.1 引导加载自动配置类

核心注解:@SpringBootApplication 相当于三个注解:@SpringBootConfiguration、@EnableAutoConfiguration 和 @ComponentScan(“com.xxx.xxx”)

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
  1. @SpringBootConfiguration

    @Configuration 代表当前类是一个配置类(说明 MainApplication 主程序类也是一个配置类,所以也可以称其为核心配置类)

  2. @ComponentScan

    指定扫描哪些包,这是个 Spring 注解

  3. @EnableAutoConfiguration *

    是一个合成注解,最重要的两个:

    1. @AutoConfigurationPackage 自动配置包 -> @Import 注解导入了 Registrar.class,这个类中的 registerBeanDefinitions 方法会批量向容器中批量注册组件

      img-20220806105210728

      image-20220806105657119

      registerBeanDefinitions 方法的参数 metadata 相当于注解的元信息,元信息会获取到是哪个类使用了此注解。因为 @AutoConfigurationPackage 是一层一层合成起来的,所以最终相当于标注在了 MainApplication 核心配置类上面。

      源码第 124 行使用元信息获取到了核心配置类的完整包路径,并生成了一个数组,最终将 MainApplicaiton 类所在的包及其子包中的组件批量注册到容器中。

      @AutoConfigurationPackage 注解,也就是 registerBeanDefinitions 方法最终做的事就是将 MainApplicaiton 类所在的包及其子包中所有的组件批量的注册到容器。

    2. @Import(AutoConfigurationImportSelector.class)

      1. 利用 Select 机制,也就是源码第 99 行 getAutoConfigurationEntry(annotationMetadata) 方法,给容器中批量导入一些东西。

        image-20220807152101076

      2. 在 getAutoConfigurationEntry(annotationMetadata) 方法中,通过第 123 行 getCandidateConfigurations() 方法获取到了所有候选的配置类,再移除了一些重复的和注解标明排除的,最后加载了 127 个组件。

        image-20220807153507325

      3. getCandidateConfigurations() 方法内部通过 Spring 的工厂加载机制 SpringFactoriesLoader 的 Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader) 方法得到所有组件

        image-20220807154422247

        image-20220807154625476

      4. loadSpringFactories() 方法会从 META-INF/spring.factories 这个位置来加载一个文件,也就是 SpringBoot 默认扫描我们当前系统里面所有 META-INF/spring.factories 位置的文件。

        image-20220807154831756

        spring-boot-autoconfigure-2.3.4.RELEASE.jar 包里面也有 META-INF/spring.factories 文件。

        image-20220807155428892

      5. 因为文件中写死了要加载的配置类,所以 SpringBoot 一启动,就会加载所有的 127 个配置类。

6.2 按需开启自动配置项

虽然我们 127 个场景的所有自动配置启动的时候默认全部加载,但是得益于 @Conditional 等条件装配注解的规则,SpringBoot 最终会按需加载配置。

6.3 修改默认配置
/*
下面这段代码来自 spring-boot-autoconfigure-2.3.4.RELEASE.jar
package org.springframework.boot.autoconfigure.web.servlet; 第 99 行。
作用是给容器中添加文件上传解析器。
*/
@Bean
@ConditionalOnBean(MultipartResolver.class) // 此条件判断了容器中有这个类型的组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //  此条件判断容器中有这个名字的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
   // 给 @Bean 标注的方法传入了对象参数,这个参数的值就会从容器中找。
   // 也就是说,如果用户自定义了一个文件上传解析器,但是名字不叫这个,SpringBoot 也能解决这个问题
   // Detect if the user has created a MultipartResolver but named it incorrectly
   return resolver;
}
  • SpringBoot 默认会在底层配好所有的组件,但是用户自己配置了,会以用户自己的优先。(最常见的就是自定义的 CharacterEncodingFilter)
总结:
  • SpringBoot 先加载所有的自动配置类(XxxxAutoConfiguration)。

  • 每个自动配置类按照条件生效,不是全部生效;默认都会绑定配置文件指定的值,XxxxProperties 文件里面拿,XxxProperties 和配置文件进行了绑定。

  • 生效的配置类就会给容器中装配很多的组件。

  • 只要容器中有这些组件,就相当于这些功能就有了。

  • 只要有用户自定义的配置,就以自定义的优先。

  • 定制化配置

    1. 用户自己 @Bean 替换掉底层组件

    2. 用户去看这个组件是获取的配置文件什么值,就去修改配置文件,例如修改字符编码拦截器:

      image-20220807193524131

  • XxxxAutoConfiguration —> 组件 —> XxxProperties 里面拿值 —> appliction.properties

  • SpringBoot 中一般改 application.properties 文件就能修改所有的默认值。

6.4 最佳实践
  1. 引入场景依赖

    参见官方文档

  2. 查看自动配置了哪些(选做)

    1. 去 jar 包自己分析。(有些麻烦,而且引入场景对应的自动配置一般都生效了。)

    2. 在 application.properties 中添加 debug=true 开启 debug 模式,再运行程序会有自动配置报告:

      image-20220807194955392

      Negative matches 为不生效的\不匹配的

      image-20220807195147114

      Positive matches 为生效的

  3. 是否需要修改配置项

    1. 参照官方文档修改配置项。

    2. 自己分析 XxxxProperties 绑定了配置文件的哪些前缀。

    3. 举例,替换 SpringBoot 默认的启动图片:

      先去官网查询前缀,然后修改 application.properties 配置文件。

      spring.banner.image.location=classpath:javadeveloper.jpg
      
    4. 自定义加入或者替换组件

      @Bean @Component

    5. 自定义器 XXXCustomizer(将已有组件的行为自定义)

七、开发技巧

7.1 Lombok

​ 简化 JavaBean 开发(使用注解简化 getter、setter、toString等方法的开发),Lombok 会在编译时加入需要的 getter、setter 等方法,SpringBoot 对 Lombok 有很好的支持。

​ 使用:

  1. 导入依赖:

    <!--lombok,省略getter、setter等-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    
  2. 安装插件

    image-20220808002403334

  3. 使用

    image-20220808002439824

  4. @Data 注解相当于 getter、setter方法

  5. @NoArgsConstractor 注解相当于无参构造器

  6. @AllArgsConstractor 注解相当于全部参数参构造器

  7. @ToString 注解

  8. @EqualsAndHashCode 注解

  9. @Slf4j 注解是日志注解,在方法中配合 log.info(“hello”); 可以在程序运行时控制台打印日志。

7.2 Developer Tools 热更新\热部署
  1. 官方文档引入依赖。

  2. 加入依赖之后,每次在项目中做更改就不用重启项目了,只需要点编译按钮或者快捷键 Ctrl + F9。

    image-20220808170802594

  3. 但这样每次还要编译一次,并不是实时的热部署,不过对于开发静态页面来说就不需要重启了。

7.3 Spring Initailzr 项目初始化向导
  1. 新建项目时选择 Spring Initailzr

    image-20220808181056560

  2. 选择 SpringBoot 版本、勾选需要的开发场景

    image-20220808181841169

  3. 完成创建后,各种开发场景的依赖和父项目会被自动依赖

    image-20220808184002721

  4. resources 包中自动创建了全局配置文件 application.properties 、静态资源包 static 和 templates 页面包

    image-20220808184104102

  5. 自动创建好了主程序类

    image-20220808184620293

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值