7--SpringBoot-后端开发、原理

SpringBoot原理

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

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

  1. 在pom.xml中依赖配置比较繁琐,在项目开发时,需要自己去找到对应的依赖,还需要找到依赖它所配套的依赖以及对应版本,否则就会出现版本冲突问题。
  1. 在使用Spring框架进行项目开发时,需要在Spring的配置文件中做大量的配置,这就造成Spring框架入门难度较大,学习成本较高。
    SpringBoot 框架底层提供了两个非常重要的功能:一个是起步依赖 ,一个是自动配置

1.通过SpringBoot所提供的起步依赖,就可以大大的简化pom文件当中依赖的配置,从而解决了Spring框架当中依赖配置繁琐的问题。

2.通过自动配置的功能就可以大大的简化框架在使用时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对象,然后我们却可以通过@Autowired从Spring容器中注入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容器中)
    方案一:
java 复制代码
@SpringBootApplication
@ComponentScan({"com.itheima","com.example"}) //指定要扫描的包
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
}

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

缺点:

  1. 使用繁琐
  1. 性能低
    不推荐使用
    方案二
    @Import 导入

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

  1. 导入普通类

  2. 导入配置类

  3. 导入ImportSelector接口实现类

1.导入普通类

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

2.导入配置类

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

3.接口实现类

java 复制代码
public class MyImportSelector implements ImportSelector {//接口实现类
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//返回值字符串数组(数组中封装了全限定名称的类)
return new String[]{"com.example.HeaderConfig"};
}
}
java 复制代码
@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注解

配置优先级

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)

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

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

java 复制代码
@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 (单例)

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

测试二

java 复制代码
@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时, 通常会单独定义一个配置类

java 复制代码
@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对象。

相关推荐
xmh-sxh-131413 分钟前
jdk各个版本介绍
java
天天扭码32 分钟前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶32 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺37 分钟前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序44 分钟前
vue3 封装request请求
java·前端·typescript·vue
陈王卜1 小时前
django+boostrap实现发布博客权限控制
java·前端·django
小码的头发丝、1 小时前
Spring Boot 注解
java·spring boot
午觉千万别睡过1 小时前
RuoYI分页不准确问题解决
spring boot
java亮小白19971 小时前
Spring循环依赖如何解决的?
java·后端·spring
飞滕人生TYF1 小时前
java Queue 详解
java·队列