当前位置: 首页 > article >正文

7--SpringBoot-后端开发、原理详解(面试高频提问点)

目录

SpringBoot原理

起步依赖

自动配置

配置优先级

Bean设置

获取Bean

第三方Bean 


SpringBoot原理

内容偏向于底层的原理分析

基于Spring框架进行项目的开发有两个不足的地方:

  1. pom.xml中依赖配置比较繁琐,在项目开发时,需要自己去找到对应的依赖,还需要找到依赖它所配套的依赖以及对应版本,否则就会出现版本冲突问题。
  2. 在使用Spring框架进行项目开发时,需要在Spring的配置文件中做大量的配置,这就造成Spring框架入门难度较大,学习成本较高。
SpringBoot 框架底层提供了两个非常重要的功能:一个是起步依赖,一个是自动配置
  1. 通过SpringBoot所提供的起步依赖,就可以大大的简化pom文件当中依赖的配置,从而解决了Spring框架当中依赖配置繁琐的问题。
  1. 通过自动配置的功能就可以大大的简化框架在使用时bean的声明以及bean的配置。我们只需要引入程序开发时所需要的起步依赖,项目开发时所用到常见的配置都已经有了,我们直接使用就可以了。

起步依赖

起步依赖的原理就是Maven的依赖传递。

如果使用了SpringBoot,就不需要繁琐的引入依赖了。只需要引入一个依赖就可以了,那就是web开发的起步依赖:springboot-starter-web

问题:为什么只需要引入一个web开发的起步依赖,web开发所需要的所有的依赖都有了呢?

答案:因为Maven的依赖传递

在SpringBoot提供的这些起步依赖当中,已提供了当前程序开发所需要的所有的常见依赖(官网地址:https://docs.spring.io/spring-boot/docs/2.7.7/reference/htmlsingle/#using.build-systems.starters)。

比如:springboot-starter-web,这是web开发的起步依赖,在web开发的起步依赖当中,就 集成了web开发中常见的依赖:json、web、webmvc、tomcat等。只需要引入这一个起步依赖,其他的依赖都会自动的通过Maven的依赖传递进来。

自动配置

SpringBoot的自动配置就是当Spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中, 不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。

比如:我们要进行事务管理、要进行AOP程序的开发,此时就不需要我们再去手动的声明这些bean对象了,我们直接使用就可以从而大大的简化程序的开发,省去了繁琐的配置操作。

在CommonConfig配置类上添加了一个注解@Configuration,而@Configuration底层就是@Component,所以配置类CommonConfig最终也是SpringIOC容器当中的一个bean对象

  • 问题:在当前项目中我们并没有声明谷歌提供的Gson这么一个bean对象,然后我们却可以通过@AutowiredSpring容器中注入bean对象,那么这个bean对象怎么来的?
  • 答案SpringBoot项目在启动时通过自动配置完成了bean对象的创建。
  • 问题:当前包:com.itheima, 第三方依赖中提供的包:com.example,此时引入进来的第三方依赖当中的bean以及配置类为什么没有生效?

  • 答案:在类上添加@Component注解来声明bean对象时,还需要保证@Component注解能被Spring的组件扫描到。

  • SpringBoot项目中的@SpringBootApplication注解,具有包扫描的作用,但是它只会扫描启动类所在的当前包以及子包。

  • 当前包:com.itheima, 第三方依赖中提供的包:com.example(扫描不到)

  • 解决:
  • 方案1@ComponentScan 组件扫描,指定要扫描的包
  • 方案2@Import 导入(使用@Import导入的类会被Spring加载到IOC容器中)
方案一:
@SpringBootApplication
@ComponentScan({"com.itheima","com.example"}) //指定要扫描的包
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
}

进行项目开发时,当需要引入大量的第三方的依赖,就需要在启动类上配置N多要扫描的包,这种方式会很繁琐。而且这种大面积的扫描性能也比较低。

缺点:

1. 使用繁琐

2. 性能低

不推荐使用
方案二
@Import 导入

导入形式主要有以下几种:

1. 导入普通类

2. 导入配置类

3. 导入ImportSelector接口实现类

1.导入普通类 

@Import(TokenParser.class) //导入的类会被Spring加载到IOC容器中
@SpringBootApplication
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
}

2.导入配置类

@Configuration
public class HeaderConfig {//配置类
@Bean
public HeaderParser headerParser(){
return new HeaderParser();
}
@Bean
public HeaderGenerator headerGenerator(){
return new HeaderGenerator();
}
}
@Import(HeaderConfig.class) //导入配置类
@SpringBootApplication
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
}

3.接口实现类

public class MyImportSelector implements ImportSelector {//接口实现类
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//返回值字符串数组(数组中封装了全限定名称的类)
return new String[]{"com.example.HeaderConfig"};
}
}
@Import(MyImportSelector.class) //导入ImportSelector接口实现类
@SpringBootApplication
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
}

问题:如果基于以上方式完成自动配置,当要引入一个第三方依赖时,是不是还要知道第三方依赖中有哪些配置类和哪些Bean对象?

答案:是的。 (对程序员来讲,很不友好,而且比较繁琐)

问题:当我们要使用第三方依赖,依赖中到底有哪些bean和配置类,谁最清楚?

答案:第三方依赖自身最清楚。

结论:我们不用自己指定要导入哪些bean对象和配置类了,让第三方依赖它自己来指定。 

问题:怎么让第三方依赖自己指定bean对象和配置类?

答案:比较常见的方案就是第三方依赖提供一个注解,这个注解一般都以@EnableXxxx开头的注解,注解中封装的就是@Import注解

4.使用第三方依赖提供的 @EnableXxxxx注解(SpringBoot当中所采用的方式)

第三方依赖中提供的注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)//指定要导入哪些bean对象或配置类
public @interface EnableHeaderConfig {
}
在使用时只需在启动类上加上 @EnableXxxxx 注解即可
@EnableHeaderConfig //使用第三方依赖提供的Enable开头的注解
@SpringBootApplication
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
}

配置优先级

SpringBoot 项目当中支持的三类配置文件:
  • application.properties
  • application.yml
  • application.yaml

配置文件优先级排名(从高到低):

1. properties配置文件

2. yml配置文件

3. yaml配置文件

SpringBoot项目当中除了以上3种配置文件外,SpringBoot为了增强程序的扩展性,除了支持配置文件的配置方式以外,还支持另外两种常见的配置方式:

1. Java系统属性配置 (格式: -Dkey=value

-Dserver.port=9000

2. 命令行参数 (格式:--key=value

--server.port=10010

优先级: 命令行参数 > 系统属性参数 > properties参数 > yml参数 > yaml参数

项目打包

点击右侧Maven中的package进行打包

显示打包完成

找到jar包的文件目录:

在当前目录下输入cmd回车,即可在当前目录下打开命令行

通过指令

  • java -Dserver.port=9000 -jar tlias-0.0.1-SNAPSHOT.jar 
  • java -jar tlias-0.0.1-SNAPSHOT.jar --server.port=9000
  • java -Dserver.port=9000 -jar tlias-0.0.1-SNAPSHOT.jar --server.port=10010

以上三种方式可更改端口号,第三种端口号改为10010,因为命令行参数优先级高于java系统属性

通过ctrl c可结束操作

优先级顺序,从高到低:

  • 命令行参数(--xxx=xxx

  • java系统属性(-Dxxx=xxx

  • application.properties

  • application.yml

  • application.yaml(忽略)

Bean设置

通过Spring当中提供的注解@Component以及它的三个衍生注解(@Controller@Service@Repository)来声明IOC容器中的bean对象,为应用程序注入运行时所需要依赖的bean对象,也就是依赖注入DI

获取Bean

默认情况下,SpringBoot项目在启动的时候会自动的创建IOC容器(也称为Spring容器),并且在启动的过 程当中会自动的将bean对象都创建好,存放在IOC容器当中。应用程序在运行时需要依赖什么bean对 象,就直接进行依赖注入就可以了。

Spring容器中提供了一些方法,可以主动从IOC容器中获取到bean对象,下面介绍3种常用方式:

1. 根据name获取bean

Object getBean(String name)

2. 根据类型获取bean

<T> T getBean(Class<T> requiredType)

3. 根据name获取bean(带类型转换)

<T> T getBean(String name, Class<T> requiredType)

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {
@Autowired
private ApplicationContext applicationContext; //IOC容器对象
//获取bean对象
@Test
public void testGetBean(){
//根据bean的名称获取
DeptController bean1 = (DeptController)
applicationContext.getBean("deptController");
System.out.println(bean1);
//根据bean的类型获取
DeptController bean2 = applicationContext.getBean(DeptController.class);
System.out.println(bean2);
//根据bean的名称 及 类型获取
DeptController bean3 = applicationContext.getBean("deptController",
DeptController.class);
System.out.println(bean3);
}
}

默认bean对象是单例模式(只有一个实例对象)。那么如何设置bean对象为非单例呢?需要设置bean的作用域。

作用域说明
singleton
容器内同名称的 bean 只有一个实例(单例)(默认)
prototype
每次使用该 bean 时会创建新的实例(非单例)
request
每个请求范围内会创建新的实例( web 环境中,了解)
session
每个会话范围内会创建新的实例( web 环境中,了解)
application
每个应用范围内会创建新的实例( web 环境中,了解)

借助Spring中的@Scope注解来配置Bean的作用域

测试一

默认bean的作用域为:singleton (单例)

@Lazy //延迟加载(第一次使用bean对象时,才会创建bean对象并交给ioc容器管理)
@RestController
@RequestMapping("/depts")
public class DeptController {
@Autowired
private DeptService deptService;
public DeptController(){
System.out.println("DeptController constructor ....");
}
//省略其他代码...
}

测试二

@Scope("prototype") //bean作用域为非单例
@Lazy //延迟加载
@RestController
@RequestMapping("/depts")
public class DeptController {
@Autowired
private DeptService deptService;
public DeptController(){
System.out.println("DeptController constructor ....");
}
//省略其他代码...
}

第三方Bean 

要从IOC容器当中来获取到bean对象,需要先拿到IOC容器对象,怎么样才能拿到IOC容器呢?

想获取到IOC容器,直接将IOC容器对象注入进来就可以了

在配置类中定义@Bean标识的方法

如果需要定义第三方Bean时, 通常会单独定义一个配置类

@Configuration //配置类 (在配置类当中对第三方bean进行集中的配置管理)
public class CommonConfig {
//声明第三方bean
@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean
//通过@Bean注解的name/value属性指定bean名称, 如果未指定, 默认是方法名
public SAXReader reader(DeptService deptService){
System.out.println(deptService);
return new SAXReader();
}
}

如果是在项目当中我们自己定义的类,想将这些类交给IOC容器管理,我们直接使用@Component 以及它的衍生注解来声明就可以。

如果这个类它不是我们自己定义的,而是引入的第三方依赖当中提供的类,而且我们还想将这个类 交给IOC容器管理。此时我们就需要在配置类中定义一个方法,在方法上加上一个@Bean注解,通过这种方式来声明第三方的bean对象。

注解:8--SpringBoot原理分析、注解-详解(面试高频提问点)-CSDN博客


http://www.kler.cn/news/312444.html

相关文章:

  • Web开发:ABP框架3——入门级别的接口增删改查实现原理
  • 基于SpringBoot的自习室预订系统
  • 莱卡相机sd内存卡格式化了怎么恢复数据
  • Volta无障碍的 JavaScript 工具管理器
  • Java 中使用 Redis 的几种方式优缺点对比
  • Linux 生成 git ssh 公钥
  • 站群服务器适用于哪些场景当中?
  • Linux服务器及应用环境快速部署、调试、迁移、维护、监控
  • Jenkins怎么设置每日自动执行构建任务?
  • 使用 nvm 管理 node 版本:如何在 macOS 和 Windows 上安装使用nvm
  • UniApp如何打包成客户端应用程序
  • 前后端分离集成CAS单点登录
  • Windows安装HeidiSQL教程(图文)
  • python中装饰器的作用
  • Autosar学习----AUTOSAR_SWS_BSWGeneral(六)
  • 基于协同过滤算法+PHP的新闻推荐系统
  • 无人机维修保养一对一教学技术详解
  • LaTex2024 下载安装运行HelloWorld—全流程笔记
  • 【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
  • QT 修改全局鼠标光标样式并支持还原样式
  • 如何在多台Linux虚拟机上安装和配置Zookeeper集群
  • uboot:源码分析-启动第一阶段-start.S解析
  • brpc的简单使用
  • 力扣 11.盛最多水的容器
  • 重修设计模式-结构型-桥接模式
  • Python编码系列—Python组合模式:构建灵活的对象组合
  • Suno新上线Covers翻唱新 - 实现音频风格任意转换
  • Spring Boot-跨服务事务管理问题
  • DNS解析流程
  • 系统架构-面向对象