SpringBoot快速入门1---关于SpringBoot

本文深入探讨了SpringBoot的微服务架构,从单体应用到微服务的转变,详细解析了首个SpringBoot程序的创建过程,包括pom.xml配置、启动器和主程序的工作原理。同时,介绍了SpringBoot的自动配置机制,yaml配置文件的使用,以及JSR303数据校验和多环境切换。此外,文章还涵盖了配置文件的加载位置和优先级。
摘要由CSDN通过智能技术生成

微服务

  • 什么是微服务

    • 微服务是一种架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成―系列小服务的组合;可以通过http的方式进行互通。要说微服务架构,先得说说过去我们的单体应用架构
  • 单体应用架构

    • 所谓单体应用架构(all in one)是指,我们将一个应用的中的所有应用服务都封装在一个应用中
    • 无论是ERP、CRM或是其他什么系统,你都把数据库访问,web访问,等等各个功能放到一个war
    • 这样做的好处是,易于开发和测试;也十分方便部署;当需要扩展时,只需要将war复制多份,然后放到多个服务器上,再做个负载均衡就可以了
    • 单体应用架构的缺点是,哪怕我要修改一个非常小的地方,我都需要停掉整个服务,重新打包、部署这个应用war包。特别是对于一个大型应用,我们不可能吧所有内容都放在一个应用里面,我们如何维护、如何分工合作都是问题
  • 微服务架构

    • all in one的架构方式,我们把所有的功能单元放在一个应用里面。然后我们把整个应用部署到服务器上。如果负载能力不行,我们将整个应用进行水平复制,进行扩展,然后在负载均衡
    • 所谓微服务架构,就是打破之前all in one的架构方式,把每个功能元素独立出来。把独立出来的功能元素的动态组合,需要的功能元素才去拿来组合,需要多一些时可以整合多个功能元素。所以微服务架构是对功能元素进行复制,而没有对整个应用进行复制
    • 这样做的好处是:
      1. 节省了调用资源
      2. 每个功能元素的服务都是一个可替换的、可独立升级的软件代码

第一个SpringBoot程序

  • 创建一个springBoot项目,会自动生成以下文件

    • 程序的主程序类
    • 一个application.properties配置文件
    • 一个测试类
  • 生成的XXApplication和测试包下的XXXApplicationTests类都可以直接运行来启动当前创建的项目

  • pom.xml

    <!--有一个父项目-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.study</groupId>
    <artifactId>springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--web依赖:tomcat,dispatcherServlet,xml-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    
        <!--spring-boot-starter:所有的springboot依赖都是使用这个开头的-->
    
        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <!--打jar包插件-->
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    
    • 项目元数据信息:创建时候输入的Project Metadata部分,也就是Maven项目的基本元素,包括: groupId、artifactId、version、name、 description等
    • parent:继承spring-boot-starter-parent的依赖管理,控制版本与打包等内容
    • dependencies:项目具体依赖,这里包含了spring-boot-starter-web用于实现HTTP接口(该依赖中包含了Spring MVC),官网对它的描述是:使用Spring MVC构建Web(包括RESTful)应用程序的入门者,使用Tomcat作为默认嵌入式容器。spring-boot-starter-test用于编写单元测试的依赖包
    • build:构建配置部分。默认使用了spring-boot-maven-plugin,配合spring-boot-starter-parent就可以把Spring Boot应用打包成JAR来直接运行
  • 建相关包(必须建在XXApplication同级目录下)

  • 直接写一个controller类

    @RestController
    public class HelloController {
    
        @RequestMapping("/test")
        public String hello(){
            return "hello,world";
        }
    }
    
  • 直接运行,访问http://localhost:8080/test查看结果

  • 用Lifecycle里的package可以实现对当前项目打包

原理初探

自动配置

pom.xml
  • spring-boot-dependencies:核心依赖在父工程中

  • 我们在写或者引入一些SpringBoot依赖的时候,不需要指定版本,因为有这些版本仓库

  • 对默认依赖版本不满意,可以加入自定义版本

    <properties>
        <mysql.version>5.1.46</mysql.version>
    </properties>
    
启动器
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
  • 启动器:是springboot的启动场景
  • starter可以理解成pom配置了一堆jar组合的空maven项目,用来简化maven依赖配置,starter可以继承也可以依赖于别的starter
  • 比如spring-boot-starter-web,它就会帮我们自动导入web环境的所有依赖
  • 见到 *-spring-boot-starter:第三方为我们提供的简化开发的场景启动器
  • springboot会将所有的功能场景,都变成一个个的启动器
  • 要使用什么功能,只需要找到对应的启动器就可以了starter
主程序
@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }
}
  • 主程序所在包及其下面的所有包里面的组件都会被默认扫描

    • 想要改变扫描路径@SpringBootApplication(scanBasePackages="com.xxx")
    • 或者指定扫描:@ComponentScan("com.xxx")指定扫描路径
  • @SpringBootApplication:标注这个类是一个springboot的应用

    • 等同于@SpringBootConfiguration+@EnableAutoConfiguration+ComponentScan("com.xxx")
  • SpringApplication.run:将springboot应用启动

  • 关于@Configuration注解类需要被CGLIB代理的理解

    @Configuration
    public class Test() {
        
        @Bean
        public Person p() {
            return new Person();
        }
        
        @Bean
        public A a() {
            p();
            return new A();
        }
    }
    
    • 首先有一个问题;如果先调用方法P再调用方法A,在不生成代理对象的时候,此时会创建两次Person对象?那么创建两次对象,即在spring里非单例对象,这样的话无法保证spring中配置类的属性单例原则
    • 那么有没有一种可能,通过代理方法来管理person对象的创建,如果调用方法p()会交由代理去判断person对象是否已经被创建成功,如果是那么则交由代理对象的proxy.invokeSuper的方法调用父类去创建;如果没有则通过代理类$$BeanFactory.getBean的方法创建对象person,从而保证对象只被创建一次,即为单例
  • 注解:

    • @SpringBootConfiguration:springboot的配置
      • @Configuration:spring配置类,参数proxyBeanMethods默认为true,表示获取的对象为代理对象,多次调用,对象是同一个,springboot总会检查这个组件是否在容器中存在–保持组件单例。调成false,获取的对象不为代理对象,多次调用,对象不是同一个。两种配置:Full(全配置),Lite(轻量级)分别表示proxyBeanMethods设置为true和false。Lite模式下,配置类内部不能通过方法调用来处理依赖,否则每次生成的都是一个新实例而并非IoC容器内的单例,而且该模式下,配置类就是一普通类,所以@Bean方法可以使用private/final等进行修饰(static自然也是可以的)
        • @Component说明配置类也是一个spring的组件
    • @EnableAutoConfiguration:自动配置
      • @AutoConfigurationPackage:自动配置包
        • @Import(AutoConfigurationPackages.Registrar.class)自动配置包注册,利用Registrar给容器中导入一系列组件,将指定的一个包下的所有组件导入进来:SpringbootApplication所在的包下
      • @Import(AutoConfigurationImportSelector.class):给容器中批量导入包
        • @Import作用:用来向容器中导入配置类或者一些需要前置加载的类
        • List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);:获取所有需要导入到容器中的配置类
          • 利用工厂加载Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件,该方法是从META-INF/spring.factories位置来加载一个文件的,默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
          • 文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
  • META-INF/spring.factories:自动配置的核心文件

  • 结论:springboot所有自动配置都是在启动的时候扫描并加载:spring.factories所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的start,就有对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功

  • 步骤:

    1. springboot在启动的时候,从类路径下/META-INF/spring.factories获取指定的值
    2. 将这些自动配置的类导入容器,自动配置就会生效,帮我进行自动配置
    3. 以前我们需要手动配置的东西,现在springboot帮我们做了
    4. 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
    5. 整合javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.2.0.RELEASE.jar这个包下
    6. 容器中也会存在非常多的xxxAutoConfiguration的文件(@Bean),就是这些类给容器中导入了这个场景需要的所有组件;并自动配置,@Configuration , JavaConfig
    7. 有了自动配置类,免去了我们手动编写配置文件的工作
  • SpringApplication.run分析

    • 会开启一个进程
    • 分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行
  • SpringApplication这个类主要做了以下四件事情

    1. 推断应用的类型是普通的项目还是Web项目
    2. 查找并加载所有可用初始化器,设置到initializers属性中
    3. 找出所有的应用程序监听器,设置到listeners属性中
    4. 推断并设置main方法的定义类,找到运行的主类
      在这里插入图片描述
关于SpringBoot,谈谈你的理解
  • 自动装配
  • run()方法
    1. 判断是web项目还是普通项目
    2. 推断主类
    3. 开启监听器获取上下文处理bean

SpringBoot配置

配置文件

  • SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的
    • application.properties
      • 语法结构 :key=value
  • application.yml
    • 语法结构 :key:空格 value
  • **配置文件的作用 :**修改SpringBoot自动配置的默认值,因为默认值SpringBoot在底层都给我们自动配置好了
  • 各种配置拥有默认值
    • 默认配置最终都会映射到对象中
    • 配置文件的值最终会绑定到每个类上,这个类会在容器中创建对象

yaml概述

  • YAML是 “YAML Ain’t a Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)

  • 这种语言以数据作为中心,而不是以标记语言为重点

  • yaml可以直接给实体类赋值

  • 以前的配置文件,大多数都是使用xml来配置;比如一个简单的端口配置,我们来对比下yaml和xml

  • 传统xml配置:

    <server>
    	<port>8081<port>
    </server>
    
  • yaml配置:

    server:
    	port: 8080
    

yaml基础语法

  • 说明:语法要求严格!

    1. 空格不能省略,对空格(缩进)的要求很严格(python风格)
    2. 以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的
    3. 属性和值的大小写都是十分敏感的
    # 普通key-value
    server:
      port: 8081
    
    # 对象
    student:
      name: cbc
      age: 3
    
    # 行内写法
    student: {name: cbc, age: 3}
    
    # 数组
    pets:
      - cat
      - dog
      - pig
    
    pets: [cat, dog, pig]
    

注入配置文件

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

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

    2. 编写一个实体类 Dog

    3. 原来我们是使用@value注解给属性注值

    4. 现在试着使用yaml配置方式

      @Component
      //需要加上该注解,prefix值为yaml文件里的对象名称
      @ConfigurationProperties(prefix = "dog")
      public class Dog {
          private String name;
          private int age;
      
      # 对应prefix的值
      dog: {name: cbc, age: 3}
      
    5. pom里加上依赖就不会爆红,加不加不影响程序运行

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-configuration-processor</artifactId>
          <optional>true</optional>
      </dependency>
      
  • 也可以使用properties配置文件给对象赋值

    name=cbc
    age=3
    
  • 取值

    @PropertySource(value = "classpath:cbc.properties")
    public class Dog {
        //SPEL表达式取出配置文件的值
        @Value("${name}")
        private String name;
        @Value("${age}")
        private int age;
    
  • yaml取随机数

    dog:
      name: ${random.uuid}
      age: ${random.int}
    
  • yaml默认值,存在取存在值,不存在取默认值

    dog:
      name: ${dog.sex:hello}
      age: ${dog.sex:hello}_30
    
  • 小结

    • cp只需要写一次即可, value则需要每个字段都添加
    • 松散绑定:比如yml中写的last-name,在类里属性名可以叫lastName,-后面跟着的字母默认是大写的。这就是松散绑定
    • JSR303数据校验,这个就是我们可以在字段是增加一层过滤器验证,可以保证数据的合法性
    • 复杂类型封装,yml中可以封装对象,使用@value就不支持
      在这里插入图片描述
    • 配置yml和配置properties都可以获取到值 , 强烈推荐 yml
    • 如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value
    • 如果说,我们专门编写了一个JavaBean来和配置文件进行一一映射,就直接@configurationProperties,不要犹豫

JSR303数据校验

  • 如何使用

    • Springboot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。我们这里来写个注解让我们的name只能支持Email格式

      @Component //注册bean
      @ConfigurationProperties(prefix = "person")
      @Validated //数据校验
      public class Person {
      
          @Email(message="邮箱格式错误") //name必须是邮箱格式
          private String name;
      }
      
  • 常见参数

    @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       验证 Date 和 Calendar 对象是否在当前时间之前
    @Future     验证 Date 和 Calendar 对象是否在当前时间之后
    @Pattern    验证 String 对象是否符合正则表达式的规则
    

多环境切换

  • profile是Spring对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境

  • 多配置文件

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

    • 例如:

      • application-test.properties 代表测试环境配置

      • application-dev.properties 代表开发环境配置

      • 但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件

    • 我们需要通过一个配置来选择需要激活的环境:

      # 比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试
      # 我们启动SpringBoot,就可以看到已经切换到dev下的配置了
      spring.profiles.active=dev
      
  • 多文档块

    • 和properties配置文件中一样,但是使用yml去实现不需要创建多个配置文件,更加方便了

      server:
        port: 8081
      # 选择要激活哪个环境块
      spring:
        profiles:
          active: prod #使用环境名为prod的配置
      
      ---
      
      server:
        port: 8083
      spring:
        profiles: dev # 配置环境的名称
      
      ---
      
      server:
        port: 8084
      spring:
        profiles: prod # 配置环境的名称
      
    • 注意:如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件的!

  • 配置文件加载位置

    • 外部加载配置文件的方式十分多,我们选择最常用的即可,在开发的资源文件中进行配置
      1. file:./config/
      2. file:./
      3. classpath:/config/
      4. classpath:/
    • 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
      

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值