• SpringBoot2-基础入门(二)


    SpringBoot2 - 基础入门(二)

    了解自动装配原理

    一、依赖管理

    1.1 父项目做依赖管理
    依赖管理
    <parent>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-parentartifactId>
            <version>2.7.12version>
    parent>`
    
    spring-boot-starter-parent的父项目:
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-dependenciesartifactId>
        <version>2.7.12version>
    parent>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在spring-boot-dependencies中几乎声明了所有开发中常用的依赖配置的版本号

    例如对于数据库链接的依赖,spring-boot-dependencies中有以下配置

    <mysql.version>8.0.33mysql.version>
    ......
    <dependency>
         <groupId>com.mysqlgroupId>
         <artifactId>mysql-connector-jartifactId>
         <version>${mysql.version}version>
         <exclusions>
           <exclusion>
             <groupId>com.google.protobufgroupId>
             <artifactId>protobuf-javaartifactId>
           exclusion>
         exclusions>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 如何覆盖父项目中的配置

    只需要在maven项目的核心配置文件pom.xml中,重写需要的依赖版本,此时maven就会根据就近原则加载相应的依赖

    例如对于链接mysql的依赖,只需在pom.xml中添加以下配置

    <properties>
     <mysql.version>想要的版本号mysql.version>
    properties>
    
    • 1
    • 2
    • 3
    • 在spring-boot-dependencies中配置的所有依赖,我们在引入时都可以不设置版本号,称之为版本仲裁
    1.2 starer场景启动器

    就某个开发场景而言只要我们引入相应的启动器,这个场景所需要的常规依赖都会帮我们自动引入

    以web为例:

    <dependencies>
         <dependency>
             <groupId>org.springframework.bootgroupId>
             <artifactId>spring-boot-starter-webartifactId>
         dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 可以看一下他的依赖树:

    在这里插入图片描述

    • 所有场景启动器最底层的依赖 – spring boot自动配置的核心依赖
        <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-starterartifactId>
          <version>2.7.12version>
          <scope>compilescope>
        dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2、自动配置

    2.1 自动配置依赖
    • 自动配置Tomcat

      • 引入Tomcat依赖
      • 配置
      <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-tomcatartifactId>
            <version>2.7.12version>
            <scope>compilescope>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • 自动配置SpringMVC

      • 引入SpringMVC全套组件
      • 自动配号SpringMVC常用组件(功能)
      <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webartifactId>
            <version>5.3.27version>
            <scope>compilescope>
      dependency>
      <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>5.3.27version>
            <scope>compilescope>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    • 在主程序类中有以下固定写法

      @SpringBootApplication
      public class MainApplication {
          public static void main(String[] args) {
               SpringApplication.run(MainApplication.class, args);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      其中SpringApplication.run返回一个ConfigurableApplicationContext对象也就是IOC容器

      我们可以通过以下方法查看IOC容器中已装配的组件

      @SpringBootApplication
      public class MainApplication {
       public static void main(String[] args) {
           // 返回IOC容器
           ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
           //获取已装配的组件名称
           String[] beanDefinitionNames = run.getBeanDefinitionNames();
           //输出
           for(String name : beanDefinitionNames){
               System.out.println(name);
           }
       }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      输出后可以看到包括视图解析器,文件上传,字符编码等,所有web开发所需要的基本组件

    2.2 组件扫描
    • 为什么只需要设置@Controller组件,springboot就可以帮我们扫描到我们自定义的组件

      这是因为springboot所设定的默认规则 – 约定大于配置

      只要我们的程序符合以下目录结构,那他就会帮我们自动扫描

      com
      +- example
        +- myapplication
            +- MyApplication.java
            |
            +- customer
            |   +- Customer.java
            |   +- CustomerController.java
            |   +- CustomerService.java
            |   +- CustomerRepository.java
            |
            +- order
                +- Order.java
                +- OrderController.java
                +- OrderService.java
                +- OrderRepository.java
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
    • 如果想要扫描别的位置那可以在@SpringBootApplication注解中设置属性scanBasePackages,例如:

      @SpringBootApplication(scanBasePackages = "com.test")//扫描com.test下的所有组件
      public class MainApplication {
          public static void main(String[] args) {
              // 返回IOC容器
              ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
              //获取已装配的组件名称
              String[] beanDefinitionNames = run.getBeanDefinitionNames();
              //输出
              for(String name : beanDefinitionNames){
                  System.out.println(name);
              }
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    • 或者设置注解@ComponentScan(“包路径”),@SpringBootApplication就是包含这个注解的所以这两个注解不能同时使用

    3、配置文件

    3.1 各种配置都拥有默认值
    • 默认配置最终都会映射到MultipartProperties
    • 配置文件的值最终会绑定到某个类上,这个类最终会在容器中创建对象
    3.2 按需加载所有的自动配置项
    • 引入了那个场景这个场景的自动配置才会自动开启
    • SpringBoot所有的自动配置功能都在以下包中
     <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-autoconfigureartifactId>
          <version>2.7.12version>
          <scope>compilescope>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    二、容器功能

    1. 添加组件

    1.1 配置类 – 本身也是组件
    • @Configuration – 告诉SpringBoot这是一个配置类 == 配置文件
    package com.ywj.boot.config;
    
    import org.springframework.context.annotation.Configuration;
    
    /**
     * Author : YWJ
     * Date : 2023/5/26
     * Name : SpringBootDemo
     */
    @Configuration  // 告诉SpringBoot这是一个配置类 == 配置文件
    public class MyConfig {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • @Bean – 给容器中添加组件,以方法名作为组件的Id,返回类型就是组件的类型,返回的值就是组件在容器中的实例,默认都是单例
    package com.ywj.boot.config;
    
    import com.ywj.boot.pojo.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * Author : YWJ
     * Date : 2023/5/26
     * Name : SpringBootDemo
     */
    @Configuration  // 告诉SpringBoot这是一个配置类 == 配置文件
    public class MyConfig {
        
        @Bean
        // 也可使用@Bean("id")设置组件id
        public User user01(){
            return new User("张三",18);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    1.2 使用@Import导入组件
    • 给容器中自动创建出导入的组件,默认组件名称就是导入类的全类名
    @Import(User.class) // 导入一个User组件
    @Configuration(proxyBeanMethods = true)  // 告诉SpringBoot这是一个配置类 == 配置文件
    public class MyConfig {
    
        @Bean
        public User user01(){
            return new User("张三",18);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 3 查看容器中的组件
    • 使用ioc的getBean方法
    @SpringBootApplication
    public class MainApplication {
        public static void main(String[] args) {
            // 返回IOC容器
            ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
            //获取已装配的组件名称
            String[] beanDefinitionNames = run.getBeanDefinitionNames();
            //输出
            for(String name : beanDefinitionNames){
                System.out.println(name);
            }
            
            // 获取自定义的组件
            User user01 = run.getBean("user01", User.class);
            System.out.println(user01);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 也可使用配置类来执行组件方法
    @SpringBootApplication
    public class MainApplication {
        public static void main(String[] args) {
            // 返回IOC容器
            ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
           // 获取配置类组件
            MyConfig bean = run.getBean(MyConfig.class);
            //通过配置类调用组件方法
            User user = bean.user01();
            User user1 = bean.user01();
            System.out.println(user==user1);   // ture
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    上述方法也是可以返回我们所配置的组件的,并且不管调用多少次他都是单例的

    这是因为在springboot2.0以后的版本中 注解@Configuration 中有一个属性proxyBeanMethods 默认为 true

    proxyBeanMethods :是不是代理Bean的方法

    如果@Configuration(proxyBeanMethods = true);此时就会使用代理对象调用配置类中的方法,

    此时SpringBoot总会检查这个组件是否在容器中存在实例,如果存在则直接复用,因此它总是单例的

    如果改成false则不通过代理对象调用,同时也不会是单例。

    • true情况下-- 通常用来解决组件依赖问题
    • 使用false则会跳过springboot在容器中寻找的过程,大大增加服务速度
    1.4 条件装配 – @Conditional

    在这里插入图片描述

    • 示例 @ConditionalOnBean(name=“李四”) 只有在容器中存在name=”李四“的组件时,被标注的组件才能加载进容器
    @Configuration(proxyBeanMethods = true)  // 告诉SpringBoot这是一个配置类 == 配置文件
    public class MyConfig {
    
        @ConditionalOnBean(name="李四") 
        @Bean
        public User user01(){
            return new User("张三",18);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 该注解可以标注在一个方法上,也可以标注在一个类中,标注在组件方法上时只对被标注方法生效,标注在类上时,该类中所有的组件方法都会生效
    1.5 使用配置文件设置组件 – 和springMVC相同
    • 配置文件就和SpringMVC相同使用Bean标签配置
    • @ImportResource注解 – 导入一个配置文件
    @Import(User.class)
    @Configuration
    @ImportResource("classpath:beans.xml")
    
    public class MyConfig {
    
        @ConditionalOnBean(name="李四")
        @Bean
        public User user01(){
            return new User("张三",18);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1.6 配置绑定
    • 方法一

      在组件类中添加以下注解

      @Component
      @ConfigurationProperties(prefix = “test”) 其中prefix是组件属性在配置文件中的前缀,例如test.name 中的test

    • 通过在配置文件中设置相关Bean属性,然后将这些属性绑定到一个组件上

      • 配置文件
      test.name=张三
      test.age=789
      
      • 1
      • 2
      • 组件类 – 必须有get set方法
      package com.ywj.boot.pojo;
      
      import org.springframework.boot.context.properties.ConfigurationProperties;
      import org.springframework.stereotype.Component;
      
      /**
       * Author : YWJ
       * Date : 2023/5/26
       * Name : SpringBootDemo
       */
      @Component
      @ConfigurationProperties(prefix = "test")
      public class User {
      
          private String name ;
          private Integer age ;
      
          public User() {
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Integer getAge() {
              return age;
          }
      
          public void setAge(Integer age) {
              this.age = age;
          }
      
          public User(String name, Integer age) {
              this.name = name;
              this.age = age;
          }
      
          @Override
          public String toString() {
              return "User{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
      `
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 配置好后,可使用自动装配
      @RestController
      public class HelloController {
          @Autowired
         User user ;
      
          @RequestMapping("/user")
          public User getUser(){
              System.out.println(user);
              return user;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 方法二

      在配置类中添加以下注解

      @EnableConfigurationProperties(User.class)
      // 开启User的属性配置功能
      // 将这个组件自动注册到容器中
      
      • 1
      • 2
      • 3

      同时在组件上添加以下注解

      @ConfigurationProperties(prefix = “test”)

      此时不在需要配置@Component注解

    三、自动装配原理

    1. 引导加载自动配置类

    @SpringBootApplication是以下注解的一个组合注解

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(
     excludeFilters = {@Filter(
     type = FilterType.CUSTOM,
     classes = {TypeExcludeFilter.class}
    ), @Filter(
     type = FilterType.CUSTOM,
     classes = {AutoConfigurationExcludeFilter.class}
    )}
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1.1 @SpringBootConfiguration

    @SpringBootConfiguration注解源码

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration
    @Indexed
    public @interface SpringBootConfiguration {
     @AliasFor(
         annotation = Configuration.class
     )
     boolean proxyBeanMethods() default true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 可以看到@SpringBootConfiguration本质上也就是一个@Configuration
    • @Configuration代表当前是一个配置类,因此主程序类也是一个配置类,可以称之为主配置类
    1.2 @ComponentScan
    • 指定要扫那些包
    1.3 @EnableAutoConfiguration

    @EnableAutoConfiguration源码

    @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 {};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • @AutoConfigurationPackage 自动配置包==@Import({Registrar.class})==
    @Import({Registrar.class})
    public @interface AutoConfigurationPackage {
        String[] basePackages() default {};
    
        Class<?>[] basePackageClasses() default {};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    通过@Import导入组件registrar

    而组件register会将该注解所标注类所在包下的所有组件导入容器

    • @Import({AutoConfigurationImportSelector.class})

      • 利用getAutoConfigurationEntry(AnnotationMetadata annotationMetadata),给容器中批量导入一些组件
      • 利用List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);获取所有需要导入的组件的全类名
      • 利用工厂加载SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);获取 Map loadSpringFactories(ClassLoader classLoader)
      • 默认扫描我们当前系统里面所有的META-INF/spring.factories

    2. 按需加载配置

    • springboot会先加载所有的自动配置类
    • 每个自动配置类都会按照一定的条件生效,默认都会绑定配置文件指定的值。
    • 生效的配置类就会给容器中配置很多组件
    • 只要容器中有这些组件,相当与这些功能就有了
    • 只要用户有自己的配置,就以用户的为准
      • 使用@Bean配置组件
      • 修改配置文件

    3. 查看加载和未加载的配置

    • 只需开启debug模式,在application.properties 文件中添加下列内容之后再运行,就会输出配置加载信息
    debug=true
    
    • 1

    四、开发小技巧

    1. Lombok

    简化JavaBean开发

    1.1 引入lombok
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    1.2 安装插件

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sgAxZImw-1685180916916)(C:\Users\YWJ\AppData\Roaming\Typora\typora-user-images\image-20230527171704252.png)]

    1.3 在JavaBean上设置注解@Data – 编译阶段生成相应的getset方法
    package com.ywj.boot.pojo;
    
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    /**
     * Author : YWJ
     * Date : 2023/5/26
     * Name : SpringBootDemo
     */
    @Data
    @ConfigurationProperties(prefix = "test")
    public class User {
        private String name ;
        private Integer age ;
       
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    添加以下方法会在编译阶段创建相应的方法

    @ToString : 生成toString

    @AllArgsConstructor :生成所有参数的有参构造器

    @NoArgsConstructor:生成无参构造

    @EaualsAndHashCode :重写equals和hashcode

    @Slf4j :记录日志,会自动注入一个Log对象,通过Log.info(“日志信息”)

    2. dev-tools

    热更新

    2.1 引入依赖
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
            <optional>trueoptional>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2.2 生效修改

    CTRL+F9

    该方法对java代码来说是利用重新启动的

    对静态页面来说是局部修改

    2.3 热更新-- JRebel – 收费

    3. Spring Initializr – 项目初始化向导

    简化项目创建
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    Python二级 每周练习题20
    第51节:cesium 范围查询(含源码+视频)
    【Autosar 存储栈Memery Stack 4.Tc397的Flash编程】
    Pycharm中新建一个文件夹下__init__.py文件有什么用
    云原生Kubernetes:K8S资源控制之污点与容忍
    使用手机作为电脑的麦克风和摄像头外设
    react写一个简单的3d滚轮picker组件
    Redis持久化
    汽车自适应巡航系统控制策略研究
    【游戏建模全流程】Maya风格化模型制作教程
  • 原文地址:https://blog.csdn.net/qq_56056920/article/details/130903992