国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【JavaWeb后端開發(fā)-第七章】SpingBoot原理

這篇具有很好參考價值的文章主要介紹了【JavaWeb后端開發(fā)-第七章】SpingBoot原理。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。


前言

????在前面的所有章節(jié)當中,我們學習的都是web開發(fā)的技術使用,都是面向應用層面的,我們學會了怎么樣去用。而我們今天所要學習的是web后端開發(fā)的最后一個篇章springboot原理篇,主要偏向于底層原理。

本章節(jié)的安排包括三個部分:
????1. 配置優(yōu)先級:Springboot項目當中屬性配置的常見方式以及配置的優(yōu)先級
????2. Bean的管理
????3. 剖析Springboot的底層原理

1. 配置優(yōu)先級

在我們前面的章節(jié)當中,我們已經講解了SpringBoot項目當中支持的三類配置文件:
????? application.properties
????? application.yml
????? application.yaml

????在SpringBoot項目當中,我們要想配置一個屬性,可以通過這三種方式當中的任意一種來配置都可以,那么如果項目中同時存在這三種配置文件,且都配置了同一個屬性,如:Tomcat端口號,到底哪一份配置文件生效呢?

????? application.properties

server.port=8081

????? application.yml

server:
  port: 8082

????? application.yaml

server:
  port: 8082

我們啟動SpringBoot程序,測試下三個配置文件中哪個Tomcat端口號生效:

????? propertiesyaml、yml三種配置文件同時存在

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

properties、yamlyml三種配置文件,優(yōu)先級最高的是properties

????? yaml、yml兩種配置文件同時存在

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

配置文件優(yōu)先級排名(從高到低):
????1. properties配置文件
????2. yml配置文件
????3. yaml配置文件

注意事項:雖然springboot支持多種格式配置文件,但是在項目開發(fā)時,推薦統(tǒng)一使用一種格式的配置。(yml是主流

????

????在SpringBoot項目當中除了以上3種配置文件外,SpringBoot為了增強程序的擴展性,除了支持配置文件的配置方式以外,還支持另外兩種常見的配置方式

  1. Java系統(tǒng)屬性配置 (格式: -Dkey=value)
-Dserver.port=9000
  1. 命令行參數(格式:–key=value)
--server.port=10010

????

那在idea當中運行程序時,如何來指定Java系統(tǒng)屬性命令行參數呢?

????? 編輯啟動程序的配置信息

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

重啟服務,同時配置Tomcat端口(三種配置文件、系統(tǒng)屬性、命令行參數),測試哪個Tomcat端口號生效:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

刪除命令行參數配置,重啟SpringBoot服務:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

優(yōu)先級命令行參數 > 系統(tǒng)屬性參數 > properties參數 > yml參數 > yaml參數

思考:如果項目已經打包上線了,這個時候我們又如何來設置Java系統(tǒng)屬性和命令行參數呢?

java -Dserver.port=9000 -jar XXXXX.jar --server.port=10010 

下面我們來演示下打包程序運行時指定Java系統(tǒng)屬性和命令行參數
????1. 執(zhí)行maven打包指令package,把項目打成jar文件
????2. 使用命令:java -jar 方式運行jar文件程序

項目打包:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

運行jar程序:
????? 同時設置Java系統(tǒng)屬性和命令行參數

java -Dserver.port=9000 -jar springboot-web-config-0.0.1-SNAPSHOT.jar --server.port=10010 

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????? 僅設置Java系統(tǒng)屬性

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

注意事項:
????? Springboot項目進行打包時,需要引入插件 spring-boot-maven-plugin (基于官網骨架創(chuàng)建項目,會自動添加該插件)

????在SpringBoot項目當中,常見的屬性配置方式有5種, 3種配置文件,加上2種外部屬性的配置(Java系統(tǒng)屬性、命令行參數)。通過以上的測試,我們也得出了優(yōu)先級(從低到高):
????? application.yaml(忽略)
????? application.yml
????? application.properties
????? java系統(tǒng)屬性-Dxxx=xxx
????? 命令行參數--xxx=xxx

2. Bean管理

????在前面的章節(jié)當中,已經講過了我們可以通過Spring當中提供的注解@Component以及它的三個衍生注解(@Controller@Service、@Repository)來聲明IOC容器中的bean對象,同時我們也學習了如何為應用程序注入運行時所需要依賴的bean對象,也就是依賴注入DI。

我們本章主要學習IOC容器Bean的其他使用細節(jié),主要學習以下三方面:
????1. 如何從IOC容器中手動的獲取到bean對象
????2. bean的作用域配置
????3. 管理第三方的bean對象

接下來我們先來學習第一方面,IOC容器中獲取bean對象。

2.1. 獲取Bean

????默認情況下,SpringBoot項目在啟動的時候會自動的創(chuàng)建IOC容器(也稱為Spring容器),并且在啟動的過程當中會自動的將bean對象都創(chuàng)建好,存放在IOC容器當中。應用程序在運行時需要依賴什么bean對象,就直接進行依賴注入就可以了。

而在Spring容器中提供了一些方法,可以主動從IOC容器中獲取到bean對象,下面介紹3種常用方式:

  1. 根據name獲取bean
Object getBean(String name)
  1. 根據類型獲取bean
<T> T getBean(Class<T> requiredType)
  1. 根據name獲取bean(帶類型轉換)
<T> T getBean(String name, Class<T> requiredType) 

思考:要從IOC容器當中來獲取到bean對象,需要先拿到IOC容器對象,怎么樣才能拿到IOC容器呢?
解答:想獲取到IOC容器,直接將IOC容器對象注入進來就可以了

控制器:DeptController.java

@RestController
@RequestMapping("/depts")
public class DeptController {
    @Autowired
    private DeptService deptService;
    public DeptController(){
        System.out.println("DeptController constructor ....");
    }
    @GetMapping
    public Result list(){
        List<Dept> deptList = deptService.list();
        return Result.success(deptList);
    }
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        deptService.delete(id);
        return Result.success();
    }
    @PostMapping
    public Result save(@RequestBody Dept dept){
        deptService.save(dept);
        return Result.success();
    }
}

業(yè)務實現類:DeptServiceImpl.java

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;
    @Override
    public List<Dept> list() {
        List<Dept> deptList = deptMapper.list();
        return deptList;
    }
    @Override
    public void delete(Integer id) {
        deptMapper.delete(id);
    }
    @Override
    public void save(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.save(dept);
    }
}

Mapper接口DeptMapper.java

@Mapper
public interface DeptMapper {
    //查詢全部部門數據
    @Select("select * from dept")
    List<Dept> list();
    //刪除部門
    @Delete("delete from dept where id = #{id}")
    void delete(Integer id);
	//新增部門
    @Insert("insert into dept(name, create_time, update_time) values
    (#{name},#{createTime},#{updateTime})")
    void save(Dept dept);
}

test文件夾中的測試類SpringbootWebConfig2ApplicationTests.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);
    }
}

程序運行后控制臺日志:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

問題:輸出的bean對象地址值是一樣的,說明IOC容器當中的bean對象有幾個?
答案:只有一個。 (默認情況下,IOC中的bean對象是單例
????
問題:那么能不能將bean對象設置為非單例的(每次獲取的bean都是一個新對象)?
答案:可以,在下一個知識點(bean作用域)中講解

注意事項:
????上述所說的【Spring項目啟動時,會把其中的bean都創(chuàng)建好】還會受到作用域及延遲初始化影響,這里主要針對于默認的單例非延遲加載的bean而言。

2.2. Bean作用域

????在前面我們提到的IOC容器當中,默認bean對象是單例模式(只有一個實例對象)。那么如何設置bean對象為非單例呢?需要設置bean的作用域。

在Spring中支持五種作用域,后三種在web環(huán)境才生效:

作用域 說明
singleton 容器內同名稱的bean只有一個實例(單例)(默認)
prototype 每次使用該bean時會創(chuàng)建新的實例(非單例)
request 每個請求范圍內會創(chuàng)建新的實例(web環(huán)境中,了解)
session 每個會話范圍內會創(chuàng)建新的實例(web環(huán)境中,了解)
session 每個應用范圍內會創(chuàng)建新的實例(web環(huán)境中,了解)

知道了bean的5種作用域了,我們要怎么去設置一個bean的作用域呢?
可以借助Spring中的@Scope注解來進行配置作用域

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????
1). 測試一

????? 控制器

//默認bean的作用域為:singleton (單例)
@Lazy //延遲加載(第一次使用bean對象時,才會創(chuàng)建bean對象并交給ioc容器管理)
@RestController
@RequestMapping("/depts")
public class DeptController {
    @Autowired
    private DeptService deptService;
    public DeptController(){
        System.out.println("DeptController constructor ....");
    }
//省略其他代碼...
}

????? 測試類

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {
    @Autowired
    private ApplicationContext applicationContext; //IOC容器對象
    //bean的作用域
    @Test
    public void testScope(){
        for (int i = 0; i < 10; i++) {
            DeptController deptController =
                    applicationContext.getBean(DeptController.class);
            System.out.println(deptController);
        }
    }
}

重啟SpringBoot服務,運行測試方法,查看控制臺打印的日志:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

注意事項:
????? IOC容器中的bean默認使用的作用域singleton (單例)
????? 默認singleton的bean,在容器啟動時被創(chuàng)建,可以使用@Lazy注解來延遲初始化(延遲到第一次使用時)

????
2). 測試二

????修改控制器DeptController代碼:

@Scope("prototype") //bean作用域為非單例
@Lazy //延遲加載
@RestController
@RequestMapping("/depts")
public class DeptController {
    @Autowired
    private DeptService deptService;
    public DeptController(){
        System.out.println("DeptController constructor ....");
    }
//省略其他代碼...
}

重啟SpringBoot服務,再次執(zhí)行測試方法,查看控制吧打印的日志:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

注意事項:
????? prototype的bean,每一次使用該bean的時候都會創(chuàng)建一個新的實例
????? 實際開發(fā)當中,絕大部分的Bean是單例的,也就是說絕大部分Bean不需要配置scope屬性

2.3. 第三方Bean

????學習完bean的獲取、bean的作用域之后,接下來我們再來學習第三方bean的配置。

????之前我們所配置的bean,像controller、service,dao三層體系下編寫的類,這些類都是我們在項目當中自己定義的類(自定義類)。當我們要聲明這些bean,也非常簡單,我們只需要在類上加上@Component以及它的這三個衍生注解(@Controller、@Service、@Repository),就可以來聲明這個bean對象了。
????但是在我們項目開發(fā)當中,還有一種情況就是這個類它不是我們自己編寫的,而是我們引入的第三方依賴當中提供的。

pom.xml文件中,引入dom4j

<!--Dom4j-->
<dependency>
	<groupId>org.dom4j</groupId>
	<artifactId>dom4j</artifactId>
	<version>2.1.3</version>
</dependency>

dom4j就是第三方組織提供的。 dom4j中的SAXReader類就是第三方編寫的。

當我們需要使用到SAXReader對象時,直接進行依賴注入是不是就可以了呢?
????按照我們之前的做法,需要在SAXReader類上添加一個注解@Component(將當前類交給IOC容器管理)

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

結論:第三方提供的類是只讀的。無法在第三方類上添加@Component注解或衍生注解

那么我們應該怎樣使用并定義第三方的bean呢?
????如果要管理的bean對象來自于第三方(不是自定義的),是無法用@Component及衍生注解聲明bean的,就需要用到@Bean注解

解決方案1:在啟動類上添加@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服務,執(zhí)行測試方法后,控制臺輸出日志:Tom : 18

說明:以上在啟動類中聲明第三方Bean的作法,不建議使用(項目中要保證啟動類的純粹性

解決方案2:在配置類中定義@Bean標識的方法

如果需要定義第三方Bean時, 通常會單獨定義一個配置類
com.itheima包中創(chuàng)建config包,然后在config包中創(chuàng)建CommonConfig.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();
    }
}

注釋掉SpringBoot啟動類中創(chuàng)建第三方bean對象的代碼
重啟服務,執(zhí)行測試方法,查看控制臺日志:Tom : 18

????在方法上加上一個@Bean注解,Spring 容器在啟動的時候,它會自動的調用這個方法,并將方法的返回值聲明為Spring容器當中的Bean對象。

注意事項 :
????? 通過@Bean注解namevalue屬性可以聲明bean的名稱,如果不指定,默認bean的名稱就是方法名
????? 如果第三方bean需要依賴其它bean對象,直接在bean定義方法中設置形參即可,容器會根據類型自動裝配

關于Bean大家只需要保持一個原則:
????? 如果是在項目當中我們自己定義的類,想將這些類交給IOC容器管理,我們直接使用@Component以及它的衍生注解來聲明就可以。
????? 如果這個類它不是我們自己定義的,而是引入的第三方依賴當中提供的類,而且我們還想將這個類交給IOC容器管理。此時我們就需要在配置類中定義一個方法,在方法上加上一個@Bean注解,通過這種方式來聲明第三方的bean對象。

3. SpringBoot原理

????經過前面章節(jié)的學習,大家也會發(fā)現基于SpringBoot進行web程序的開發(fā)是非常簡單、非常高效的。
????SpringBoot使我們能夠集中精力地去關注業(yè)務功能的開發(fā),而不用過多地關注框架本身的配置使用。而我們前面所講解的都是面向應用層面的技術,接下來我們開始學習SpringBoot的原理,這部分內容偏向于底層的原理分析。

????在剖析SpringBoot的原理之前,我們先來快速回顧一下我們前面所講解的Spring家族的框架。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????Spring是目前世界上最流行的Java框架,它可以幫助我們更加快速、更加容易的來構建Java項目。而在Spring家族當中提供了很多優(yōu)秀的框架,而所有的框架都是基于一個基礎框架的SpringFramework(也就是Spring框架)。而前面我們也提到,如果我們直接基于Spring框架進行項目的開發(fā),會比較繁瑣。

這個繁瑣主要體現在兩個地方:
????1. 在pom.xml中依賴配置比較繁瑣,在項目開發(fā)時,需要自己去找到對應的依賴,還需要找到依賴它所配套的依賴以及對應版本,否則就會出現版本沖突問題。
????2. 在使用Spring框架進行項目開發(fā)時,需要在Spring的配置文件中做大量的配置,這就造成Spring框架入門難度較大,學習成本較高。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????基于Spring存在的問題,官方在Spring框架4.0版本之后,又推出了一個全新的框架:SpringBoot。
????通過 SpringBoot來簡化Spring框架的開發(fā)(是簡化不是替代)。我們直接基于SpringBoot來構建Java項目,會讓我們的項目開發(fā)更加簡單,更加快捷。

????SpringBoot框架之所以使用起來更簡單更快捷,是因為SpringBoot框架底層提供了兩個非常重要的功能:一個是起步依賴,一個是自動配置。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????通過SpringBoot所提供的起步依賴,就可以大大的簡化pom文件當中依賴的配置,從而解決了Spring框架當中依賴配置繁瑣的問題。
????
????通過自動配置的功能就可以大大的簡化框架在使用時bean的聲明以及bean的配置。我們只需要引入程序開發(fā)時所需要的起步依賴,項目開發(fā)時所用到常見的配置都已經有了,我們直接使用就可以了

????簡單回顧之后,接下來我們來學習下SpringBoot的原理。其實學習SpringBoot的原理就是來解析SpringBoot當中的起步依賴自動配置的原理。我們首先來學習SpringBoot當中起步依賴的原理

3.1. 起步依賴

????假如我們沒有使用SpringBoot,用的是Spring框架進行web程序的開發(fā),此時我們就需要引入web程序開發(fā)所需要的一些依賴。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

spring-webmvc依賴:這是Spring框架進行web程序開發(fā)所需要的依賴
????
servlet-api依賴:Servlet基礎依賴
????
jackson-databind依賴:JSON處理工具包
????
如果要使用AOP,還需要引入aop依賴、aspect依賴
????
項目中所引入的這些依賴,還需要保證版本匹配,否則就可能會出現版本沖突問題

????如果我們使用了SpringBoot,就不需要像上面這么繁瑣的引入依賴了。我們只需要引入一個依賴就可以了,那就是web開發(fā)的起步依賴:springboot-starter-web。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

為什么我們只需要引入一個web開發(fā)的起步依賴,web開發(fā)所需要的所有的依賴都有了呢?
????因為Maven的依賴傳遞。

????? 在SpringBoot給我們提供的這些起步依賴當中,已提供了當前程序開發(fā)所需要的所有的常見依賴(官網地址:https://docs.spring.io/spring-boot/docs/2.7.7/reference/htmlsingle/#using.build-systems.starters )。
????? 比如:springboot-starter-web,這是web開發(fā)的起步依賴,在web開發(fā)的起步依賴當中,就集成了web開發(fā)中常見的依賴:json、webwebmvc、tomcat等。我們只需要引入這一個起步依賴,其他的依賴都會自動的通過Maven的依賴傳遞進來。

結論:起步依賴的原理就是Maven的依賴傳遞。

3.2. 自動配置

????我們講解了SpringBoot當中起步依賴的原理,就是Maven的依賴傳遞。接下來我們解析下自動配置的原理,我們要分析自動配置的原理,首先要知道什么是自動配置

3.2.1. 概述

????SpringBoot的自動配置就是當Spring容器啟動后,一些配置類、bean對象就自動存入到了IOC容器中,不需要我們手動去聲明,從而簡化了開發(fā),省去了繁瑣的配置操作。

比如:我們要進行事務管理、要進行AOP程序的開發(fā),此時就不需要我們再去手動的聲明這些bean對象了,我們直接使用就可以從而大大的簡化程序的開發(fā),省去了繁瑣的配置操作。

????

下面我們打開idea,一起來看下自動配置的效果:

????運行SpringBoot啟動類

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????大家會看到有兩個CommonConfig,在第一個CommonConfig類中定義了一個bean對象bean對象的名字叫reader。
????在第二個CommonConfig中它的bean名字叫commonConfig,為什么還會有這樣一個bean對象呢?原因是在CommonConfig配置類上添加了一個注解@Configuration,而@Configuration底層就是@Component

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

所以配置類最終也是SpringIOC容器當中的一個bean對象

????在IOC容器中除了我們自己定義的bean以外,還有很多配置類,這些配置類都是SpringBoot在啟動的時候加載進來的配置類。這些配置類加載進來之后,它也會生成很多的bean對象。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

比如:配置類GsonAutoConfiguration里面有一個bean,bean的名字叫gson,它的類型是Gson。
????
com.google.gson.Gson是谷歌包中提供的用來處理JSON格式數據的。

????當我們想要使用這些配置類中生成的bean對象時,可以使用@Autowired就自動注入了:

import com.google.gson.Gson;
import com.itheima.pojo.Result;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class AutoConfigurationTests {
    @Autowired
    private Gson gson;
    @Test
    public void testJson(){
        String json = gson.toJson(Result.success());
        System.out.println(json);
    }
}

添加斷點,使用debug模式運行測試類程序:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

問題:在當前項目中我們并沒有聲明谷歌提供的Gson這么一個bean對象,然后我們卻可以通過@Autowired從Spring容器中注入bean對象,那么這個bean對象怎么來的?
答案:SpringBoot項目在啟動時通過自動配置完成了bean對象的創(chuàng)建。

????體驗了SpringBoot的自動配置了,下面我們就來分析自動配置的原理。其實分析自動配置原理就是來解析在SpringBoot項目中,在引入依賴之后是如何將依賴jar包當中所定義的配置類以及bean加載到SpringIOC容器中的。

3.2.2. 常見方案

概述

????我們知道了什么是自動配置之后,接下來我們就要來剖析自動配置的原理。解析自動配置的原理就是分析在 SpringBoot項目當中,我們引入對應的依賴之后,是如何將依賴jar包當中所提供的bean以及配置類直接加載到當前項目的SpringIOC容器當中的。

接下來,我們就直接通過代碼來分析自動配置原理。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

準備工作:在Idea中導入"資料\03. 自動配置原理"下的 itheima-utils工程

????
????1、在SpringBoot項目 spring-boot-web-config2 工程中,通過坐標引入itheima-utils依賴

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

itheima-utils的項目結構如下:
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

其中,TokenParser.java

@Component
public class TokenParser {
	public void parse(){
		System.out.println("TokenParser ... parse ...");
	}
}

????2、在測試類中,添加測試方法

@SpringBootTest
public class AutoConfigurationTests {

	@Autowired
	private ApplicationContext applicationContext;

	@Test
	public void testTokenParse(){
		System.out.println(applicationContext.getBean(TokenParser.class));
	}
	
	//省略其他代碼...
}

????3、執(zhí)行測試方法

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

異常信息描述: 沒有com.example.TokenParse類型的bean
說明:在Spring容器中沒有找到com.example.TokenParse類型的bean對象

思考:引入進來的第三方依賴當中的bean以及配置類為什么沒有生效?
????? 原因在我們之前講解IOC的時候有提到過,在類上添加@Component注解來聲明bean對象時,還需要保證@Component注解能被Spring的組件掃描到。
????? SpringBoot項目中的@SpringBootApplication注解,具有包掃描的作用,但是它只會掃描啟動類所在的當前包以及子包。
????? 當前包:com.itheima, 第三方依賴中提供的包:com.example(掃描不到)

那么如何解決以上問題的呢?
????? 方案1:@ComponentScan組件掃描
????? 方案2:@Import導入(使用@Import導入的類會被Spring加載到IOC容器中)

方案一

@ComponentScan組件掃描

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

重新執(zhí)行測試方法,控制臺日志輸出:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????大家可以想象一下,如果采用以上這種方式來完成自動配置,那我們進行項目開發(fā)時,當需要引入大量的第三方的依賴,就需要在啟動類上配置N多要掃描的包,這種方式會很繁瑣。而且這種大面積的掃描性能也比較低。
????
缺點:
????1.使用繁瑣
????2.性能低
結論:SpringBoot中并沒有采用以上這種方案

方案二

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

重新執(zhí)行測試方法,控制臺日志輸出:
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

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

????? 測試類

@SpringBootTest
public class AutoConfigurationTests {
    @Autowired
    private ApplicationContext applicationContext;
    @Test
    public void testHeaderParser(){
        System.out.println(applicationContext.getBean(HeaderParser.class));
    }
    @Test
    public void testHeaderGenerator(){
        System.out.println(applicationContext.getBean(HeaderGenerator.class
        ));
    }
    
	//省略其他代碼...
}

執(zhí)行測試方法:
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

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

執(zhí)行測試方法:
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

我們使用@Import注解通過這三種方式都可以導入第三方依賴中所提供的bean或者是配置類。

思考:如果基于以上方式完成自動配置,當要引入一個第三方依賴時,是不是還要知道第三方依賴中有哪些配置類和哪些Bean對象?
答案:是的。(對程序員來講,很不友好,而且比較繁瑣)
????
思考:當我們要使用第三方依賴,依賴中到底有哪些bean和配置類,誰最清楚?
答案:第三方依賴自身最清楚。

結論:我們不用自己指定要導入哪些bean對象和配置類了,讓第三方依賴它自己來指定。

????

怎么讓第三方依賴自己指定bean對象和配置類?
????? 比較常見的方案就是第三方依賴給我們提供一個注解,這個注解一般都以@EnableXxxx開頭的注解,注解中封裝的就是@Import注解

????

4). 使用第三方依賴提供的 @EnableXxxxx注解

????? 第三方依賴中提供的注解

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

執(zhí)行測試方法:
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

以上四種方式都可以完成導入操作,但是 第4種 方式會更方便更優(yōu)雅,而這種方式也是SpringBoot當中所采用的方式。

3.2.3. 原理分析

3.2.3.1. 源碼跟蹤

????前面我們講解了在項目當中引入第三方依賴之后,如何加載第三方依賴中定義好的bean對象以及配置類,從而完成自動配置操作。那下面我們通過源碼跟蹤的形式來剖析下SpringBoot底層到底是如何完成自動配置的。

源碼跟蹤技巧:
????在跟蹤框架源碼的時候,一定要抓住關鍵點,找到核心流程。一定不要從頭到尾一行代碼去看,一個方法的去研究,一定要找到關鍵流程,抓住關鍵點,先在宏觀上對整個流程或者整個原理有一個認識,有精力再去研究其中的細節(jié)。

????

要搞清楚SpringBoot的自動配置原理,要從SpringBoot啟動類上使用的核心注解@SpringBootApplication開始分析:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java
????

在@SpringBootApplication注解中包含了:
????? 元注解(不再解釋)
????? @SpringBootConfiguration
????? @EnableAutoConfiguration
????? @ComponentScan

(1)我們先來看第一個注解:@SpringBootConfiguration

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

@SpringBootConfiguration注解上使用了@Configuration,表明SpringBoot啟動類就是一個配置類。
????
@Indexed注解,是用來加速應用啟動的(不用關心)。

(2)接下來再先看@ComponentScan注解

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

@ComponentScan注解是用來進行組件掃描的,掃描啟動類所在的包及其子包下所有被@Component及其衍生注解聲明的類。
????
SpringBoot啟動類,之所以具備掃描包功能,就是因為包含了@ComponentScan注解。

(3)最后我們來看看@EnableAutoConfiguration注解(自動配置核心注解):

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

使用@Import注解,導入了實現ImportSelector接口的實現類。
AutoConfigurationImportSelector類ImportSelector接口的實現類
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

AutoConfigurationImportSelector類中重寫了ImportSelector接口selectImports()方法

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

selectImports()方法底層調用getAutoConfigurationEntry()方法,獲取可自動配置的配置類信息集合

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

getAutoConfigurationEntry()方法通過調用getCandidateConfigurations(annotationMetadata, attributes)方法獲取在配置文件中配置的所有自動配置類的集合

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

getCandidateConfigurations方法的功能:
????獲取所有基于METAINF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件、META-INF/spring.factories文件中配置類的集合

????

????METAINF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件META-INF/spring.factories文件這兩個文件在哪里呢?

????通常在引入的起步依賴中,都有包含以上兩個文件

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????在前面在給大家演示自動配置的時候,我們直接在測試類當中注入了一個叫gson的 bean對象,進行JSON格式轉換。雖然我們沒有配置bean對象,但是我們是可以直接注入使用的。原因就是因為在自動配置類當中做了自動配置。到底是在哪個自動配置類當中做的自動配置呢?我們通過搜索來查詢一下。

????在METAINF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports配置文件中指定了第三方依賴Gson的配置類:GsonAutoConfiguration

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

第三方依賴中提供的GsonAutoConfiguration類

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

GsonAutoConfiguration類上,添加了注解@AutoConfiguration,通過查看源碼,可以明確:GsonAutoConfiguration類是一個配置。
???? 【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????看到這里,大家就應該明白為什么可以完成自動配置了,原理就是在配置類中定義一個@Bean標識的方法,而Spring會自動調用配置類中使用@Bean標識的方法,并把方法的返回值注冊到IOC容器中。

自動配置源碼小結
????自動配置原理源碼入口就是@SpringBootApplication注解,在這個注解中封裝了3個注解,分別是:

????? @SpringBootConfiguration
????????聲明當前類是一個配置類
????? @ComponentScan
????????進行組件掃描(SpringBoot中默認掃描的是啟動類所在的當前包及其子包)
????? @EnableAutoConfiguration
????????封裝了@Import注解(Import注解中指定了一個ImportSelector接口的實現類)
????????????在實現類重寫的selectImports()方法,讀取當前項目下所有依賴jar包中METAINF/spring.factories、METAINF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports兩個文件里面定義的配置類(配置類中定義了@Bean注解標識的方法)。

????

????當SpringBoot程序啟動時,就會加載配置文件當中所定義的配置類,并將這些配置類信息(類的全限定名)封裝到String類型的數組中,最終通過@Import注解將這些配置類全部加載到Spring的IOC容器中,交給IOC容器管理。

????最后呢,給大家拋出一個問題:在METAINF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中定義的配置類非常多,而且每個配置類中又可以定義很多的bean,那這些bean都會注冊到Spring的IOC容器中嗎?
????答案:并不是。 在聲明bean對象時,上面有加一個以@Conditional開頭的注解,這種注解的作用就是按照條件進行裝配,只有滿足條件之后,才會將bean注冊到Spring的IOC容器(下面會詳細來講解)

3.2.3.2. @Conditional

????我們在跟蹤SpringBoot自動配置的源碼的時候,在自動配置類聲明bean的時候,除了在方法上加了一個@Bean注解以外,還會經常用到一個注解,就是以Conditional開頭的這一類的注解。以Conditional開頭的這些注解都是條件裝配的注解。下面我們就來介紹下條件裝配注解

@Conditional注解
????? 作用:按照一定的條件進行判斷,在滿足給定條件后才會注冊對應的bean對象到Spring的IOC容器中。
????? 位置:方法、類

????? @Conditional本身是一個父注解,派生出大量的子注解:
????????@ConditionalOnClass:判斷環(huán)境中有對應字節(jié)碼文件,才注冊bean到IOC容器。
????????@ConditionalOnMissingBean:判斷環(huán)境中沒有對應的bean(類型或名稱),才注冊bean到IOC容器。
????????@ConditionalOnProperty:判斷配置文件中有對應屬性和值,才注冊bean到IOC容器。

下面我們通過代碼來演示下Conditional注解的使用:

????? @ConditionalOnClass注解

@Configuration
public class HeaderConfig {
    @Bean
    @ConditionalOnClass(name="io.jsonwebtoken.Jwts")//環(huán)境中存在指定的這個類,才會將該bean加入IOC容器
    public HeaderParser headerParser(){
        return new HeaderParser();
    }
//省略其他代碼...
}

????? pom.xml

<!--JWT令牌-->
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt</artifactId>
	<version>0.9.1</version>
</dependency>

????? 測試類

@SpringBootTest
public class AutoConfigurationTests {
    @Autowired
    private ApplicationContext applicationContext;
    @Test
    public void testHeaderParser(){
        System.out.println(applicationContext.getBean(HeaderParser.class));
    }
    
	//省略其他代碼...
}

執(zhí)行testHeaderParser()測試方法:
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java
因為io.jsonwebtoken.Jwts字節(jié)碼文件在啟動SpringBoot程序時已存在,所以創(chuàng)建HeaderParser對象并注冊到IOC容器中。

????? @ConditionalOnMissingBean注解

@Configuration
public class HeaderConfig {
    @Bean
    @ConditionalOnMissingBean //不存在該類型的bean,才會將該bean加入IOC容器
    public HeaderParser headerParser(){
        return new HeaderParser();
    }

	//省略其他代碼...
}

執(zhí)行testHeaderParser()測試方法:
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java
????SpringBoot在調用@Bean標識的headerParser()前,IOC容器中是沒有HeaderParser類型的bean,所以HeaderParser對象正常創(chuàng)建,并注冊到IOC容器中。

再次修改@ConditionalOnMissingBean注解:

@Configuration
public class HeaderConfig {
    @Bean
    @ConditionalOnMissingBean(name="deptController2")//不存在指定名稱的bean,才會將該bean加入IOC容器
    public HeaderParser headerParser(){
        return new HeaderParser();
    }
//省略其他代碼...
}

執(zhí)行testHeaderParser()測試方法:
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java
因為在SpringBoot環(huán)境中不存在名字叫deptController2的bean對象,所以創(chuàng)建HeaderParser對象并注冊到IOC容器中。

再次修改@ConditionalOnMissingBean注解:

@Configuration
public class HeaderConfig {

    @Bean
    @ConditionalOnMissingBean(HeaderConfig.class)//不存在指定類型的bean,才會將bean加入IOC容器
    public HeaderParser headerParser(){
        return new HeaderParser();
    }
    
	//省略其他代碼...
}
@SpringBootTest
public class AutoConfigurationTests {
    @Autowired
    private ApplicationContext applicationContext;
    
    @Test
    public void testHeaderParser(){
        System.out.println(applicationContext.getBean(HeaderParser.class));
    }
    
	//省略其他代碼...
}

執(zhí)行testHeaderParser()測試方法:
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java
????
????因為HeaderConfig類中添加@Configuration注解,而@Configuration注解中包含了@Component,所以SpringBoot啟動時會創(chuàng)建HeaderConfig類對象,并注冊到IOC容器中。
????
????當IOC容器中有HeaderConfig類型的bean存在時,不會把創(chuàng)建HeaderParser對象注冊到IOC容器中。而IOC容器中沒有HeaderParser類型的對象時,通過getBean(HeaderParser.class)方法獲取bean對象時,引發(fā)異常:NoSuchBeanDefinitionException

????

????? @ConditionalOnProperty注解(這個注解和配置文件當中配置的屬性有關系)

先在application.yml配置文件中添加如下的鍵值對:

name: itheima 

在聲明bean的時候就可以指定一個條件@ConditionalOnProperty

@Configuration
public class HeaderConfig {

    @Bean
    @ConditionalOnProperty(name ="name",havingValue = "itheima")//配置文件中存在指定屬性名與值,才會將bean加入IOC容器
    public HeaderParser headerParser(){
        return new HeaderParser();
    }
    
    @Bean
    public HeaderGenerator headerGenerator(){
        return new HeaderGenerator();
    }
}

執(zhí)行testHeaderParser()測試方法:
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

修改@ConditionalOnProperty注解: havingValue的值修改為"itheima2"

@Bean
@ConditionalOnProperty(name ="name",havingValue = "itheima2")//配置文件中存在指定屬性名與值,才會將bean加入IOC容器
public HeaderParser headerParser(){
	return new HeaderParser();
}

再次執(zhí)行testHeaderParser()測試方法:
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java
因為application.yml配置文件中,不存在:name: itheima2,所以HeaderParser對象IOC容器不存在

????

我們再回頭看看之前講解SpringBoot源碼時提到的一個配置類:GsonAutoConfiguration

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

最后再給大家梳理一下自動配置原理:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

自動配置的核心就在@SpringBootApplication注解上,SpringBootApplication這個注解底層包含了3個注解,分別是:
????? @SpringBootConfiguration
????
????? @ComponentScan
????
????? @EnableAutoConfiguration
????
????
@EnableAutoConfiguration這個注解才是自動配置的核心。
????? 它封裝了一個@Import注解,Import注解里面指定了一個ImportSelector接口的實現類。
????
????? 在這個實現類中,重寫了ImportSelector接口中的selectImports()方法
????
????? 而selectImports()方法中會去讀取兩份配置文件,并將配置文件中定義的配置類做為selectImports()方法的返回值返回,返回值代表的就是需要將哪些類交給Spring的IOC容器進行管理。
????
????? 那么所有自動配置類的中聲明的bean都會加載到Spring的IOC容器中嗎? 其實并不會,因為這些配置類中在聲明bean時,通常都會添加@Conditional開頭的注解,這個注解就是進行條件裝配。而Spring會根據Conditional注解有選擇性的進行bean的創(chuàng)建。
????
????? @Enable開頭的注解底層,它就封裝了一個注解 import 注解,它里面指定了一個類,是ImportSelector 接口的實現類。在實現類當中,我們需要去實現 ImportSelector 接口當中的一個方法 selectImports 這個方法。這個方法的返回值代表的就是我需要將哪些類交給 spring 的 IOC容器進行管理。
????
????? 此時它會去讀取兩份配置文件,一份兒是 spring.factories,另外一份兒是autoConfiguration.imports。而在 autoConfiguration.imports 這份兒文件當中,它就會去配置大量的自動配置的類。
????
????? 而前面我們也提到過這些所有的自動配置類當中,所有的 bean都會加載到 spring 的IOC容器當中嗎?其實并不會,因為這些配置類當中,在聲明 bean 的時候,通常會加上這么一類@Conditional 開頭的注解。這個注解就是進行條件裝配。所以SpringBoot非常的智能,它會根據 @Conditional 注解來進行條件裝配。只有條件成立,它才會聲明這個bean,才會將這個 bean 交給 IOC 容器管理。

3.2.4. 案例

3.2.4.1. 自定義starter分析

????前面我們解析了SpringBoot中自動配置的原理,下面我們就通過一個自定義starter案例來加深大家對于自動配置原理的理解。首先介紹一下自定義starter的業(yè)務場景,再來分析一下具體的操作步驟。
????所謂starter指的就是SpringBoot當中的起步依賴。在SpringBoot當中已經給我們提供了很多的起步依賴了,我們?yōu)槭裁催€需要自定義 starter 起步依賴?

問題:為什么還需要自定義 starter 起步依賴?
????
解答
????這是因為在實際的項目開發(fā)當中,我們可能會用到很多第三方的技術,并不是所有的第三方的技術官方都給我們提供了與SpringBoot整合的starter起步依賴,但是這些技術又非常的通用,在很多項目組當中都在使用。

業(yè)務場景:
????? 我們前面案例當中所使用的阿里云OSS對象存儲服務,現在阿里云的官方是沒有給我們提供對應的起步依賴的,這個時候使用起來就會比較繁瑣,我們需要引入對應的依賴。我們還需要在配置文件當中進行配置,還需要基于官方SDK示例來改造對應的工具類,我們在項目當中才可以進行使用。
????? 大家想在我們當前項目當中使用了阿里云OSS,我們需要進行這么多步的操作。在別的項目組當中要想使用阿里云OSS,是不是也需要進行這么多步的操作,所以這個時候我們就可以自定義一些公共組件,在這些公共組件當中,我就可以提前把需要配置的bean都提前配置好。將來在項目當中,我要想使用這個技術,我直接將組件對應的坐標直接引入進來,就已經自動配置好了,就可以直接使用了。我們也可以把公共組件提供給別的項目組進行使用,這樣就可以大大的簡化我們的開發(fā)。

在SpringBoot項目中,一般都會將這些公共組件封裝為SpringBoot當中的starter,也就是我們所說的起步依賴。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

SpringBoot官方starter命名: spring-boot-starter-xxxx
第三組織提供的starter命名: xxxx-spring-boot-starter

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????Mybatis提供了配置類,并且也提供了springboot會自動讀取的配置文件。當SpringBoot項目啟動時,會讀取到spring.factories配置文件中的配置類并加載配置類,生成相關bean對象注冊到IOC容器中。
????結果:我們可以直接在SpringBoot程序中使用Mybatis自動配置的bean對象

在自定義一個起步依賴starter的時候,按照規(guī)范需要定義兩個模塊:
????1. starter模塊(進行依賴管理 [把程序開發(fā)所需要的依賴都定義在starter起步依賴中] )
????2. autoconfigure模塊(自動配置)

將來在項目當中進行相關功能開發(fā)時,只需要引入一個起步依賴就可以了,因為它會將autoconfigure自動配置的依賴給傳遞下來。

????上面我們簡單介紹了自定義starter的場景,以及自定義starter時涉及到的模塊之后,接下來我們就來完成一個自定義starter的案例。

????

- - - - - - - - - - - - - - - - - - - -?? 案例??- - - - - - - - - - - - - - - - - - - -
????

需求:
????自定義aliyun-oss-spring-boot-starter,完成阿里云OSS操作工具類AliyunOSSUtils的自動配置。

目標:
????引入起步依賴引入之后,要想使用阿里云OSS,注入AliyunOSSUtils直接使用即可。

????

之前阿里云OSS的使用:
????? 配置文件

#配置阿里云OSS參數
aliyun:
  oss:
  endpoint: https://oss-cn-shanghai.aliyuncs.com
  accessKeyId: LTAI5t9MZK8iq5T2Av5GLDxX
  accessKeySecret: C0IrHzKZGKqU8S7YQcevcotD3Zd5Tc
  bucketName: web-framework01

????? AliOSSProperties類

@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
	//區(qū)域
	private String endpoint;
	//身份ID
	private String accessKeyId ;
	//身份密鑰
	private String accessKeySecret ;
	//存儲空間
	private String bucketName;
}

????? AliOSSUtils工具類

@Component //當前類對象由Spring創(chuàng)建和管理
public class AliOSSUtils {
    @Autowired
    private AliOSSProperties aliOSSProperties;
    /**
     * 實現上傳圖片到OSS
     */
    public String upload(MultipartFile multipartFile) throws
            IOException {
		// 獲取上傳的文件的輸入流
        InputStream inputStream = multipartFile.getInputStream();
		// 避免文件覆蓋
        String originalFilename =
                multipartFile.getOriginalFilename();
        String fileName = UUID.randomUUID().toString() +
                originalFilename.substring(originalFilename.lastIndexOf("."));
		//上傳文件到 OSS
        OSS ossClient = new
                OSSClientBuilder().build(aliOSSProperties.getEndpoint(),
                aliOSSProperties.getAccessKeyId(),
                aliOSSProperties.getAccessKeySecret());
        ossClient.putObject(aliOSSProperties.getBucketName(),
                fileName, inputStream);
		//文件訪問路徑
        String url =aliOSSProperties.getEndpoint().split("http://")[0] +
                "http://" + aliOSSProperties.getBucketName() + "." +
                aliOSSProperties.getEndpoint().split("http://")[1] + "/" + fileName;
		// 關閉ossClient
        ossClient.shutdown();
        return url;// 把上傳到oss的路徑返回
    }
}

????當我們在項目當中要使用阿里云OSS,就可以注入AliOSSUtils工具類來進行文件上傳。但這種方式其實是比較繁瑣的。
????大家再思考,現在我們使用阿里云OSS,需要做這么幾步,將來大家在開發(fā)其他的項目的時候,你使用阿里云OSS,這幾步你要不要做?當團隊中其他小伙伴也在使用阿里云OSS的時候,步驟 不也是一樣的。
????所以這個時候我們就可以制作一個公共組件(自定義starter)。starter定義好之后,將來要使用阿里云OSS進行文件上傳,只需要將起步依賴引入進來之后,就可以直接注入AliOSSUtils使用了。

需求明確了,接下來我們再來分析一下具體的實現步驟:
????第1步:創(chuàng)建自定義starter模塊(進行依賴管理)
????????? 把阿里云OSS所有的依賴統(tǒng)一管理起來
????第2步:創(chuàng)建autoconfigure模塊
????????? 在starter中引入autoconfigure (我們使用時只需要引入starter起步依賴即可)
????第3步:在autoconfigure中完成自動配置
????????? 1. 定義一個自動配置類,在自動配置類中將所要配置的bean都提前配置好
????????? 2. 定義配置文件,把自動配置類的全類名定義在配置文件中

我們分析完自定義阿里云OSS自動配置的操作步驟了,下面我們就按照分析的步驟來實現自定義starter。

3.2.4.2. 自定義starter實現

????自定義starter的步驟我們剛才已經分析了,接下來我們就按照分析的步驟來完成自定義starter的開發(fā)。
????

首先我們先來創(chuàng)建兩個Maven模塊

????1). aliyun-oss-spring-boot-starter模塊

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

注意:上面這一步,如果Spring Boot沒有2.7.5版本,就先用有的,生成maven包后再pom.xml文件中修改成想要的版本即可。

創(chuàng)建完starter模塊后,刪除多余的文件,最終保留內容如下:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

- -注意- -
如果沒有.iml文件,采用如下操作:
????按兩下ctrl,在彈出的窗口右上角點擊project,在下拉列表中選擇需要生成.iml文件的模塊,左邊運行寫 : mvn idea:module ,然后回車運行,即可生成.iml文件

刪除pom.xml文件中多余的內容后:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-oss-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

</project>

????
????2). aliyun-oss-spring-boot-autoconfigure模塊

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

創(chuàng)建完starter模塊后,刪除多余的文件,最終保留內容如下:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

- -注意- -
如果沒有.iml文件,采用如下操作:
????按兩下ctrl,在彈出的窗口右上角點擊project,在下拉列表中選擇需要生成.iml文件的模塊,左邊運行寫 : mvn idea:module ,然后回車運行,即可生成.iml文件

刪除pom.xml文件中多余的內容后:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

</project>

按照我們之前的分析,是需要在starter模塊中來引入autoconfigure這個模塊的。打開starter模塊中的pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-parent</artifactId>
	    <version>2.7.5</version>
	    <relativePath/> <!-- lookup parent from repository -->
	</parent>
	
	<groupId>com.aliyun.oss</groupId>
	<artifactId>aliyun-oss-spring-boot-starter</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	
	<properties>
	    <java.version>11</java.version>
	</properties>
	
	<dependencies>
	    <!--引入autoconfigure模塊-->
	    <dependency>
	        <groupId>com.aliyun.oss</groupId>
	        <artifactId>aliyun-oss-spring-bootautoconfigure</artifactId>
	        <version>0.0.1-SNAPSHOT</version>
	    </dependency>
	
	    <dependency>
	        <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-starter</artifactId>
	    </dependency>
	</dependencies>
	
</project>

前兩步已經完成了,接下來是最關鍵的就是第三步:

autoconfigure模塊當中來完成自動配置操作。

我們將之前案例中所使用的阿里云OSS部分的代碼直接拷貝到autoconfigure模塊下,然后進行改造就行了。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

拷貝過來后,還缺失一些相關的依賴,需要把相關依賴也拷貝過來:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-parent</artifactId>
	    <version>2.7.5</version>
	    <relativePath/> <!-- lookup parent from repository -->
	</parent>
	
	<groupId>com.aliyun.oss</groupId>
	<artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	
	<properties>
	    <java.version>11</java.version>
	</properties>
	
	<dependencies>
	    <dependency>
	        <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-starter</artifactId>
	    </dependency>
	    
	    <!--引入web起步依賴-->
	    <dependency>
	        <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-starter-web</artifactId>
	    </dependency>
	    
	    <!--Lombok-->
	    <dependency>
	        <groupId>org.projectlombok</groupId>
	        <artifactId>lombok</artifactId>
	    </dependency>
	    
	    <!--阿里云OSS-->
	    <dependency>
	        <groupId>com.aliyun.oss</groupId>
	        <artifactId>aliyun-sdk-oss</artifactId>
	        <version>3.15.1</version>
	    </dependency>
	    <dependency>
	        <groupId>javax.xml.bind</groupId>
	        <artifactId>jaxb-api</artifactId>
	        <version>2.3.1</version>
	    </dependency>	    
	    <dependency>
	        <groupId>javax.activation</groupId>
	        <artifactId>activation</artifactId>
	        <version>1.1.1</version>
	    </dependency>	    
	    <!-- no more than 2.3.3-->
	    <dependency>
	        <groupId>org.glassfish.jaxb</groupId>
	        <artifactId>jaxb-runtime</artifactId>
	        <version>2.3.3</version>
	    </dependency>
	    
	</dependencies>
	
</project>

現在大家思考下,在類上添加的@Component注解還有用嗎?

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

答案:沒用了。 在SpringBoot項目中,并不會去掃描com.aliyun.oss這個包,不掃描這個包那類上的注解也就失去了作用。

@Component注解不需要使用了,可以從類上刪除了。
????
刪除后報紅色錯誤,暫時不理會,后面再來處理。
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java
刪除AliOSSUtils類中的@Component注解、@Autowired注解
【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

下面我們就要定義一個自動配置類AliOSSAutoConfiguration了,在自動配置類當中來聲明AliOSSUtils的bean對象。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????
AliOSSAutoConfiguration類:

@Configuration//當前類為Spring配置類
@EnableConfigurationProperties(AliOSSProperties.class)//導入AliOSSProperties類,并交給SpringIOC管理
public class AliOSSAutoConfiguration {
    //創(chuàng)建AliOSSUtils對象,并交給SpringIOC容器
    @Bean
    public AliOSSUtils aliOSSUtils(AliOSSProperties
                                           aliOSSProperties){
        AliOSSUtils aliOSSUtils = new AliOSSUtils();
        aliOSSUtils.setAliOSSProperties(aliOSSProperties);
        return aliOSSUtils;
    }
}

AliOSSProperties類:

/*阿里云OSS相關配置*/
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
    //區(qū)域
    private String endpoint;
    //身份ID
    private String accessKeyId;
    //身份密鑰&ensp;&ensp;&ensp;&ensp;
    private String accessKeySecret;
    //存儲空間
    private String bucketName;

    public String getEndpoint() {
        return endpoint;
    }

    public void setEndpoint(String endpoint) {
        this.endpoint = endpoint;
    }

    public String getAccessKeyId() {
        return accessKeyId;
    }

    public void setAccessKeyId(String accessKeyId) {
        this.accessKeyId = accessKeyId;
    }

    public String getAccessKeySecret() {
        return accessKeySecret;
    }

    public void setAccessKeySecret(String accessKeySecret) {
        this.accessKeySecret = accessKeySecret;
    }

    public String getBucketName() {
        return bucketName;
    }

    public void setBucketName(String bucketName) {
        this.bucketName = bucketName;
    }
}

AliOSSUtils類:

public class AliOSSUtils {

    //注入配置參數實體類對象
    private AliOSSProperties aliOSSProperties;

    public AliOSSProperties getAliOSSProperties() {
        return aliOSSProperties;
    }

    public void setAliOSSProperties(AliOSSProperties aliOSSProperties) {
        this.aliOSSProperties = aliOSSProperties;
    }

    /**
     * 實現上傳圖片到OSS
     */
    public String upload(MultipartFile file) throws IOException {
        //獲取阿里云OSS參數
        String endpoint =aliOSSProperties.getEndpoint();
        String accessKeyId = aliOSSProperties.getAccessKeyId();
        String accessKeySecret = aliOSSProperties.getAccessKeySecret();
        String bucketName = aliOSSProperties.getBucketName();

        // 獲取上傳的文件的輸入流
        InputStream inputStream = file.getInputStream();

        // 避免文件覆蓋
        String originalFilename = file.getOriginalFilename();
        String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));

        //上傳文件到 OSS
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        ossClient.putObject(bucketName, fileName, inputStream);

        //文件訪問路徑
        String url = endpoint.split("http://")[0] + "http://" + bucketName + "." + endpoint.split("http://")[1] + "/" + fileName;
        // 關閉ossClient
        ossClient.shutdown();
        return url;// 把上傳到oss的路徑返回
    }


}

?

在aliyun-oss-spring-boot-autoconfigure模塊中的resources下,新建自動配置文件:

????METAINF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

com.aliyun.oss.AliOSSAutoConfiguration

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

3.2.4.3 自定義starter測試

阿里云OSS的starter我們剛才已經定義好了,接下來我們就來做一個測試。

????今天的課程資料當中,提供了一個自定義starter的測試工程。我們直接打開文件夾,里面有一個測試工程。測試工程就是springboot-autoconfiguration-test,我們只需要將測試工程直接導入到Idea當中即可。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

測試前準備:
????1. 在test工程中引入阿里云starter依賴
????????通過依賴傳遞,會把autoconfigure依賴也引入了

<!--引入阿里云OSS起步依賴-->
<dependency>
	<groupId>com.aliyun.oss</groupId>
	<artifactId>aliyun-oss-spring-boot-starter</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>

????2. 在test工程中的application.yml文件中,配置阿里云OSS配置參數信息(從以前的工程中拷貝即可)

#配置阿里云OSS參數
aliyun:
   oss:
     endpoint: https://oss-cn-shanghai.aliyuncs.com
     accessKeyId: LTAI5t9xxxxxq5T2Av5GLDxX
     accessKeySecret: C0IrHzKxxxxx8S7YQcevcotD3Zd5Tc
     bucketName: web-framework01

????3. 在springboot-autoconfiguration-test工程中的com.itheima.controller.UploadController類編寫代碼

@RestController
public class UploadController {

	@Autowired
	private AliOSSUtils aliOSSUtils;
	
	@PostMapping("/upload")
	public String upload(MultipartFile image) throws Exception {
		//上傳文件到阿里云 OSS
		String url = aliOSSUtils.upload(image);
		return url;
	}
}

編寫完代碼后,我們啟動當前的SpringBoot測試工程:
????隨著SpringBoot項目啟動,自動配置會把AliOSSUtils的bean對象裝配到IOC容器中

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

注意,如果在運行過程出現如下錯誤:
????java: 程序包com.aliyun.oss 不存在
解決辦法:
????刪除項目中的.iml文件,然后重新創(chuàng)建

用postman工具進行文件上傳:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

通過斷點可以看到自動注入AliOSSUtils的bean對象:

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

4. Web后端開發(fā)總結

????到此基于SpringBoot進行web后端開發(fā)的相關知識我們已經學習完畢了。下面我們一起針對這段web課程做一個總結。
????我們來回顧一下關于web后端開發(fā),我們都學習了哪些內容,以及每一塊知識,具體是屬于哪個框架的。

????web后端開發(fā)現在基本上都是基于標準的三層架構進行開發(fā)的,在三層架構當中,Controller控制器層負責接收請求響應數據Service業(yè)務層負責具體的業(yè)務邏輯處理,而Dao數據訪問層也叫持久層,就是用來處理數據訪問操作的,來完成數據庫當中數據的增刪改查操作

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????在三層架構當中,前端發(fā)起請求首先會到達Controller(不進行邏輯處理),然后Controller會直接調用Service 進行邏輯處理, Service再調用Dao完成數據訪問操作。

????如果我們在執(zhí)行具體的業(yè)務處理之前,需要去做一些通用的業(yè)務處理,比如:我們要進行統(tǒng)一的登錄校驗,我們要進行統(tǒng)一的字符編碼等這些操作時,我們就可以借助于Javaweb當中三大組件之一的過濾器Filter或者是Spring當中提供的攔截器Interceptor來實現。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????而為了實現三層架構層與層之間的解耦,我們學習了Spring框架當中的第一大核心:IOC控制反轉DI依賴注入。

????所謂控制反轉,指的是將對象創(chuàng)建的控制權由應用程序自身交給外部容器,這個容器就是我們常說的IOC容器Spring容器。
????而DI依賴注入指的是容器為程序提供運行時所需要的資源。

????除了IOCDI我們還講到了AOP面向切面編程,還有Spring中的事務管理、全局異常處理器,以及傳遞會話技術Cookie、Session以及新的會話跟蹤解決方案JWT令牌,阿里云OSS對象存儲服務,以及通過Mybatis持久層架構操作數據庫等技術。

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????我們在學習這些web后端開發(fā)技術的時候,我們都是基于主流的SpringBoot進行整合使用的。而SpringBoot又是用來簡化開發(fā),提高開發(fā)效率的。像過濾器、攔截器IOC、DIAOP、事務管理等這些技術到底是哪個框架提供的核心功能?

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

????Filter過濾器、Cookie、 Session這些都是傳統(tǒng)的JavaWeb提供的技術。
????JWT令牌、阿里云OSS對象存儲服務,是現在企業(yè)項目中常見的一些解決方案。
????IOC控制反轉DI依賴注入、AOP面向切面編程、事務管理、全局異常處理、攔截器等,這些技術都是 Spring Framework框架當中提供的核心功能。
????Mybatis就是一個持久層的框架,是用來操作數據庫的。

????在Spring框架的生態(tài)中,對web程序開發(fā)提供了很好的支持,如:全局異常處理器、攔截器這些都是Spring框架中web開發(fā)模塊所提供的功能,而Spring框架的web開發(fā)模塊,我們也稱為:SpringMVC

【JavaWeb后端開發(fā)-第七章】SpingBoot原理,JavaWeb學習,spring boot,后端,java

SpringMVC不是一個單獨的框架,它是Spring框架的一部分,是Spring框架中的web開發(fā)模塊,是用來簡化原始的Servlet程序開發(fā)的。

????外界俗稱的SSM,就是由:SpringMVCSpring Framework、Mybatis三塊組成。
????基于傳統(tǒng)的SSM框架進行整合開發(fā)項目會比較繁瑣,而且效率也比較低,所以在現在的企業(yè)項目開發(fā)當中,基本上都是直接基于SpringBoot整合SSM進行項目開發(fā)的。

????到此我們web后端開發(fā)的內容就已經全部講解結束了。


資料來源:b站黑馬程序員文章來源地址http://www.zghlxwxcb.cn/news/detail-807653.html


到了這里,關于【JavaWeb后端開發(fā)-第七章】SpingBoot原理的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【鴻蒙開發(fā)】第七章 ArkTS語言UI范式-基礎語法

    【鴻蒙開發(fā)】第七章 ArkTS語言UI范式-基礎語法

    通過前面的章節(jié),我們基本清楚鴻蒙應用開發(fā)用到的語言和項目基本結構,在【鴻蒙開發(fā)】第四章 Stage應用模型及項目結構也提到過ArkTS的UI范式的 基本語法 、 狀態(tài)管理 、 渲染控制 等能力,簡要介紹如下: 基本語法 : ArkTS 定義了 聲明式UI描述 、 自定義組件 和 動態(tài)擴展

    2024年02月03日
    瀏覽(24)
  • Qt5開發(fā)及實例V2.0-第七章-Qt圖形視圖框架

    Qt5開發(fā)及實例V2.0-第七章-Qt圖形視圖框架

    7.1.1 Graphics View的特點 Graphics View框架結構的主要特點如下。 (1)Graphics View框架結構中,系統(tǒng)可以利用Qt繪圖系統(tǒng)的反鋸齒、OpenGL工具來改善繪圖性能。 (2)Graphics View支持事件傳播體系結構,可以使圖元在場景(scene)中的交互能力提高1倍,圖元能夠處理鍵盤事件和鼠標事

    2024年02月07日
    瀏覽(19)
  • 第七章:敏捷開發(fā)工具方法-part2-CI/CD工具介紹

    第七章:敏捷開發(fā)工具方法-part2-CI/CD工具介紹

    什么是CI/Cd? CI-Continuous integration : 持續(xù)集成 是指多名開發(fā)者在開發(fā)不同功能代碼的過程當中,可以頻繁的將代嗎行合并到一起并切相互不影響工作。 CD-continuous deployment : 持續(xù)部署 是基于某種工具或平臺實現代碼自動化的構建、測試和部署到線上環(huán)境以實現交付高質量的

    2024年02月09日
    瀏覽(29)
  • 第七章 圖論

    第七章 圖論

    第七章 圖論 一、數據結構定義 圖的鄰接矩陣存儲法 圖的鄰接表存儲法 把所有節(jié)點存儲為節(jié)點數組,每個節(jié)點里有自己的數據和一個邊指針,這個邊指針相當于一個鏈表的頭指針,這個鏈表里存放所有與這個節(jié)點相連的邊,邊里存放該邊指向的節(jié)點編號和下一條邊指針 圖的

    2024年02月14日
    瀏覽(79)
  • 第七章 函數矩陣

    第七章 函數矩陣

    和矩陣函數不同的是,函數矩陣本質上是一個矩陣,是以函數作為元素的矩陣。 矩陣函數本質上是一個矩陣,是以矩陣作為自變量的函數。 函數矩陣和數字矩陣的運算法則完全相同。 不過矩陣的元素 a i j ( x ) a_{ij}(x) a ij ? ( x ) 需要是閉區(qū)間 [ a , b ] [a,b] [ a , b ] 上的實函數

    2024年02月04日
    瀏覽(22)
  • 第七章金融中介

    ?? ? ? ? 金融中介是通過向資金盈余者發(fā)行 間接融資合約( 如存款單),并和資金短缺者達成 間接投資合約 (發(fā)放信貸)或購買其發(fā)行的證券,在資金供求方之間融通資金,對資金跨期、跨域進行優(yōu)化配置的金融機構。 ? ? ? ? 金融體系由金融市場和金融中介構成,以銀行業(yè)為

    2024年02月04日
    瀏覽(27)
  • python第七章(字典)

    python第七章(字典)

    一。字典(類型為dict)的特點: 1.符號為大括號 2.數據為鍵值對形式出現 3.各個鍵值對之間以逗號隔開 格式:str1={\\\'name\\\':\\\'Tom\\\'}? name相當于鍵值(key),Tom相當于值 二??兆值涞膭?chuàng)建方法 三。字典的基本操作(增刪改查) 1.字典的增加操作:字典序列[key] = 值 注意點:如果存

    2024年01月24日
    瀏覽(46)
  • 第七章 測試

    第七章 測試

    7.1.1 選擇程序設計語言 1. 計算機程序設計語言基本上可以分為匯編語言和高級語言 2. 從應用特點看,高級語言可分為基礎語言、結構化語言、專用語言 01 有理想的模塊化機制; 02 可讀性好的控制結構和數據結構; 03 便于調試和提高軟件可靠性; 04 編譯程序發(fā)現程序錯誤的

    2024年02月08日
    瀏覽(29)
  • [JavaScript] 第七章 對象

    [JavaScript] 第七章 對象

    ??作者主頁:青花鎖 ??簡介:Java領域優(yōu)質創(chuàng)作者??、Java微服務架構公號作者?? ??簡歷模板、學習資料、面試題庫、技術互助 ??文末獲取聯系方式 ?? [Java項目實戰(zhàn)] 介紹Java組件安裝、使用;手寫框架等 [Aws服務器實戰(zhàn)] Aws Linux服務器上操作nginx、git、JDK、Vue等 [Java微服務

    2024年02月02日
    瀏覽(61)
  • 數據結構第七章

    數據結構第七章

    圖(Graph)G由兩個集合V和E組成,記為G=(V, E),其中V是頂點的有窮非空集合,E是V中頂點偶對的有窮集合,這些頂點偶對稱為邊。V(G)和E(G)通常分別表示圖G的頂點集合和邊集合,E(G)可以為空集。若EG)為空,則圖G只有頂點而沒有邊。 子圖:假設有兩個圖G=(V,E)和G1=(V1,E1);如果V1

    2024年02月03日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包