SpringBoot2-基础入门(二)

SpringBoot2 - 基础入门(二)

了解自动装配原理

文章目录

  • SpringBoot2 - 基础入门(二)
  • 了解自动装配原理
    • 一、依赖管理
        • 1.1 父项目做依赖管理
        • 1.2 starer场景启动器
      • 2、自动配置
        • 2.1 自动配置依赖
        • 2.2 组件扫描
      • 3、配置文件
        • 3.1 各种配置都拥有默认值
        • 3.2 按需加载所有的自动配置项
    • 二、容器功能
      • 1. 添加组件
        • 1.1 配置类 -- 本身也是组件
        • 1.2 使用@Import导入组件
        • 1. 3 查看容器中的组件
        • 1.4 条件装配 -- @Conditional
        • 1.5 使用配置文件设置组件 -- 和springMVC相同
        • 1.6 配置绑定
    • 三、自动装配原理
      • 1. 引导加载自动配置类
        • 1.1 @SpringBootConfiguration
        • 1.2 @ComponentScan
        • 1.3 @EnableAutoConfiguration
      • 2. 按需加载配置
      • 3. 查看加载和未加载的配置
    • 四、开发小技巧
      • 1. Lombok
        • 1.1 引入lombok
        • 1.2 安装插件
        • 1.3 在JavaBean上设置注解@Data -- 编译阶段生成相应的getset方法
      • 2. dev-tools
        • 2.1 [引入依赖](https://docs.spring.io/spring-boot/docs/2.7.12/reference/html/using.html#using.devtools)
        • 2.2 生效修改
        • 2.3 热更新-- JRebel -- 收费
      • 3. Spring Initializr -- 项目初始化向导

一、依赖管理

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>

在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>
  • 如何覆盖父项目中的配置

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

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

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

1.2 starer场景启动器

  • 以spring-boot-starter-*命名的依赖文件
  • 官方文档地址

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

以web为例:

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

SpringBoot2-基础入门(二)_第1张图片

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

2、自动配置

2.1 自动配置依赖

  • 自动配置Tomcat

    • 引入Tomcat依赖
    • 配置
    <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-starter-tomcatartifactId>
          <version>2.7.12version>
          <scope>compilescope>
    dependency>
    
  • 自动配置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>
    
  • 在主程序类中有以下固定写法

    @SpringBootApplication
    public class MainApplication {
        public static void main(String[] args) {
             SpringApplication.run(MainApplication.class, args);
        }
    }
    

    其中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);
         }
     }
    }
    

    输出后可以看到包括视图解析器,文件上传,字符编码等,所有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
    
  • 如果想要扫描别的位置那可以在@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);
            }
        }
    }
    
  • 或者设置注解@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. 添加组件

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 {
}
  • @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 使用@Import导入组件

  • 给容器中自动创建出导入的组件,默认组件名称就是导入类的全类名
@Import(User.class) // 导入一个User组件
@Configuration(proxyBeanMethods = true)  // 告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {

    @Bean
    public User user01(){
        return new User("张三",18);
    }
}

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);
    }
}
  • 也可使用配置类来执行组件方法
@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
    }
}

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

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

proxyBeanMethods :是不是代理Bean的方法

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

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

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

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

1.4 条件装配 – @Conditional

SpringBoot2-基础入门(二)_第2张图片

  • 示例 @ConditionalOnBean(name=“李四”) 只有在容器中存在name=”李四“的组件时,被标注的组件才能加载进容器
@Configuration(proxyBeanMethods = true)  // 告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {

    @ConditionalOnBean(name="李四") 
    @Bean
    public User user01(){
        return new User("张三",18);
    }
}
  • 该注解可以标注在一个方法上,也可以标注在一个类中,标注在组件方法上时只对被标注方法生效,标注在类上时,该类中所有的组件方法都会生效

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.6 配置绑定

  • 方法一

    在组件类中添加以下注解

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

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

    • 配置文件
    test.name=张三
    test.age=789
    
    • 组件类 – 必须有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 +
                    '}';
        }
    }
    `
    
    • 配置好后,可使用自动装配
    @RestController
    public class HelloController {
        @Autowired
       User user ;
    
        @RequestMapping("/user")
        public User getUser(){
            System.out.println(user);
            return user;
        }
    }
    
  • 方法二

    在配置类中添加以下注解

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

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

    @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.1 @SpringBootConfiguration

@SpringBootConfiguration注解源码

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
 @AliasFor(
     annotation = Configuration.class
 )
 boolean proxyBeanMethods() default true;
}
  • 可以看到@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 {};
}
  • @AutoConfigurationPackage 自动配置包==@Import({Registrar.class})==
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}

通过@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. Lombok

简化JavaBean开发

1.1 引入lombok

<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
dependency>

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 ;
   
}

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

@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>

2.2 生效修改

CTRL+F9

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

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

2.3 热更新-- JRebel – 收费

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

简化项目创建
SpringBoot2-基础入门(二)_第3张图片

在这里插入图片描述
SpringBoot2-基础入门(二)_第4张图片

你可能感兴趣的:(springboot,spring,boot,java,spring)