SpringBoot 的入门学习(1):helloword,启动类的底层逻辑,yam配置注入, JSR 数据校验,自定义stater,@Configuration

01、概述

官方网站
官方文档(中文版)
相关版本

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”.
能快速创建出生产级别的Spring应用。

Spring是如何简化Java开发的

为了降低Java开发的复杂性,Spring采用了以下4种关键策略:

1、基于POJO的轻量级和最小侵入性编程(客户端实现框架借口,解耦),所有东西都是bean;
2、通过IOC,依赖注入(DI)和面向接口实现松耦合;
3、基于切面(AOP)和惯例进行声明式编程;
4、通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;

Springboot 的优缺点

优点

  • 创建独立Spring应用
  • 内嵌web服务器
  • 开箱即用,自动starter依赖,简化构建配置
  • 自动配置Spring以及第三方功能
  • 提供生产级别的监控、健康检查及外部化配置
  • 无代码生成、无需编写XML
  • SpringBoot是整合Spring技术栈的一站式框架。SpringBoot是简化Spring技术栈的快速开发脚手架

缺点

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

微服务,分布式与云原生

微服务

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

分布式

  • 分布式计算是计算机科学中一个研究方向,它研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配给多个计算机进行处理,最后把这些计算结果综合起来得到最终的结果。
  • 分布式网络存储技术是将数据分散地存储于多台独立的机器设备上。
  • 分布式网络存储系统采用可扩展的系统结构,利用多台存储服务器分担存储负荷,利用位置服务器定位存储信息,不但解决了传统集中式存储系统中单存储服务器的瓶颈问题,还提高了系统的可靠性、可用性和扩展性。

云原生

  • 实际上,云原生是一条最佳路径或者最佳实践。更详细的说,云原生为用户指定了一条低心智负担的、敏捷的、能够以可扩展、可复制的方式最大化地利用云的能力、发挥云的价值的最佳路径。
  • 云原生其实是一套指导进行软件架构设计的思想。 按照这样的思想而设计出来的软件:首先,天然就“生在云上,长在云上”;其次,能够最大化地发挥云的能力,使得我们开发的软件和“云”能够天然地集成在一起,发挥出“云”的最大价值。

原生应用如何上云。 Cloud Native

02、基础入门-SpringBoot-HelloWorld

方式1:直接使用 Spring Initializr 的 web 页面创建项目

在这里插入图片描述

方式2:使用 IDEA 的 Spring Initializater插件直接创建项目

在这里插入图片描述
在这里插入图片描述
注意 :下图中右上角会有一个版本选择,如果选择的版本之前maven库中没有,就会加载一段时间。
在这里插入图片描述

方式3:手动创建项目

  • 创建依赖

    <parent>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-parent</artifactId>
    	<version>2.3.4.RELEASE</version>
    </parent>
    
    <dependencies>
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-web</artifactId>
    	</dependency>
    </dependencies>
    
  • 创建主程序

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class MainApplication {
          
          
    
        public static void main(String[] args) {
          
          
            SpringApplication.run(MainApplication.class, args);
        }
    }
    
    
  • 编写业务:

    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
          
          
        @RequestMapping("/hello")
        public String handle01(){
          
          
            return "Hello, Spring Boot 2!";
        }
    }
    
  • 运行&测试
    运行MainApplication类
    浏览器输入http://localhost:8888/hello,将会输出Hello, Spring Boot 2!

  • 设置配置
    maven 工程的 resource 文件夹中创建 application.properties 文件。

    # 设置端口号,当然最好不该,就按照默认 8080来
    server.port=8888
    
    

    点击这里查看更多配置信息

  • 打包部署
    在pom.xml添加

    <build>
    	<plugins>
    		<plugin>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-maven-plugin</artifactId>
    		</plugin>
    	</plugins>
    </build>
    
    • 在IDEA的Maven插件上点击运行 clean 、package,把 helloworld 工程项目的打包成jar包,
    • 打包好的jar包被生成在helloworld工程项目的target文件夹内。
    • 用cmd运行 java -jar boot-01-helloworld-1.0-SNAPSHOT.jar,既可以运行helloworld工程项目。将jar包直接在目标服务器执行即可。

03、运行原理探索

①、导入start 依赖的父项目的依赖

  • 上面这个Spring项目,主要是依赖一个父项目,主要是管理项目的资源过滤及插件!

    <!--引入启动器所依赖的父项目-->
    <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>	
    

    spring-boot-dependencies 主要用于管理项目的依赖的版本号,只要引入了这个 项目,就无须考虑引入其他依赖时的版本号了,进而避免了某些包的版本冲突。
    其实 spring-boot-dependencies 本身就是一个 pom.xml,里面管理了很多常见第三方的依赖和版本。
    在这里插入图片描述

②、配置启动器(starter)

启动器: 说白了就是SpringBoot的启动场景;

  • springboot-boot-starter-xxx:就是spring-boot的场景启动器。只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
    启动器存在很多中,官方给出的启动器命名规则为 : spring-boot-starter-* 其中*是特定类型的应用程序。如下所示:(更多启动器参数点击这里)
    在这里插入图片描述

  • 在helloword 中我们引入的启动器依赖如下:
    spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件;

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    

此时无需关注版本号,spring-boot-dependencies 会自动进行版本仲裁。

IDEA快捷键:

  • ctrl + shift + alt + U:以图的方式显示项目中依赖之间的关系。
  • alt + ins:相当于Eclipse的 Ctrl + N,创建新类,新包等。

③:主启动类

默认主启动类

//@SpringBootApplication 来标注一个主程序类
//说明这是一个Spring Boot应用
@SpringBootApplication
public class SpringbootApplication {
    
    

   public static void main(String[] args) {
    
    
     //以为是启动了一个方法,没想到启动了一个服务
      SpringApplication.run(SpringbootApplication.class, args);
   }
}

@SpringBootApplication 原理解析

作用:标注在某个类上说明这个类是SpringBoot的主配置类 , SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
进入这个注解:可以看到上面还有很多其他注解!

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

  • @ComponentScan: 这个注解在Spring中很重要 ,它对应XML配置中的元素。
    作用:自动扫描并加载符合条件的组件或者bean, 将这个bean定义加载到IOC容器中

  • @SpringBootConfiguration:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类。
    点击进去得到下面的注解:

    // 点进去得到下面的 @Component
    @Configuration
    public @interface SpringBootConfiguration {
          
          }
    
    @Component //说明这也是一个spring的组件
    public @interface Configuration {
          
          }
    
    
    • @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件;
    • @Component 说明,启动类本身也是Spring中的一个组件而已,负责启动应用!
  • @EnableAutoConfiguration 自动配置功能,告诉SpringBoot开启自动配置功能,这样自动配置才能生效;
    点进注解接续查看:

    @AutoConfigurationPackage
    @Import({
          
          AutoConfigurationImportSelector.class})
    public @interface EnableAutoConfiguration {
          
          
        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    
        Class<?>[] exclude() default {
          
          };
    
        String[] excludeName() default {
          
          };
    }
    
    
    • @AutoConfigurationPackage 的源码如下:
      @Import({
              
              Registrar.class})    //导入选择器包注册
      public @interface AutoConfigurationPackage {
              
              
          String[] basePackages() default {
              
              };
          Class<?>[] basePackageClasses() default {
              
              };
      }	
      
      @import :Spring 底层注解 , 给容器中导入一个组件。这里导入了 一个Registrar.class,是为了将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;这样是为什么所有的文件必须在主启动类所在的包下,如果不在该包下,就需要添加新的注释
    • @Import({AutoConfigurationImportSelector.class}):自动配置导入选择器。具体解释看下面。

@Import({AutoConfigurationImportSelector.class})

@Import({AutoConfigurationImportSelector.class})**@EnableAutoConfiguration 中,能够 自动配置导入选择器。那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:

  • 1、这个类中有一个这样的方法

    // 获得候选的配置
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
          
          
        //这里的getSpringFactoriesLoaderFactoryClass()方法
        //返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }
    
    
  • 2、这个方法又调用了 SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法

    public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
          
          
        String factoryClassName = factoryClass.getName();
        //这里它又调用了 loadSpringFactories 方法
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }
    
  • 3、我们继续点击查看 loadSpringFactories 方法

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
          
          
        //获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
          
          
            return result;
        } else {
          
          
            try {
          
          
                //去获取一个资源 "META-INF/spring.factories"
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();
    
                //将读取到的资源遍历,封装成为一个Properties
                while(urls.hasMoreElements()) {
          
          
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();
    
                    while(var6.hasNext()) {
          
          
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryClassName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;
    
                        for(int var11 = 0; var11 < var10; ++var11) {
          
          
                            String factoryName = var9[var11];
                            result.add(factoryClassName, factoryName.trim());
                        }
                    }
                }
    
                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
          
          
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }
    
    
  • 4、发现一个多次出现的文件:spring.factories,全局搜索它
    spring.factories
    我们根据源头打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在!
    在这里插入图片描述

  • 5、我们在上面的自动配置类随便找一个打开看看,比如 :WebMvcAutoConfiguration
    在这里插入图片描述
    可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看着熟悉一下!

加载 spring.factories 总结

  • SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。(xxxxProperties里面读取,xxxProperties和配置文件进行了绑定)
  • 生效的配置类就会给容器中装配很多组件
  • 只要容器中有这些组件,相当于这些功能就有了
  • 定制化配置
    • 用户直接自己@Bean替换底层的组件
    • 用户去看这个组件是获取的配置文件什么值就去修改。

自动配置的过程总结

  • SpringBoot 在启动的时候从类路径下的 META-INF/spring.factories 中获取EnableAutoConfiguration 指定的值
  • 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作(以前需要我们自动配置的东西,现在SpringBoot帮我们做了);
  • 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
  • 它会吧所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
  • 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
  • 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;

配置类的过程

在编程中,我们的配置类过程如下:

  • 1、SpringBoot启动会加载大量的自动配置类
  • 2、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
  • 3、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
  • 4、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
    xxxxAutoConfigurartion:自动配置类;给容器中添加组件

@Conditional

  • 自动配置类必须在一定的条件下才能生效;

  • @Conditional派生注解(Spring注解版原生的@Conditional作用)
    作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;
    在这里插入图片描述

  • 那么多的自动配置类,必须在一定的条件下才能生效;也就是说,我们加载了这么多的配置类,但不是所有的都生效了。

  • 我们可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;

    #开启springboot的调试类
    debug=true
    
    • Positive matches:(自动配置类启用的:正匹配)
    • Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
    • Unconditional classes: (没有条件的类)

SpringApplication.run 原理分析

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

SpringApplication.run 主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;

SpringApplication 类实例化的时候会进行下面几步操作:

  • 1、推断应用的类型是普通的项目还是Web项目
  • 2、查找并加载所有可用初始化器 , 设置到initializers属性中
  • 3、找出所有的应用程序监听器,设置到listeners属性中
  • 4、推断并设置main方法的定义类,找到运行的主类

SpringApplication 的run 方法会进行下面操作:

  • 启动监听器模块
  • 启动配置环境模块
  • 启动应用上下文模块

如下图所示:
在这里插入图片描述

04、相关插件

Lombok 自动生成构造器,getter,setter,toString等

  • spring boot已经管理Lombok。引入依赖:

     <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
    </dependency>
    
  • IDEA中File->Settings->Plugins,搜索安装Lombok插件。

    @NoArgsConstructor
    //@AllArgsConstructor
    @Data
    @ToString
    @EqualsAndHashCode
    public class User {
          
          
    
        private String name;
        private Integer age;
    
        private Pet pet;
    
        public User(String name,Integer age){
          
          
            this.name = name;
            this.age = age;
        }
    }
    

slf4j 简化日志开发

@Slf4j
@RestController
public class HelloController {
    
    
    @RequestMapping("/hello")
    public String handle01(@RequestParam("name") String name){
    
    
        log.info("请求进来了....");
        return "Hello, Spring Boot 2!"+"你好:"+name;
    }
}

dev-tools:实时修改页面

添加依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

在IDEA中,项目或者页面修改以后:Ctrl+F9。

05、yaml配置注入

配置文件

SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的 。他们具有两种格式:

  • properties 格式:application.properties
    语法结构 :key=value
  • yaml 格式:application.yaml
    语法结构 :key:空格 value

配置文件的作用 : 修改SpringBoot自动配置的默认值,因为 SpringBoot 在底层都给我们自动配置好了;

比如我们可以在配置文件中修改Tomcat 默认启动的端口号!测试一下!

server.port=8081

yaml 概述

YAML是 “YAML Ain’t a Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)
说明: 语法必须严格遵守下面的要求:

  • 1、空格不能省略
  • 2、以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。
  • 3、属性和值的大小写都是十分敏感的。

基础语法

  • 字面量:普通的值 [ 数字,布尔值,字符串 ]
    字面量直接写在后面就可以 , 字符串默认不用加上双引号或者单引号;

    k: v
    
  • 对象、Map(键值对)

    student:
        name: qinjiang
        age: 3
    
  • 数组( List、set )
    用 - 值表示数组中的一个元素,比如:

    pets:
     - cat
     - dog
     - pig
    
  • 行内写法

    student: {
          
          name: qinjiang,age: 3}
    pets: [cat,dog,pig]
    
  • 注意:

    “ ” 双引号:不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;
    比如 :name: “kuang \n shen” 输出 :kuang 换行 shen
    ‘’ 单引号:会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出
    比如 :name: ‘kuang \n shen’ 输出 :kuang \n shen

  • 例子:修改 SpringBoot 的默认端口号

    server:
      port: 8082
    

yaml注入配置文件

yaml文件更强大的地方在于,他可以给我们的实体类直接注入匹配值!
例子1

  • 1、在springboot项目中的resources目录下新建一个文件 application.yml

  • 2、编写一个实体类 Dog;

    ackage com.kuang.springboot.pojo;
    
    @Component  //注册bean到容器中
    public class Dog {
          
          
        private String name;
        private Integer age;
        
        //有参无参构造、get、set方法、toString()方法  
    }
    
  • 3、如果我们需要给这个bean 赋值,那么就需要使用 @value 注释

    @Component //注册bean
    public class Dog {
          
          
        @Value("阿黄")
        private String name;
        @Value("18")
        private Integer age;
    }
    
  • 4、在SpringBoot的测试类下注入狗狗输出一下;

    @SpringBootTest
    class DemoApplicationTests {
          
          
    
        @Autowired //将狗狗自动注入进来
        Dog dog;
    
        @Test
        public void contextLoads() {
          
          
            System.out.println(dog); //打印看下狗狗对象
        }
    
    }
    
    
  • 结果成功输出,@Value注入成功,这是我们原来的办法。
    在这里插入图片描述

例子2:此时存在更多的默认属性时

@Component //注册bean到容器中
public class Person {
    
    
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
    
    //有参无参构造、get、set方法、toString()方法  
}
  • 我们来使用yaml配置的方式进行注入,大家写的时候注意区别和优势,我们编写一个yaml配置!

    person:
      name: qinjiang
      age: 3
      happy: false
      birth: 2000/01/01
      maps: {
          
          k1: v1,k2: v2}
      lists:
       - code
       - girl
       - music
      dog:
        name: 旺财
        age: 1
    
    
  • 我们刚才已经把person这个对象的所有值都写好了,我们现在来注入到我们的类中!

    /*
    @ConfigurationProperties作用:
    将配置文件中配置的每一个属性的值,映射到这个组件中;
    告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
    参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
    */
    @Component //注册bean
    @ConfigurationProperties(prefix = "person")
    public class Person {
          
          
        private String name;
        private Integer age;
        private Boolean happy;
        private Date birth;
        private Map<String,Object> maps;
        private List<Object> lists;
        private Dog dog;
    }
    
    
  • 注意: 上面的读入配置文件的注释需要添加依赖,如下

    <!-- 导入配置文件处理器,配置文件进行绑定就会有提示,需要重启 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
    </dependency>
    
    
  • @configurationProperties: 默认从全局配置文件中获取值;
    @PropertySource: 加载指定的配置文件;如果配置文件在当前目录下则书写 @PropertySource(value = "classpath:person.properties")

配置文件占位符: 随机数的生成

配置文件还可以编写占位符生成随机数

person:
    name: qinjiang${
    
    random.uuid} # 随机uuid
    age: ${
    
    random.int}  # 随机int
    happy: false
    birth: 2000/01/01
    maps: {
    
    k1: v1,k2: v2}
    lists:
      - code
      - girl
      - music
    dog:
      name: ${
    
    person.hello:other}_旺财
      age: 1

测试一下:
在这里插入图片描述

回顾properties配置

配置文件除了yml还有我们之前常用的properties。
【注意】 properties配置文件在写中文的时候,会有乱码 , 我们需要去IDEA中设置编码格式为UTF-8;
settings–>FileEncodings 中配置;
在这里插入图片描述
测试步骤

  • 1、新建一个实体类User

    @Component //注册bean
    public class User {
          
          
        private String name;
        private int age;
        private String sex;
    }
    
  • 2、编辑配置文件 user.properties

    user1.name=kuangshen
    user1.age=18
    user1.sex=男
    
  • 3、我们在User类上使用@Value来进行注入!

    @Component //注册bean
    @PropertySource(value = "classpath:user.properties")
    public class User {
          
          
        //直接使用@value
        @Value("${user.name}") //从配置文件中取值
        private String name;
        @Value("#{9*2}")  // #{SPEL} Spring表达式
        private int age;
        @Value("男")  // 字面量
        private String sex;
    }
    
  • 4、Springboot测试

    @SpringBootTest
    class DemoApplicationTests {
          
          
        @Autowired
        User user;
        @Test
        public void contextLoads() {
          
          
            System.out.println(user);
        }
    }
    
  • 结果正常输出:
    在这里插入图片描述

注入方式对比

@Value这个使用起来并不友好!我们需要为每个属性单独注解赋值,比较麻烦;我们来看个功能对比图
在这里插入图片描述

1、@ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加

2、松散绑定:这个什么意思呢? 比如我的yml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定。可以测试一下
3、JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性
4、复杂类型封装,yml中可以封装对象 , 使用value就不支持

06、JSR303数据校验

先看看如何使用

  • 导入配置文件

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    
    
  • Springboot中可以用 @validated 来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。我们这里来写个注解让我们的name只能支持Email格式;

    @Component //注册bean
    @ConfigurationProperties(prefix = "person")
    @Validated  //数据校验
    public class Person {
          
          
    	//email 注释已经在 validation 中有所定义
        @Email(message="邮箱格式错误") //name必须是邮箱格式
        private String name;
    }
    
  • 运行结果 :default message [不是一个合法的电子邮件地址];
    在这里插入图片描述

常见参数

@NotNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private int age;
@Email(message="邮箱格式错误")
private String email;

空检查
@Null       验证对象是否为null
@NotNull    验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank   检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty   检查约束元素是否为NULL或者是EMPTY.
    
Booelan检查
@AssertTrue     验证 Boolean 对象是否为 true  
@AssertFalse    验证 Boolean 对象是否为 false  
    
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  
@Length(min=, max=) string is between min and max included.

日期检查
@Past       验证 DateCalendar 对象是否在当前时间之前  
@Future     验证 DateCalendar 对象是否在当前时间之后  
@Pattern    验证 String 对象是否符合正则表达式的规则

.......等等
除此以外,我们还可以自定义一些数据校验规则

07 多环境切换

Properties 下的多配置文件

我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本;
例如:

  • application-test.properties: 代表测试环境配置
  • application-dev.properties: 代表开发环境配置

但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件;我们需要通过一个配置来选择需要激活的环境。
通过spring.profile决定激活哪个环节,注意value值为 application-{profile}.properties/yml 中的 profile
比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;

#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
spring.profiles.active=dev  
#springboot的多环境配置: 可以选择激活哪一个配置文件

yaml的多文档模块

和properties配置文件中一样,但是使用yml去实现不需要创建多个配置文件。如下,不同的端口号配置不同:

server:
  port: 8081
#选择要激活那个环境块
spring:
  profiles:
    active: prod

---
server:
  port: 8083
spring:
  profiles: dev #配置环境的名称


---

server:
  port: 8084
spring:
  profiles: prod  #配置环境的名称

注意: 如果yml和properties同时都配置了端口,并且没有激活其他环境 ,默认会使用properties配置文件的

配置文件的位置

外部加载配置文件的方式十分多,我们选择最常用的即可,在开发的资源文件中进行配置!
springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:

优先级1:项目路径下的config文件夹配置文件
优先级2:项目路径下配置文件
优先级3:资源路径下的config文件夹配置文件
优先级4:资源路径下配置文件

  • 优先级由高到底,高优先级的配置会覆盖低优先级的配置;

  • SpringBoot会从这四个位置全部加载主配置文件;互补配置;

  • 我们还可以通过spring.config.location 来改变默认的配置文件位置

  • 项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;这种情况,一般是后期运维做的多,相同配置,外部指定的配置文件优先级最高

    java -jar spring-boot-config.jar --spring.config.location=F:/application.properties
    

08、自定义 新的 starter

说明

启动器模块是一个 空 jar 文件,仅提供辅助性依赖管理,这些依赖可能用于自动装配或者其他类库;

官方命名:

  • 前缀:spring-boot-starter-xxx
  • 比如:spring-boot-starter-web

自定义命名:

  • xxx-spring-boot-starter
  • 比如:mybatis-spring-boot-starter

我们都知道可以使用SpringBoot快速的开发基于Spring框架的项目。由于围绕SpringBoot存在很多开箱即用的Starter依赖,使得我们在开发业务代码时能够非常方便的、不需要过多关注框架的配置,而只需要关注业务即可。

  • 其实springboot的一个启动器基本上就包含两个项目,一个是spring-boot-starter,另一个是spring-boot-autoConfigure
    在这里插入图片描述
  • starter项目模块在pom文件中引入了autoConfiger这个项目,所以starter里面可以使用autoConfiger里面的东西。

其实写自己启动器也就是大致5个步骤

  • 1:编写自己具体的业务,根据自己的需求。
  • 2:xxxProperties配置文件的编写
  • 3:xxxAutoConfigure的编写
  • 4:将我们的启动类放到springboot项目中的resouces/META-INT下面的spring.factories(这个目录以及文件需要自己手动建)
  • 5:将自己编写的自动配置安装到Maven仓库即可。
  • 6:测试。

编写启动器

  • 第一步首先创建一个空项目,根据创建三个模块如下:
    在这里插入图片描述

  • 第二步:编写peoperties
    在这里插入图片描述

  • 第三步:编写autoConfig
    在这里插入图片描述

  • 第四步:在当前项目下,我们的业务(即使用配置文件,完成的事情)在这里插入图片描述

  • 第五步:创建META-INF/spring.factories文件,指定要加载的配置文件 。

  • 第六步:把项目打包并测试,在starter项目中引入autoConfig
    在这里插入图片描述
    在这里插入图片描述

  • 最后一步,便是建立一个项目测试
    在这里插入图片描述

  • 在当前项目下,添加配置文件application.properties:

    //前缀为@ConfigurationProperties 传入的参数
    c.cover.hello.prefix="prefix"
    c.cover..hello.suffix="suffix"
    
  • 结果如下:
    在这里插入图片描述

@Configuration

Spring3.0开始,@Configuration 用于定义配置类,定义的配置类可以替换xml文件,一般和@Bean注解联合使用。

  • @Configuration注解主要标注在某个类上,相当于xml配置文件中的<beans>
  • @Bean注解主要标注在某个方法上,相当于xml配置文件中的<bean>
    在这里插入图片描述
    等价于
    在这里插入图片描述
    注意:@Configuration注解的配置类有如下要求:
  • @Configuration不可以是final类型;
  • @Configuration不可以是匿名类;
  • 嵌套的configuration必须是静态类。

其他创建 bean 注释

Configuration里面有一个 component 组件来标识,说明此类也是一个 bean,可以被调用,来看看哪些主要的注解含有 component:

  • @Component: 可以使用此注解描述 Spring 中的 Bean ,但它是一个泛化的概念**,仅仅表 示一个组件** (Bean ,并且可以作用在任何层次 使用时只需将该注解标注在相应类上即可

  • @Repository: 用于将数据访问层( DAO 层)的类标识为 Spring 中的 Bean ,其功能与 @Component 相同

  • @Service: 通常作用在业务层( Service ,用于将业务层的类标识为 Spring 中的 Bean 其功能与@Component 相同

  • @Controller: 通常作用在控制层(如 Spring MVC Controller ,用于将控制层的类标识 Spring 中的 Bean ,其功能与@Component 相同

  • @Autowired: 用于对 Bean 的属性变量、属性的 setter 方法及构造方法进行标注,配合对 应的注解处理器完成 Bean 的自动配置工作 默认按照 Bean 的类型进行装配

  • @Resource: 其作用与 Autowired 一样 ==其区别在于@Autowired 默认按照 Bean 类型装 配,而@Resource 默认按照 Bean 实例名称进行装配 ==
    @Resource 中有两个重要属性: name 和 type。

    • name 属性解析为 Bean 实例名称, type 属性解析为 Bean 实例类型
    • 如果 指定 name 属性,按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配;如 果都不指定,则先按 Bean 实例名称装配,如果不能匹配,再按照 Bean 类型进行装自己;如果都 无法匹配,则抛出 NoSuchBeanDefinitionException 异常
  • @Qualifier: @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为接 Bean 的实例名称装配, Bean 的实例名称由 @Qualifier 注解的参数指定。 在上面几个注解中,虽然@Repository @Service @Controller 功能与@Component 注解 的功能相同,但为了使标注类本身用途更加清晰,建议在实际开发中使用@Repository @Service @Controller 分别对实现类进行标注 下面。

@Configuration的不同格式与 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-3.0.xsd"
           default-lazy-init="true">
        <!--bean定义-->
    </beans>
    

    等价于

    @Configuration
    public class MockConfiguration{
          
          
        //bean定义
    }
    
  • 注册bean 定义层面,添加bean的返回类型

    <bean id="mockService" class="..MockServiceImpl">
        ...
    </bean>
    

    等价于

    @Configuration
    public class MockConfiguration{
          
          
        @Bean
        public MockService mockService(){
          
          
            return new MockServiceImpl();
        }
    }
    
  • 表达依赖注入关系层面

    <bean id="mockService" class="..MockServiceImpl">
        <propery name ="dependencyService" ref="dependencyService" />
    </bean>
    
    <bean id="dependencyService" class="DependencyServiceImpl"></bean>
    

    等价于

    @Configuration
    public class MockConfiguration{
          
          
        @Bean
        public MockService mockService(){
          
          
            return new MockServiceImpl(dependencyService());
        }
        
        @Bean
        public DependencyService dependencyService(){
          
          
            return new DependencyServiceImpl();
        }
    }
    

猜你喜欢

转载自blog.csdn.net/Mr_tianyanxiaobai/article/details/119750938