Always keep|

奕帆卷卷

园龄:1年4个月粉丝:3关注:0

SpringBoot原理

配置

  • SpringBoot中支持三种格式的配置文件

.properties

.yml

.yaml

虽然Springboot支持多种文件配置,但是通常在项目开发中,我们一般推荐使用yml文件配置

优先级

在SpringBoot项目中,常见的属性配置有5种,3种配置文件加上两种外部的配置,生效优先级

  • SrpingBoot配置优先级(低 -> 高):

1.application.yaml(忽略)

2.application.yml

3.application.properties

4.java系统属性(-Dxxx=xxx)

5.命令行参数(--xxx=xxx)

Bean管理

获取Bean

默认情况下,Springboot项目在启动的时候会自动创建IOC容器,并在创建好的bean对象存放在IOC容器当中,以供应用程序直接进行依赖注入

我们有三种方式可以从IOC容器中获取Bean

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

我们要先拿到IOC容器对象,才能获取bean对象

我们直接将IOC容器对象注入进来就可以

测试类:

@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对象地址值是一样的,这说明IOC容器中的bean对象只有一个

Bean作用域

在IOC容器中,默认bean对象是单例模式,也就是上面案例输出的bean对象地址值相同,即容器中同名称的bean只有一个实例

在Spring中支持五种作用域,后三种在Web环境中才生效

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

在IOC容器中默认是单例模式,我们可以通过Spring中的@Scope注解来进行配置作用域

@Scope("prototype")

IOC容器中的bean在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)

第三方Bean

我们在项目中自己定义的类,如果我们要声明这些bean,我们只需要在类上加上@Component以及它的三个衍生注解@Controller,@Service,@Repository.就可以来声明这个bean对象

但是如果在项目开发中,有类不是我们自己编写的,而是我们引入的第三方依赖当中提供的。

当我们需要使用其他类时,我们无法在第三方类上添加@Component注解或衍生注解,那么如何定义第三方的bean呢,我们就需要用到@Bean注解

列如我们要使用SAXReader的方法我们只需要在启动类上添加@Bean标识的方法就可以了

  • 在启动类上添加@Bean标识的方法
@SpringBootApplication
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
//声明第三方bean
@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean
public SAXReader saxReader(){
return new SAXReader();
}
}

xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<emp>
<name>Tom</name>
<age>18</age>
</emp>

测试类:

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {
@Autowired
private SAXReader saxReader;
//第三方bean的管理
@Test
public void testThirdBean() throws Exception {
Document document = saxReader.read(this.getClass().getClassLoader().getResource("1.xml"));
Element rootElement = document.getRootElement();
String name = rootElement.element("name").getText();
String age = rootElement.element("age").getText();
System.out.println(name + " : " + age);
}
//省略其他代码...
}

重启SpringBoot服务,执行测试方法后,控制台输出日志:

Tom : 18

注意:在项目中我们自己定义的类,我们想要把这些类交给IOC容器管理,我们可以直接使用@Component或者衍生注解来声明就可以,

如果这个类不是我们自己定义的,而是引入的第三方依赖当中提供的类,我们想把这个类交给IOC容器管理,此时我们就需要在配置类中定义一个方法,在方法上加上一个@Bean注解

SpringBoot原理

前言

我们接下来来刨析一下SpringBoot的底层原理,因为SpringBoot能够是我们更加简单的进行业务能力的开发,不必过多的关注框架本身的配置使用。

Spring是世界上最流行Java框架,他可以帮助我们更加快速的,更加容易的构建Java项目。在Spring家族中有很多的优秀的框架,而所有的框架都是基于一个基础框架的SpringFramework。

由于Spring框架直接进行项目开发,会比较繁琐

  • 在pom.xml中依赖配置比较繁琐,在项目开发时,需要自己去找到对应的依赖,还需要找到依赖它所配套的依赖以及对应版本,否则就会出现版本冲突问题。
  • 在使用Spring框架进行项目开发时,需要在Spring的配置文件中做大量的配置,这就造成Spring框架入门难度较大,学习成本较高。

所以我们在Spring框架4.0版本之后,又推出了一个全新的框架SpringBoot,我们可以通过SpringBoot来简化Spring框架的开发,直接基于SpringBoot来构建Java项目

为什么要使用SpringBoot来构建开发呢?

主要有两个特别重要的功能

  1. 起步依赖
  2. 自动配置

起步依赖

我们没有使用SpringBoot,用的是Spring框架进行web程序的开发,此时我们就需要引入web程序开发所需要的一些依赖。

spring-webmvc依赖:这是Spring框架进行web程序开发所需要的依赖

servlet-api依赖:Servlet基础依赖

jackson-databind依赖:JSON处理工具包

如果要使用AOP,还需要引入aop依赖、aspect依赖

项目中所引入的这些依赖,还需要保证版本匹配,否则就可能会出现版本冲突问题。

如果我们使用SpringBoot,就只需要引入一个依赖就可以了,这就是Web开发的起步依赖:springboot-starter-web

原理是 Maven的依赖传递

在起步依赖中以提供了当前程序开发所需要的所有常见依赖,只需要引入这一个依赖,其他依赖就会自动的通过Maven的依赖传递进来

自动配置

自动配置就是当Spring容器启动后,一些配置类,bean对象就自动存入IOC容器中。不需要手动声明,简化操作。

SpringBoot项目在启动时通过自动配置完成了bean对象的创建。

在启动类中,有一个注解@SpringBootApplication,点进注解,有三个注解是比较重要的。

  • @SpringBootConfiguration:进去这个注解我们可以发现底层是Configuaration注解,也就是支持JavaConfig的方式来进行配置(使用Configuration配置类等同于XML文件)

  • @EnableAutoConfiguration:开启自动配置功能

  • @ComponentScan:扫描注解,默认是扫描当前类下的package。将

    `@Controller/@Service/@Component/@Reposito

    ry`等注解加载到IOC容器中

“约定大于配置”,在SpringBoot中是怎么做的呢,其实靠的就是@EnableAutoConfiguration,简单来说,这个注解可以帮助我们自动载入应用程序所需要的所有默认配置,点进去我们会发现

  • @AutoConfigurationPackage:自动配置包
  • @Import:给IOC容器导入组件

我们再进入@AutoConfigurationPackage

可以发现,依靠的还是@Import注解,再点进去查看,我们发现重要的就是以下的代码:

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}

默认的情况下就是将:主配置类(@SpringBootApplication)的所在包及其子包里边的组件扫描到Spring容器中。

我们回到@Import(AutoConfigurationImportSelector.class)这句代码上,再点进去AutoConfigurationImportSelector.class

  • FACTORIES_RESOURCE_LOCATION的值是META-INF/spring.factories

  • Spring启动的时候会扫描所有jar路径下的META-INF/spring.factories,将其文件包装成Properties对象

  • 从Properties对象获取到key值为EnableAutoConfiguration的数据,然后添加到容器里边。

    其中@EnableAutoConfiguration是关键(启用自动配置),内部实际上就去加载META-INF/spring.factories文件的信息,然后筛选出以EnableAutoConfiguration为key的数据,加载到IOC容器中,实现自动配置功能!

常见方案

当我们在工程中,导入utils工程包时,我们如果在xml文件中通过坐标引入依赖。我们在测试方法中是无法找到bean对象的

原因

  • 原因在我们之前讲解IOC的时候有提到过,在类上添加@Component注解来声明bean对象时,还需要保证@Component注解能被Spring的组件扫描到。
  • SpringBoot项目中的@SpringBootApplication注解,具有包扫描的作用,但是它只会扫描启动类所在的当前包以及子包。
  • 当前包:com.itheima, 第三方依赖中提供的包:com.example(扫描不到)

使用@ComponentScan组件扫描(启动类)

@SpringBootApplication
@ComponentScan({"com.itheima","com.example"}) //指定要扫描的包
public class SpringbootWebConfig2Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootWebConfig2Application.class, args);
}
}

@Import导入

  • 导入形式主要有以下几种:
    1. 导入普通类
    2. 导入配置类
    3. 导入ImportSelector接口实现类

1). 使用@Import导入普通类:

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

2). 使用@Import导入配置类:

  • 配置类
@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). 使用@Import导入ImportSelector接口实现类:

  • ImportSelector接口实现类
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);
}
}

本文作者:开卷日记

本文链接:https://www.cnblogs.com/yifan0820/p/17919388.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   奕帆卷卷  阅读(28)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起