Java SpringBoot的相关知识点详解

目录
  • 1. IOC和DI
  • 2. Spring容器加载Bean/创建对象的时机
  • 3. @Autowired注解
  • 4. @Configuration配置类
  • 5. @Conditional条件注解
  • 6. SpringBoot的自动配置/自动装配
  • 总结

1. IOC和DI

首先,我们应该明确,IOC是一种思想,并不是Spring特有的,而是软件工程逐步发展的一种产物,是一种优秀的编程思想,之所以我们经常会把IOC理解成是Spring特有的东西,是因为Spring框架可以帮助我们很好的去实现IOC。IOC代表的是控制反转,控制的是什么?反转的是什么?控制的是一个对象的创建、初始化和销毁,没有使用IOC之前,我们使用一个对象,会主动的去创建对象,也就是在需要使用这个对象的地方去执行 A a = new A(); 类似这种语句,而使用了IOC之后,会把系统中所有需要使用到的对象交给IOC容器去托管,当我们的程序中需要使用到某个对象时,也不是我们直接去容器获取这个对象,而是容器会主动的给我们这个对象,也就是说IOC容器会自动给程序中需要对象的地方给你注入对象,这就是反转,把获取对象的行为由主动变为被动,并且把控制权交给了容器。

DI代表的是依赖注入,什么是依赖注入?我们都知道,对象与对象之间一般都会有依赖关系的,例如对象A依赖于对象B,对象B又依赖于对象C,举个例子,对象A中有个方法a,a方法的实现需要调用B对象的b方法,这就是依赖,引入IOC之前,我们会在A对象中new一个B对象,再通过B对象去调用b方法;引入IOC之后,我们都不会去主动创建对象了,都交给IOC容器去处理了,我们只需要在对象A中声明一个B对象的成员变量,加上xml配置或者相关注解,IOC容器就可以我们自动实现注入。例如下面这段代码,在MVC架构中,Controller层依赖Service层,我们只需要在Controller层声明一个Service层的变量,并加上@Autowired注解,当IOC容器启动时加载ApplicationController这个Bean到容器中时,会自动把ApplicationService这个Bean也注入进来。

依赖注入的实现方式有三种:构造函数注入、set方法注入以及接口注入;接口注入用的比较少,一般都是使用构造函数注入和set方法注入,另外还有一种字段注入,如上图所示的注入方式就是字段注入,这种注入方式不是规范的,可以看到@Autowired注解会给出警告,不建议我们使用这种方式,但这种方式却是使用最多的,因为它很方便。

以下是构造函数注入:

以下是set方法注入:

2. Spring容器加载Bean/创建对象的时机

默认情况下,程序启动的时候,Spring就会把程序中需要用到的Bean加载到IOC容器中,也就是会一次性创建很多的对象到IOC容器中。当然,还有一种方式,就是当需要使用到某个Bean的时候,再去创建这个Bean到容器中,这就是延迟加载,或者叫延迟实例化。

如果我们希望某个Bean不要过早的被加载到容器中,使用到的时候再去创建,可以给这个Bean加上@Lazy注解。

关于@Lazy注解实现延迟加载,需要注意一个细节,我们给某个Bean加上@Lazy注解之后,并不一定就能实现延迟加载,有可能程序在启动的时候,这个Bean还是会在一开始就被创建,会产生这种情况是因为这个Bean有可能在别处被引用到,也就是说别的Bean可能依赖了这个Bean,而依赖的这个Bean又没有打上@Lazy注解,那么程序启动的时候,创建这个依赖的Bean,也会把它所依赖的Bean一并注入,这就是导致@Lazy注解有时没有生效的原因。

举个例子,ApplicationController这个Bean依赖了ApplicationServiceImpl,我们只给ApplicationServiceImpl这个Bean加上@Lazy注解,是无法实现延迟加载的,需要ApplicationController这个Bean也加上@Lazy注解。

3. @Autowired注解

@Autowired注解的作用就是实现依赖注入,大部分情况下,我们使用@Autowired这个注解就可以满足我们的需求了,但是我们需要知道这个注解的约定是什么,才能更好的使用它。首先,@Autowired注解实现的是按照类型注入,补充一个点:为了满足ocp原则,使得代码更加灵活便于扩展,我们倡导面向接口编程。例如下面这个例子,ApplicationService是一个接口,我们加上了@Autowired注解,按照类型注入的原则,IOC容器会去找ApplicationService接口的实现类去进行依赖注入,如果这个接口只有一个实现类,那么没有问题,可以实现注入,如果这个接口有多个实现类,那么IOC容器会知道给我们注入哪一个实现类吗,显然是不知道的,但是@Autowired还有一种规则,就是根据类型匹配时,如果能匹配多个,会再根据Bean的名称去匹配,如果Bean的名称能匹配上,那么没有问题,可以实现注入;如果Bean的名称匹配不上,程序会报错,因为IOC容器不知道给我们注入哪一个ApplicationService接口的实现类。

举个例子,假设现在ApplicationService接口有两个实现类ApplicationServiceImpl1(Bean名称:applicationServiceImpl1)和ApplicationServiceImpl2(Bean名称:applicationServiceImpl2),如果@Autowired注解作用的代码是private ApplicationService applicationServiceImpl1;,那么注入的是ApplicationServiceImpl1这个Bean,如果@Autowired注解作用的代码是private ApplicationService applicationServiceImpl2;,那么注入的是ApplicationServiceImpl2这个Bean,如果@Autowired注解作用的代码是private ApplicationService applicationServiceImpl;,那么程序报错,IOC容器知道为我们注入哪个Bean。

如果涉及一个接口有多个实现类的情况,我们建议使用@Autowired注解搭配@Qualifier注解,@Qualifier注解的实现机制是按照Bean的名称进行注入。

例如下面这个例子,首先@Autowired注解会根据类型找到ApplicationService的实现类,@Qualifier注解再找到名称为applicationServiceImpl的Bean进行注入。

PS:上面我们讲的是@Autowired注解如果匹配到多个Bean不知道注入哪一个的时候会报错,还有一种情况,如果@Autowired注解匹配不到任何对应的Bean也会报错。

4. @Configuration配置类

一个类被加上了@Configuration注解,就表明这个类是一个配置类,@Configuration注解底层注解是@Component,也就是说,注解类也会被加载到IOC容器中,在注解类中,通常会声明很多方法,这些方法的返回值是一个对象,并且方法加上了@Bean注解,这表明会将这些方法返回的对象加载到IOC容器中。例如:

@Configuration注解是用来替换Bean的xml配置,可以把@Configuration看作标签,把@Bean注解看作标签

传统的xml配置是这样的:

<beans>    <bean id = "people", class = "com.test.People">    </bean>    <bean id = "student", class = "com.test.Student">    </bean></beans>

思考一个问题:一般来说,把一个Bean加载到IOC容器中,不是通过@Component注解就可以实现吗?况且@Configuration注解的底层注解还是@Component,那为什么还需要@Configuation+@Bean这套注解来加载某些Bean到IOC容器中呢?换言之,@Configuation+@Bean的真正作用是什么?

@Configuation+@Bean的作用就是可以将一些定制化的Bean(特殊的Bean)注入到IOC容器中,什么是定制化的Bean?举个例子,有一个People类,有两个属性name和age,我们希望把People类加载到IOC容器中,并且使得IOC容器的这个Bean的name属性值是小明,age属性值是18。如果只是在People类上加@Component注解,是无法实现我们这个定制化的Bean的,因为IOC容器在启动的时候,创建Bean,默认调用的都是某个类的无参构造函数(也存在调用带参构造函数的情况,但是这种情况使用带参构造函数,只是为了实现依赖注入,也就是构造函数注入,并非是给属性赋值),也就是说无法给我们的属性赋特殊的值,而使用@Configuation+@Bean就可以实现。例如:

通常来说,我们不会直接把属性值写死在代码里,而是通过读取配置文件的形式,虽然说@Configuration注解表明这个类已经是一个配置类了,可以充当配置文件来使用,但是对于一些变化的属性,我们都会定义在普通配置文件里面,例如application.properties。

5. @Conditional条件注解

@Conditional注解的作用是满足某个条件时,才会将这个Bean注入到IOC容器中。我们可以通过自定义一个Condition类的方式定制某个规则,当满足这个规则才会注入Bean,例如:

通常,我们直接使用一些成品条件注解就可以满足我们的需求了。常用成品条件注解如下:

6. SpringBoot的自动配置/自动装配

自动装配是SpringBoot最核心的东西,学习自动装配,我们首先应该了解自动装配是什么,做了哪些事情?其次需要明确自动装配存在的意义,也就是说自动装配的好处是什么?最后再去了解自动装配的原理。按照这个流程下来,才能更好的掌握自动装配这个知识点。

a. 自动装配做了什么事情? 就是SpringBoot会自动把一些第三方的库或者SDK需要使用到的很多Bean都自动帮我们加载到IOC容器中。

b. 自动装配的好处是什么? 基于IOC思想,任何程序中使用到的Bean都需要注入IOC容器中进行托管,也就是说,我们引用一些第三方的库/依赖,例如Mongodb、Redis、Hadoop,也是需要把这些第三方的库涉及的Bean都加载到IOC容器中的。如果没有自动装配,那么如何把第三方的库里面的很多Bean都加载到我们的IOC容器中来,给每一个相关的类打上@Component注解?不是这样的,我们所引用的第三方库一般都是以jar包的形式存在,并不是直接给源码。即便是可以通过打上@Component注解的方式,试想我们的工作量会增加多少,引用一个第三方库可能涉及很多的Bean,并且有些Bean又可能是比较复杂的,我们不可能手动的将他们一个个注入容器,而SpringBoot都帮我们做好了,这就是自动装配的好处。

c. 自动装配的原理

首先,在SpringBoot程序的主启动类上,有一个非常重要的注解:@SpringBootApplication,进入到这个注解,可以发现底层由三个注解组成(元注解除外)

@SpringBootConfiguration:表明SpringBoot程序的主启动类也是一个配置类

@ComponentScan:指定包扫描路径,程序启动时,会根据指定的包扫描路径去加载Bean

@EnableAutoConfiguration:最重要的一个注解,我们可以理解成这个注解的作用是开启自动装配

进入到@EnableAutoConfiguration,可以发现底层由两个注解组成(元注解除外)

我们主要研究@Import注解,这个注解有两种实现方式,第一种是指定一个或多个配置类,例如:@Import(TetsConfiguration.class) 那么IOC容器就会将这个配置类加载到容器中来,另一种实现方式是指定一个ImportSelector类的子类,例如@Import(AutoConfigurationImportSelector.class) 这个ImportSelector类的子类会去实现selectImports方法,该方法的返回值是一个字符串数组,代表要加载的配置类名称列表。

SpringBoot自动装配默认使用第二种方式,我们进到AutoConfigurationImportSelector这个类里面,发现它确实实现了selectImports方法。通过这个方法,SpringBoot就可以知道我们需要自动装配哪些配置类

我们再进入getAutoConfigurationEntry方法,这个方法里面有一个核心方法getCandidateConfigurations,翻译过来就是获取候选的配置类

getCandidateConfigurations方法实现逻辑就是:会去读取某一个配置文件,根据这个配置文件的值返回自动装配要装配的配置类名称列表

我们进入到SpringFactoriesLoader类,可以知道getCandidateConfigurations读取的配置文件就是META-INF下面的spring.factories

spring.factories的位置

spring.factories配置文件主要就声明了很多自动配置类的名称,截取部分如下:

总结一下,我们一路追踪源码下来,无非确定了一件事,SpringBoot自动装配时装配了哪些配置类,这些配置类的定义都存在于spring.factories配置文件中。

另外,我们需要明确,SpringBoot自动装配时也不是把所有自动配置类定义的Bean都加载到IOC容器中,因为这些Bean大部分都会加上条件注解,需要满足一定的条件才会被加载,例如,我们进入某一个自动配置类看一下

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • SpringBoot整合Mybatis的知识点汇总

    springboots使用的版本是2.0.1,注意不同版本可能有差异,并不一定通用 添加Mybatis的起步依赖: <!--mybatis起步依赖--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version&

  • SpringBoot事件机制相关知识点汇总

    要"监听"事件,我们总是可以将"监听器"作为事件源中的另一个方法写入事件,但这将使事件源与监听器的逻辑紧密耦合. 对于实际事件,我们比直接方法调用更灵活.我们可以根据需要动态注册和注销某些事件的侦听器.我们还可以为同一事件设置多个侦听器. 本教程概述了如何发布和侦听自定义事件,并解释了 Spring Boot 的内置事件. 为什么我应该使用事件而不是直接方法调用? 事件和直接方法调用都适合于不同的情况.使用方法调用,就像断言一样-无论发送和接收模块的状态如何,他们都

  • SpringBoot使用Log4j的知识点整理

    log4j.logback.Log4j2简介 log4j是apache实现的一个开源日志组件 logback同样是由log4j的作者设计完成的,拥有更好的特性,用来取代log4j的一个日志框架,是slf4j的原生实现 Log4j2是log4j 1.x和logback的改进版,采用了一些新技术(无锁异步.等等),使得日志的吞吐量.性能比log4j 1.x提高10倍,并解决了一些死锁的bug,而且配置更加简单灵活 slf4j+log4j和直接用log4j的区别 slf4j是对所有日志框架制定的一种规

  • springboot2.x整合redis知识点讲解

    pom文件 <!--springboot中的redis依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 配置 # Redis数据库索引(默认为0) spring.redis.database=0 # Redis

  • springboot热部署知识点总结

    spring cloud我想做成一个系列,所以spring cloud+eureka后面会慢慢说到的,有兴趣的小伙伴可以关注后续! 这一节就简单说说springboot的热部署了(我一直想不通为什么叫做热部署,看到这名字就吓退了我继续学习的欲望!),但是实际上可以把这个看成是一个小技巧. 就是导入一个依赖,要用的时候,就是快捷键操作:Ctrl+F9 有什么用呢?就是避免你每次对springboot修改一点东西,就要重新启动springboot应用,贼麻烦!而且对于电脑性能不怎么样的小伙伴来说(咳

  • Java SpringBoot的相关知识点详解

    目录 1. IOC和DI 2. Spring容器加载Bean/创建对象的时机 3. @Autowired注解 4. @Configuration配置类 5. @Conditional条件注解 6. SpringBoot的自动配置/自动装配 总结 1. IOC和DI 首先,我们应该明确,IOC是一种思想,并不是Spring特有的,而是软件工程逐步发展的一种产物,是一种优秀的编程思想,之所以我们经常会把IOC理解成是Spring特有的东西,是因为Spring框架可以帮助我们很好的去实现IOC.IOC

  • Java Springboot websocket使用案例详解

    什么是WebSocket WebSocket是一种在单个TCP连接上进行全双工通信的协议 - 为什么要实现握手监控管理 如果说,连接随意创建,不管的话,会存在错误,broken pipe 表面看单纯报错,并没什么功能缺陷等,但实际,请求数增加,容易导致系统奔溃.这边画重点. 出现原因有很多种,目前我这边出现的原因,是因为客户端已关闭连接,服务端还持续推送导致. 如何使用 下面将使用springboot集成的webSocket 导入Maven 首先SpringBoot版本 <parent> &l

  • Java SpringBoot Validation用法案例详解

    目录 constraints分类 对象集成constraints示例 SpringBoot集成自动验证 集成maven依赖 验证RequestBody.Form对象参数 验证简单参数 验证指定分组 全局controller验证异常处理 自定义constraints @DateFormat @PhoneNo 使用自定义constraint注解 问题 提到输入参数的基本验证(非空.长度.大小.格式-),在以前我们还是通过手写代码,各种if.else.StringUtils.isEmpty.Colle

  • Java SpringBoot自动装配原理详解及源码注释

    目录 一.pom.xml文件 1.父依赖 2.启动器: 二.主程序: 剖析源码注解: 三.结论: 一.pom.xml文件 1.父依赖 主要是依赖一个父项目,管理项目的资源过滤以及插件! 资源过滤已经配置好了,无需再自己配置 在pom.xml中有个父依赖:spring-boot-dependencies是SpringBoot的版本控制中心! 因为有这些版本仓库,我们在写或者引入一些springboot依赖的时候,不需要指定版本! 2.启动器: 启动器也就是Springboot的启动场景; 比如sp

  • R语言中因子相关知识点详解

    因子是用于对数据进行分类并将其存储为级别的数据对象. 它们可以存储字符串和整数. 它们在具有有限数量的唯一值的列中很有用. 像"男性","女性"和True,False等.它们在统计建模的数据分析中很有用. 使用factor()函数通过将向量作为输入创建因子. 例 # Create a vector as input. data <- c("East","West","East","North

  • 基于java Springboot实现教务管理系统详解

    目录 视频演示 研究背景 我国教务现状与反思 主要技术和环境: 功能截图: 总结: 视频演示 研究背景 在当今信息社会发展中中,计算机科学的飞速发展,大多数学校开始注意办公效率的发展是很关键,对学校的管理起到举足轻重的作用.基于 Internet 网络的信息服务,快速成长为现代学校中一项不可或缺的内容措施.很多校园都已经不满意商务办公管理的缓慢成长方式.学院的需求是一个功能强大的,能提供完善管理,管理信息系统的速度.社会持续向前发展,尤其是大多地方普及计算机,计算机应用已经开始向大容量的数据存储

  • 四种引用类型在JAVA Springboot中的使用详解

    目录 概念介绍 01.  强引用 02.  软引用 03.  弱引用 04.  虚引用 对象可达性 Springboot源码中的使用 总结 概念介绍 不同的引用类型,主要体现的是对象不同的可达性(reachable)状态和对垃圾收集的影响. 01.  强引用 这个就是我们创建的普通对象了~ 当该对象被显示地赋值为 null 时,或者没有被其他存活的对象继续引用时,它就会成为垃圾收集器的目标,等待被收回 02.  软引用 软引用( SoftReference ) , 当内存不足 时会被回收 比如

  • Java SpringBoot+vue+实战项目详解

    目录 1.<锋迷商城>业务流程设计-接⼝规范 1.1 前后端分离与单体架构流程实现的区别 1.1.1单体架构 1.1.2 前后端分离架构 1.2 接口介绍 1.2.1接口概念 1.2.2接口规范 1.3 Swagger 1.3.1作用 1.3.2 Swagger整合 1.3.3 Swagger注解说明 1.3.4 Swagger-ui 插件 1.4 RESTful 总结 1.<锋迷商城>业务流程设计-接⼝规范 在企业项⽬开发中,当完成项⽬的需求分析.功能分析.数据库分析与设计之后,

  • 四种引用类型在JAVA Springboot中的使用详解

    目录 概念介绍 01.  强引用 02.  软引用 03.  弱引用 04.  虚引用 对象可达性 Springboot源码中的使用 总结 概念介绍 不同的引用类型,主要体现的是对象不同的可达性(reachable)状态和对垃圾收集的影响. 01.  强引用 这个就是我们创建的普通对象了~ 当该对象被显示地赋值为 null 时,或者没有被其他存活的对象继续引用时,它就会成为垃圾收集器的目标,等待被收回 02.  软引用 软引用( SoftReference ) , 当内存不足 时会被回收 比如

  • Java中流的有关知识点详解

    什么是流? 流:程序和设备之间连接起来的一根用于数据传输的管道,流就是一根管道. 流的分类: 四大基本抽象流(输入流,输出流,字符流,字节流) 文件流 缓冲流 转换流 数据流     流一定是类,但类不一定是流 print流 object流 按数据流的方向不同可以分为输入流和输出流. 按处理数据单位不同可以分为字节流和字符流.(一个字符是两个字节) 按功能不同可以分为节点(原始)流和处理(包裹)流. 字节流         字符流 输入流      InputStream      Reader

随机推荐