SpringBoot(一)——自动装配原理

个人博客:http://blog.kunpw.cn/

SpringBoot

1.创建SpringBoot文件

1.1 官网创建文件并下载,使用IDEA打开

1.2 IDEA创建

  • New Project -> Spring Initializr(本质也是从官网下载的模板格式);
  • 添加 java web 依赖;

2.文件简析

2.1 pom.xml

  • 配置文件,主要有四个部分:

    • 项目元数据信息:创建时输入的Project Metadata部分,也就是Meaven项目的基本元素,包括groupId、artifactId、version、name、description等;
    • parent:继承spring-boot-starter-parent的依赖管理、控制版本和打包等内容;
    • dependencies:项目具体依赖,下面包含了spring-boot-starter-web用于实现HTTP接口(该依赖包含了Spring MVC,且使用Tomcat作为默认嵌入式容器),spring-boot-starter-test是用于编写后续单元测试的依赖包:
    <!--  在这个标签中添加  -->
    <dependencies>
            <!--  添加依赖,格式为 spring-boot-starter- 这是springboot启动器的标准格式     -->
        	<!--  web依赖,tomcat      -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        
        	<dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    </dependencies>
    
    • build:构件配置部分,默认使用了spring-boot-maven-plugin,即打jar包插件;

2.2 application.properties

  • src/main/javaresource/application.properties目录核心配置文件;
  • 重写服务属性,稍后详述;
  • 编辑对象、定义属性;
  • 常用小服务:
# 直接更改项目端口号即可,修改之后再次访问该端口才能成功
server.port=8081

2.3 banner.txt(小彩蛋)


//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88" . "88                              //
//                         (| ^_^ |)                              //
//                         O\  =  /O                              //
//                      ____/`---'\____                           //
//                    .'  \\|     |//  `.                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  ''\---/''  |   |                       //
//                  \  .-\__  `-`  ___/-. /                       //
//                ___`. .'  /--.--\  `. . ___                     //
//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
//      ========`-.____`-.___\_____/___.-`____.-'========         //
//                           `=---='                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//            佛祖保佑       永不宕机     永无BUG                    //

2.4 XXXApplication.java

  • src/main/java/com/kun/XXXApplication.java目录文件;
//标注这是一个SpringBoot应用,加载所有资源类
@SpringBootApplication
public class Demo01Application {
    //程序入口
    //run,开启了一个服务,参数一:应用入口的类,参数二:命令行输入的参数类
    /*SpringApplication实例化,做了以下四项工作:
    1.判断该应用类型是普通java项目还是Web项目
    2.查找并加载所有可用初始化器,设置到initializers属性中
    3.找出所有的应用程序监听器,设置到listeners属性中
    4.推断并设置main方法的定义类,找到运行的主类
    * */
    public static void main(String[] args) {
        SpringApplication.run(Demo01Application.class, args);
    }

}

2.5 XXXApplicationTests.java

  • test/java/com/kun/XXXApplicationTests.java目录文件;
  • 实现单元测试功能;

2.6 自建框架层

  • src/main/java/com/kun/最底层包目录下新建configcontrollerdaopojo等包,这些具体用到再详细讲解,也可以参考博客简略了解一下:https://www.cnblogs.com/tooyi/p/13340374.html
  • 为说明几个常用注解以及习惯注解的用法,新建controller包,并在该目录下新建HelloController.java文件:
//使用Controller注解标注说明并被加载
@Controller
//使用Mapping类注解来映射请求,即请求/hello时响应回该类
@RequestMapping("/hello")
public class HelloController {
    //在/hello地址请求之下再请求地址/hello即可获得下列响应
    @GetMapping("/hello")
    //当请求/hello/hello时,响应主体部分为hello()方法
    @ResponseBody
    public String hello(){
        return "hello";
    }
}

3.yaml(yml)语法

  • yaml文件是对properties文件的替代,但比properties更实用,所以一般使用yaml;
  • 删除application.properties文件,新建application.yaml(.yml);

3.1 常用语法:

# 1.基础语法
# 修改自动配置的默认值,其中 : 后必须接空格
# yaml 对空格很敏感,很像python  而properties只能保存键值对

server:
  port: 8081

# yaml基本语法
# 定义参数使用key-value
name: zhaoxiaoan

# 定义对象
student:
  name: zhaoxiaoan
  age: 3

# 对象的行内写法
teacher: {name: zhao,age 30}

# 定义数组
pets:
  - cat
  - dog
  - pig

# 数组的行内写法
pet: [cat,dog,pig]

# EL表达式
age: ${random.int}

# 占位符
person: 
	hello: happy
	dog:
		name: ${person.hello:hello}_旺财
# 如果没有就直接为空,有则占位显示,即happy_旺财

3.2 重点:给实体类赋值:

  • 新建数据类:新建pojo/Dog.java、pojo/Person.java类
package com.kun.pojo;

import org.springframework.stereotype.Component;

@Component
public class Dog {
    private String name;
    private Integer age;

    //有参无参构造器、get/set方法以及toString方法,后续这些方法不再细列
    public Dog() {
    }

    public Dog(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

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

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.kun.pojo;

import java.util.Date;
import java.util.List;
import java.util.Map;

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;
	
    //省略各方法
}

  • 赋值:

    • 直接new对象;
  • 原生注解赋值:

    //1.0
    public class Dog {
        @Value("zhaoxiaoan")
        private String name;
        @Value("3")
        private Integer age;
    }
    
    • yaml文件赋值:
    # 2.0
    person:
      name: zhaoxiaoan
      age: 3
      happy: true
      birth: 2020/10/22
      maps: {k1: v1,k2: v2}
      lists:
        - code
        - music
        - study
      dog:
        name: 旺财
        age: 3
    
    @Component
    /*@PropertySource(value = "classpath:application.yaml")
    通过该注解设置装配文件
    */
    //通过ConfigurationProperties(prefix = "person")注解绑定映射yaml文件中person对象
    @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;
    }
    
    • 单元测试:

//1.0
@SpringBootTest
class DemoApplicationTests {

//自动装配类
//如果有多个对象Dog,可以通过@Qualifier选择具体的对象
@Autowired
private Dog dog;
@Test
void contextLoads() {
System.out.println(dog);
}
}

//输出为:
Dog{name=‘旺财’, age=3}


```java
@SpringBootTest
class DemoApplicationTests {

  @Autowired
  private Person person;
  @Test
  void contextLoads() {
      System.out.println(person);
  }
}

//输出为:
Person{name='zhaoxiaoan', age=3, happy=true, birth=Thu Oct 22 00:00:00 CST 2020, maps={k1=v1, k2=v2}, lists=[code, music, study], dog=Dog{name='旺财', age=3}}

3.3 yaml-ConfigurationProperties与原properties-value比较图示:

image-20201022231250885

  • 功能:即yaml可以直接映射到对象而properties需要使用@Value一个一个赋值;

  • 松散绑定:即yaml中的last-name和类中的lastName是一样的,-后接的字母转为大写;

  • JSR303数据校验:可以在字段增加一层过滤验证,保证数据合法性;

  • 复杂类型封装:yml中可以封装对象,使用@Value就不支持;

  • JSR303数据校验(类似于html中input标签中选中的url、email等功能,可以自动校验输入):

    @Component
    //@PropertySource(value = "classpath:application.yaml")
    @ConfigurationProperties(prefix = "person")
    @Validated//开启数据校验
    public class Person {
        @Email//对email赋值开启Email数据校验,假设对name属性开启Email验证
        private String name;
        private Integer age;
        private Boolean happy;
        private Date birth;
        private Map<String,Object> maps;
        private List<Object> lists;
        private Dog dog;
    }
    
    • 注意,在SpringBoot2.3以后版本由于spring-boot-starter-web的依赖项已经去除了validate依赖,所以需要手动添加依赖才能生效:

      <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.17.Final</version>
            <scope>compile</scope>
       </dependency>
      
    • 再次测试则会得到报错结果:

    Description:
    
    Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'person' to com.kun.pojo.Person failed:
    
        Property: person.name
        Value: zhaoxiaoan
        Origin: class path resource [application.yaml]:2:9
        Reason: 不是一个合法的电子邮件地址
    
    • 修改name属性赋值即可;
    • JSR303校验注解类:

    img

    img

    • 小技巧:可以进入注解原文件查看各种注解值并自主修改;

4.yaml配置文件位置和多环境配置

4.1 配置文件

  1. file:./config/
  2. file:./
  3. classpath:/config/
  4. classpath:/
  • file即项目目录,classpath即src/main/resources目录;

  • 这既是yaml配置文件可存放的位置,也是其配置文件加载的优先级权重顺序,即按照权重覆盖相同属性及服务配置;

4.2 多环境配置

  • 现实开发中可能会有三种环境版本:

    • 普通环境:application.properties配置文件;
    • 测试环境:application-test.properties配置文件;
    • 开发环境:application-dev.properties配置文件;
  • yaml格式和properties格式配置环境对比:

    • 在properties文件格式下徐亚单独配置多个文件才能生效;

    • 而在yaml格式中则实现多文档模块,步骤更为简便:

      server:
        port: 8081
      
      # 通过`---`符号分割不同配置环境,并使用spring.profiles属性说明即可
      ---
      server:
        port: 8082
      spring:
        profiles: dev
      
      ---
      server:
        port: 8083
      spring:
        profiles: test
      

5.自动装配原理(重点)

@SpringBootApplication

5.1 原理

  • src/main/java/com/kun/XXXApplication.java程序入口文件@SpringBootApplication注解出发,依次查看父级文件,了解其自动装配原理:

    • @ComponentScan:其父级文件注解,用来实现扫描当前主启动类同级的包;
    • @SpringBootConfiguration——>@Configuration——>@Component:分别实现springboot配置、spring配置和基本组件;
    • @EnableAutoConfiguration:自动装配,核心包:
    >@AutoConfigurationPackage:自动配置包
    	->@Import({Registrar.class}):自动配置包注册
    ->@Import({AutoConfigurationImportSelector.class}):自动配置导入选择器
        ->getAutoConfigurationEntry():获得自动配置的实体入口
        ->getCandidateConfigurations():获取候选配置
        	->protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        		return EnableAutoConfiguration.class; //标注了EnableAutoConfiguration注解类的所有配置
    		}
        ->loadFactoryNames():获取所有的加载配置名字
            ->loadSpringFactories():加载所有的Spring工厂
    			->classLoader.getResources("META-INF/spring.factories"):加载项目资源
                ->ClassLoader.getSystemResources("META-INF/spring.factories"):加载系统资源
            	->META-INF/spring.factories:从该文件获取资源,自动装配的核心文件
    
  • META-INF/spring.factories文件:存在于External Libraries中

image-20201023160248610

  • 文件内容:
    image-20201023160458985

    • 所有已经配置好的依赖都在这里,其它只能自己配置;

    • 随便进入一个源文件(可能只是.class文件,根据提示下载源java文件查看):

      @ConditionalOnXXX //系列核心注解,其中每个文件都有,用来判断是否满足一系列条件才加载该文件
      
  • 结论一:SpringBoot所有自动装配都是在启动的时候扫描并加载的,其中所有的自动装配类都在spring.factories文件中,只有在pom.xml文件中添加了依赖才满足生效条件并且自动装配生效;

5.2 yaml文件与自动装配

  • yaml文件内能够重写的服务实质上和spring.factories文件相关:

    @EnableConfigurationProperties //某些自动装配文件中含有此注解,即标注可以在properties配置文件中重写属性值
    
    • 在构造器类中:
    //举例如下:
    public HttpEncodingAutoConfiguration(ServerProperties properties) {
    		this.properties = properties.getServlet().getEncoding();
    	}
    //其中ServerProperties文件中的属性即与yaml配置文件绑定,可以重写配置
    
    • ServerProperties:
    @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
    //该注解中prefix值表示yaml文件中重写配置该类属性的前缀
    
    • 同样可以从yaml文件中根据配置属性返回到上级XXXProperties文件查看所有同类属性;
  • 结论二:springfactories中定义好的自动装配类XXXAutoConfiguration加载XXXProperties文件,而XXXProperties文件则与配置文件.properties/.yaml一一绑定,即可通过.yaml配置文件修改配置并被加载;

  • 开启Debug,查看具体哪些配置类被加载:

    # 在application.yaml文件中开启Spring调试类
    debug: true
    
    • 测试结果:
    Positive matches: 已经启用生效的类
    Negative matches: 没有开启生效的类
    Unconditional classes: 没有条件的类
    

5.3 SpringApplication.run启动

  • src/main/java/com/kun/XXXApplication.java文件中:

    SpringApplication.run(DemoApplication.class, args);
    
    • 该方法主要分两部分:

      • SpringApplication实例化;
      • run方法执行;
    • 做了四项工作:

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

开启Debug,查看具体哪些配置类被加载:

# 在application.yaml文件中开启Spring调试类
debug: true
  • 测试结果:
Positive matches: 已经启用生效的类
Negative matches: 没有开启生效的类
Unconditional classes: 没有条件的类

5.3 SpringApplication.run启动

  • src/main/java/com/kun/XXXApplication.java文件中:

    SpringApplication.run(DemoApplication.class, args);
    
    • 该方法主要分两部分:

      • SpringApplication实例化;
      • run方法执行;
    • 做了四项工作:

      • 判断该应用类型是普通java项目还是Web项目;
      • 查找并加载所有可用初始化器,设置到initializers属性中;
      • 找出所有的应用程序监听器,设置到listeners属性中;
      • 推断并设置main方法的定义类,找到运行的主类;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值