【微服務專題】SpringBoot自動配置源碼解析

目錄

  • 前言
  • 閱讀對象
  • 閱讀導航
  • 前置知識
  • 筆記正文
    • 0、什么是自動配置
      • 0.1 基本概念
      • 0.2 SpringBoot中的【約定大于配置】
      • 0.3 從SpringMVC看【約定大于配置】
      • 0.4 從Redis看【約定大于配置】
    • 一、@EnableAutoConfiguration源碼解析
    • 二、SpringBoot常用條件注解源碼解析
      • 2.1 自定義條件注解
      • 2.2 @ConditionalOnClass原理解析
      • 2.3 ConditionalOnBean原理解析
    • 三、SpringBoot之Mybatis自動配置源碼解析
    • 四、SpringBoot之AOP自動配置源碼解析
    • 五、SpringBoot Jar包啟動過程源碼解析
  • 學習總結
  • 感謝

前言

想要搞懂自動裝配,需要當前系列前兩篇筆記內容打底。不過我上一篇筆記寫的不好,沒有什么突出的重點,主要也是當時跟著課程看了源碼之后,也沒發現什么特別的,直到在看自動裝配源碼的時候,才后知后覺遺漏了一些重要的知識點。但是總體來說不影響這一節課的筆記記錄吧。

閱讀對象

閱讀導航

系列上一篇文章:《【微服務專題】Spring啟動過程源碼解析》

前置知識

筆記正文

0、什么是自動配置

我們說起SpringBoot,總會不自覺的聯想到自動配置約定大于配置等標簽,但說實在,我是有一點困惑的,這個【約定和配置】到底是什么意思,或者說,它們具體指的是哪些內容啊?!
我在想,像我這種,只是用過那么一年多SSM/SSH,甚至完全沒有經歷過的人來說,是很難理解的。雖然我也確實經歷過SSM/SSH,但那時候初出茅廬,根本就沒在意過這些玩意好吧…

不過話說回來,后面再回來繼續做Java的時候,已經是SpringBoot的時代了嘛,所以單從片面印象來說的話:SpringBoot確實方便了很多。最最最直觀的就是啟動,給我的感覺啟動一個web應用跟簡單運行了一個main方法一樣便捷。而在以前SSM/SSH時代,各種眼花繚亂的xml配置,還有那個令人煩躁的tomcat配置,就已經讓我很難受了。

好吧,不懂嘛,于是我就去稍微學習了一下。下面,我就按照我自己的理解,再拼上一些百度的、起碼能說服我自己的答案給大家說道說道。另外,也想舉一個真正直觀的例子給大家說說,【約定和配置】到底使了什么魔法

0.1 基本概念

【約定大于配置】是一種開發思想、設計理念,它強調使用默認約定和規則,減少開發者需要做的【顯式】配置。根據這一原則,大部分情況下,開發者只需關注那些【不符合默認約定】的配置,而不需要為每個細節都進行顯式配置。

開天眼給大家說一下:既然結果是減少了需要程序員【顯示】配置的工作量,那反過來就證明了,在SpringBoot之前的時代,有一些配置是不得不(必須)需要程序員去配置的!
另外,這里說的【配置】,不是指xml配置,而是對引入的服務的所有形式的配置,xml只是一種介質而已,我們還可以是txtyml,還有java文件的配置方式。
我認為這個結論很重要!我后面研究案例就是往這方向去看的

綜上所述,可以這樣簡單地理解【約定】和【配置】:

  1. 默認規則
  2. 【顯示】配置(不得不設置的配置 / 沒辦法使用默認規則的配置)。這里說的【配置】,不是指具體的xml配置,而是對引入的服務的【所有形式】的配置,xml只是其中一種形式而已,配置還可以是txtyml,包括java文件的配置形式。

這個理念,有如下顯著的優勢:

  1. 提高開發效率: 通過遵循默認約定,開發者可以快速啟動項目并進行開發,無需花費大量時間在繁瑣的配置上
  2. 減少決策負擔: 【約定大于配置】減少了開發者需要做出的決策,使開發過程更加流暢,不需要在每個細節上做出選擇
  3. 減少錯誤: 默認約定可以減少配置錯誤的機會,因為開發者只需要在特定情況下進行配置,從而降低了出錯的可能性

0.2 SpringBoot中的【約定大于配置】

我們都知道,SpringBoot是基于Spring的,嚴格來說,SpringBoot的出現其實是為了降低Spring的使用門檻。

  1. 使用maven的目錄結構。默認有src-main-resources文件夾,存放資源配置文件;src-main-java存放項目java源碼;target文件夾存放編譯、打包內容(其實,Maven的設計本身就是遵循【約定大于配置】的原則)

這是約定的一種,通過約定這些內容,使得項目結構統一,減少了開發人員學習成本。
試想一下,如果我們在不同的公司,他們的項目結構五花八門,甚至沒有src/main/resources,沒有src/main/java等目錄,你學習成本是不是變高了??博主之前寫過2、3年C/C++,那時候接觸的項目就是這個鳥樣子的,都是自定義資源存放目錄,打包目錄,源碼目錄,真的吐血… … 我轉戰Java很大一個原因就是奔著Java的規范性去的。當然,我現在相當后悔…

  1. 使用application.properties/yml文件設置配置內容

這也是一種約定,拒絕程序員五花八門的配置文件

  1. 默認使用Tomcat容器

接觸過SSM嗎?SSM項目通常來說,需要額外配置啟動一個Tomcat,然后將SSM項目打包部署到Tomcat上
而在SpringBoot中,我們啟動項目就跟運行一個普通的main函數一樣

  1. 提供了大量的自動配置接口,自動配置類,注解等,幫助程序員配置。嚴格來說,自動配置接口以及注解等,都是為了自動配置類服務的。SpringBoot提供的大量自動配置類,在里面默認設置了很多值用以配置第三方接口服務,這些默認配置甚至能讓開發做到開箱即用,只有一些不得不需要用戶設置的內容才需要開發人員自己設置。這就是上面概念所謂的開發者只需要關注那些不符合默認約定的配置的意義。

這是SpringBoot【約定大于配置】的重要實現。我們先稍微解釋一下,這些所謂的接口、類、注解是指什么:

  • 自動配置接口:AutoConfigurationImportFilter、AutoConfigurationImportListener等
  • 自動配置類:DispatcherServletAutoConfiguration、HttpEncodingAutoConfiguration等
  • 注解:諸如@AutoConfiguration、@AutoConfigurationPackage等

    上述我只是簡單列舉了一些內容而已,其實具體的,可以看:org.springframework.boot:spring-boot-autoconfigure這個包。里面就是SpringBoot為大家做自動配置提供的默認配置,和相關接口

0.3 從SpringMVC看【約定大于配置】

說實在,SpringMVC我不是很熟悉,所以我不是很保證自己說的是對的,在網上也沒看到非常令人信服的答案。但是關于【約定大于配置】的體現我覺得還是正確的。

有人說spring-boot-starter-web其實就是面配置的SSM。在SSM時代,我們想要開發一個web應用,免不了如下配置:

  1. 新增web.xml,在里面配置前端控制器DispatcherServlet、視圖解析器ViewResolver、過濾器等
  2. 新增核心配置文件**-servlet.xml
  3. Tomcat容器的配置
  4. 等等…

其實說需要新增這種那種xml配置是有點狹隘的說法,我前面說過了xml只是其中一種配置形式而已。
準確來說,傳統的SSM項目,需要我們開發人員顯式、準確地向Spring容器注冊DispatcherServletViewResolverSqlSessionFactoryBeanDriverManagerDataSource
如果我們沒有【顯式】地去聲明、注冊這些Bean,那我們項目直接啟動失敗!他會說找不到這個找不到那個。但是,在SpringBoot中,我們只需要在pom中引入spring-boot-starter-web就可以了,這個jar包,會自動向Spring中注冊上述關鍵bean

怎么注冊?我們簡單看一下關于SpringMVC的自動配置類。

1)WebMvcAutoConfiguration.java:SpringMVC的自動配置入口
在這里插入圖片描述
在這里我們無需關心上面的諸多注解的具體含義先,具體意義我會在后面的源碼解析中介紹。
但是可以預見的是,在某種情況下,spring-boot-stater-web會進入DispatcherServletAutoConfiguration.class里面

2)DispatcherServletAutoConfiguration.java:在這里,有一個@Bean,暫不關心他什么時候會被觸發,但至少可以預見的是:在某種情況下,DispatcherServletAutoConfiguration類會向Spring中注冊一個DispatcherServlet類型的bean
在這里插入圖片描述
啊,對的,本質上就是如此而已。SpringBoot的自動配置,實際上就是SpringBoot的源碼中預先寫好了一些配置類,預先定義好了一些Bean,我們在用SpringBoot時,這些配置類就已經在我們項目的依賴中了,而這些自動配置類或自動配置Bean到底生不生效,就看具體所指定的條件了。

不過還有一點需要說明,那就是SpringBoot可不是簡簡單單的給你注冊了一個默認的bean,它還會給部分【符合約定】的基礎參數設置默認的、至少有意義的、比較符合一般應用的初始值來初始化bean。這個就是SpringBoot提供的各種XxxProperties.java。例如:WebMvcProperties
在這里插入圖片描述
O對了,說到了這個XxxProperties.java文件,其實它也是約定的一種體現。以前SSM我們相當于直接配置了服務接口的一些參數;而在SpringBoot里面,我們直接配置的其實是XxxProperties,然后再由SpringBoot使用XxxProperties配置屬性去初始化服務接口參數。而通常這些XxxProperties對應的是application.properties里面的一些配置內容。
相比起直接配置服務接口參數,XxxProperties可讀性更強,使用也更簡單。

0.4 從Redis看【約定大于配置】

省略

OK,關于SpringBoot中的【約定大于配置】就介紹到這里了。那他們是怎么實現的呢?有經驗的朋友,或者稍微細心的朋友估計也從上圖看到了,主要是靠下圖這些類、接口、注解:org.springframework.boot:spring-boot-autoconfigure包下
在這里插入圖片描述

一、@EnableAutoConfiguration源碼解析

二、SpringBoot常用條件注解源碼解析

SpringBoot中的常用條件注解有:

  • ConditionalOnBean:是否存在某個某類或某個名字的Bean
  • ConditionalOnMissingBean:是否缺失某個某類或某個名字的Bean
  • ConditionalOnSingleCandidate:是否符合指定類型的Bean只有一個
  • ConditionalOnClass:是否存在某個類
  • ConditionalOnMissingClass:是否缺失某個類
  • ConditionalOnExpression:指定的表達式返回的是true還是false
  • ConditionalOnJava:判斷Java版本
  • ConditionalOnWebApplication:當前應用是不是一個Web應用
  • ConditionalOnNotWebApplication:當前應用不是一個Web應用
  • ConditionalOnProperty:Environment中是否存在某個屬性
  • 當然我們也可以利用@Conditional來自定義條件注解

條件注解是可以寫在類上和方法上的,如果某個條件注解寫在了自動配置類上,那該自動配置類會不會生效就要看當前條件能不能符合;或者條件注解寫在某個@Bean修飾的方法上,那這個Bean生不生效就看當前條件符不符合。

具體原理是:

  1. Spring在解析某個自動配置類時,會先檢查該自動配置類上是否有條件注解,如果有,則進一步判斷該條件注解所指定的條件當前能不能滿足,如果滿足了則繼續解析該配置類,如果不滿足則不進行解析了,也就是配置類所定義的Bean都得不到解析,也就是相當于沒有這些Bean了。
  2. 同理,Spring在解析某個@Bean的方法時,也會先判斷方法上是否有條件注解,然后進行解析,如果不滿足條件,則該Bean不會生效

2.1 自定義條件注解

SpringBoot中眾多的條件注解,都是基于Spring中的@Conditional來實現的,我們先來用一下@Conditional注解。
先來看下@Conditional注解的定義:

/*** * 指示組件只有在所有指定條件匹配時才有資格注冊。* 條件是可以在注冊bean定義之前以編程方式確定的任何狀態(有關詳細信息,請參閱條件)。* @Conditional注釋可以以以下任何一種方式使用:* 在任何直接或間接用@Component注釋的類(包括@Configuration類)上作為類型級注釋* 作為元注釋,用于組合自定義構造型注釋* 作為任何@Bean方法上的方法級注釋* 如果@Configuration類被標記為@Conditional,那么與該類關聯的所有@Bean方法、@Import注釋和@ComponentScan注釋* 將受這些條件的約束。*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {/*** All {@link Condition} classes that must {@linkplain Condition#matches match}* in order for the component to be registered.*/Class<? extends Condition>[] value();}

根據定義我們在用@Conditional注解時,需要指定一個或多個Condition的實現類,所以我們先來提供一個實現類:

public class ShenCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Map<String, Object> component = metadata.getAnnotationAttributes("org.springframework.stereotype.Component");System.out.println("下面開始打印condition里面的內容");System.out.println(component);Object value = component.get("value");return value.toString().equals("shen");}
}

上面這個實現類很簡單,就是獲取被@Conditional(ShenCondition.class)注解的類上,獲取它@Component上的注解值,如果值是shen那就返回true,否則bean注冊不成功。測試用例如下:

@Conditional(ShenCondition.class)
@Component("shen")
public class ShenWorker {public String sayHello() {return "hello";}
}@SpringBootApplication(scanBasePackages = "org.example.springboottest")
public class ShenMyApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(ShenMyApplication.class);ShenWorker shen = (ShenWorker) context.getBean(ShenWorker.class);System.out.println("------------------------");System.out.println(shen.sayHello());}
}

此時運行,控制臺輸出:
在這里插入圖片描述
把上面的ShenWorker @Component值改成其他,如@Component("shenWorker"),運行則輸出如下:
在這里插入圖片描述
報錯了,NoSuchBeanDefinitionException
我想到了這里大家應該多少知道@Conditional注解的作用了,接下來我們挑其中一兩個SpringBoot聲明的條件注解,看一下源碼,剖析一下它是怎么實現的。

2.2 @ConditionalOnClass原理解析

@ConditionalOnClass注解的作用是:校驗是否存在某個類。

Spring這種優秀源碼,通常注釋都是很完善的,我們先來看看它們是怎么定義的:

/*** @Conditional,當且僅當指定的類在類路徑上時,才匹配成功** value()可以在@Configuration類上安全地指定,因為在加載類之前,* 會使用ASM解析注釋元數據。當放置在@Bean方法上時,需要特別注意,* 考慮在單獨的Configuration類中隔離條件,特別是如果方法的返回類型與條件的目標匹配*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {/*** 必須設置的class信息。* 因為這個注釋是通過加載類字節碼來解析的(classLoader.loadClass),* 當且僅當這個注解直接作用在bean上,而不是當這個注解被用作組合的元注釋時,* 在這里指定最終可能不在classpath上的類是安全的(不會報錯)。* 想要將此注解用作元注釋,那么就只使用name屬性*/Class<?>[] value() default {};/*** 必須設置的類全限定名*/String[] name() default {};
}

根據我們自定義注解經驗,該注解的實現肯定是在@Conditional(OnClassCondition.class)OnClassCondition.class中。
順便在這里介紹一下怎么用idea追蹤代碼吧。

1)尋找關鍵實現類
首先我們知道,OnClassCondition.class實現自Condition接口,主要是實現里面的matches()方法。雖然咱還不知道它是在哪里被Spring調用的,但起碼他肯定是會被調用的對吧,所以,我們先跳到OnClassCondition.class文件,打開它的繼承圖,如下所示:
在這里插入圖片描述
可以發現它繼承或者實現了各種各樣的接口,其中一個是Condition。那OK
我們在回到OnClassCondition.class文件,alft+7打開代碼結構圖,然后在右上角點擊查看繼承過來的屬性、方法,如下所示:
在這里插入圖片描述
如上圖所示,綠色框內灰色的即為繼承過來,但是沒有重寫的方法。可以看到Condition接口的matches方法,就沒有被重寫過,那說明父類中肯定有默認的實現類,點擊一下,會跳到SpringBootCondition類中,它的默認實現方式如下:
在這里插入圖片描述
可以看到,最重要的是紅框內的2行代碼。點擊getMatchOutcome發現這是一個抽象方法,所以,又回到OnClassCondition.class文件中,查找一下看看是否實現或者重寫了該方法。最后發現如下:
在這里插入圖片描述
重寫了,再結合之前的代碼可以判斷出來,這里就是OnClassCondition類的邏輯實現核心。上面的代碼其實也不難,基本上通過方法名就知道啥意思了。主要原理就是:使用反射工具,根據權限定名去JVM加載類。

特別注意:@ConditionalOnClass和@ConditionalOnMissingClass注解的核心實現都是這個類的這個方法

2.3 ConditionalOnBean原理解析

點擊查看@ConditionalOnBean注解,會發現邏輯是在OnBeanCondition.class中,然后按照上面的思路也會發現,它跟前面的注解基本一致,實現邏輯也是在getMatchOutcome中,如下:
在這里插入圖片描述
這個源碼略顯復雜,但是可以通過閱讀注解接口的各種字段信息,推斷出來具體過程。總的來說就是根據bean是否存在來返回結果。

特別注意:@ConditionalOnBean和@ConditionalOnSingleCandidate,@ConditionalOnMissingBean注解的核心實現都是這個類的這個方法

三、SpringBoot之Mybatis自動配置源碼解析

在我們的項目pom中,導入如下:

 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency>

我們就會看到我們項目依賴中出現以groupId+artifactId命名的jar包了,如下:
在這里插入圖片描述
對的,通常第三方在寫自動配置的時候,命名風格皆是如此。而在里面的MybatisAutoConfiguration即為Mybatis的自動配置類。通過源碼我們可以發現,在里面注冊了兩個bean,當然是有條件的:
在這里插入圖片描述
上面的意思是,在Spring中如果沒有SqlSessionFactory這個類型的bean,則注冊當前bean;
另一個注冊的bean如下:
在這里插入圖片描述
最核心的一個還是,在自動配置類下面有一個這玩意:
在這里插入圖片描述
這個 Bean的作用是,如果沒有其他顯式的注冊Mapper掃描映射器,那就注冊一個默認的Mapper掃描映射器,掃描路徑跟SpringBoot掃描路徑一致。說到這里,是不是有朋友對Mybatis如何實現把接口轉換成bean這個操作感興趣呢?大家伙可以看看按照下面這個軌跡從1-9-AB,自上而下去看看,但是需要一些Spring功底。源碼入口:MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar#registerBeanDefinitions(我有一點功底,但不算很扎實)
在這里插入圖片描述
總的來說,它的原大致如下:(注意,這里是指默認自動配置類情況下,如果使用了@MapperScan注解,情況略有不同)

  1. Mybatis自動配置類會向Spring容器注冊一個掃描器Bean定義,根據Bean定義,初始化掃描器屬性。默認掃描路徑是當前SpringBoot的掃描路徑
  2. Mybatis會修改掃描到Mapper接口的自動注入屬性
  3. Mybatis會修改注冊成為Bean的條件,原本接口類是不能夠被注冊成為Bean的,但是通過修改條件讓其通過了判斷
  4. 具體怎么生成的Bean我還沒去看…,睡覺了

四、SpringBoot之AOP自動配置源碼解析

未完待續…

五、SpringBoot Jar包啟動過程源碼解析

未完待續…

學習總結

感謝

感謝阿里云社區的文章《探索Spring Boot中的原則:約定大于配置》
感謝百度大佬【作者:編程師兄】的文章《SpringBoot約定大于配置到底是什么意思?》

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/168246.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/168246.shtml
英文地址,請注明出處:http://en.pswp.cn/news/168246.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java 反射和注解1-反射詳解

反射和注解本就是一家人&#xff0c;注解離不開反射&#xff0c;這里先將反射的寫法&#xff0c;本文涉到的注解暫時可以不不用理解 1&#xff0c;創建一個類 public class ReflexUser {public String name;private String namePrivate;protected String nameProtected;Strin…

Arduino庫之 LedControl 庫說明文檔

LedControl 庫最初是為基于 8 位 AVR 處理器的 Arduino 板編寫的。用于通過MAX7219芯片控制LED矩陣和7段數碼管。但由于該代碼不使用處理器的任何復雜的內部功能&#xff0c;因此具有高度可移植性&#xff0c;并且應該在任何支持 和 功能的 Arduino&#xff08;類似&#xff09…

模擬火車訂票系統---python序列

if __name__ __main__:#創建車輛信息列表list["車次","出發站-到達站","出發時間","到達時間","歷時","余票"]trainNumber[T40,T298,Z158,Z62]address[長春-北京,長春-北京,長春-北京,長春-北京]getTime[00:12,0…

簡單介紹一下js中的構造函數、原型對象prototype、對象原型__proto__、原型鏈

構造函數 function Star (uname, age){this.uname unamethis.age agethis.sing function(){ log(唱歌~) }}let xzq new Star(薛之謙, 30)let ldh new Star(劉德華, 20)log(ldh) // { uname: 劉德華, age: 20, sing: f }ldh.sing() // 唱歌~log(ldh.sing xzq.sing) // fal…

DevEco Studio安裝

HUAWEI DevEco Studio For OpenHarmony&#xff08;以下簡稱DevEco Studio&#xff09;是基于IntelliJ IDEA Community開源版本打造&#xff0c;面向OpenHarmony全場景多設備的一站式集成開發環境&#xff08;IDE&#xff09;&#xff0c;為開發者提供工程模板創建、開發、編譯…

uniapp時間選擇器

Uniapp 是一套基于Vue.js 開發的跨平臺開發框架&#xff0c;它能夠以一套代碼編譯成多個平臺的應用&#xff0c;包括 iOS、Android、H5 等。要實現時間選擇器可以使用uni-app提供的組件picker&#xff0c;它可以用于選擇器、時間選擇器、日期選擇器等場景。 以下是一個簡單的時…

Docker的簡單介紹

Docker是一個開源的應用容器引擎&#xff0c;讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中&#xff0c;然后發布到任何流行的Linux或Windows操作系統的機器上&#xff0c;也可以實現虛擬化。容器是完全使用沙箱機制&#xff0c;相互之間不會有任何接口。 Docker…

服務器被入侵了怎么去排查

在當今數字化時代&#xff0c;網絡安全問題變得越來越重要。其中&#xff0c;服務器被入侵是一種常見的安全威脅。當服務器被入侵時&#xff0c;我們需要采取一系列措施來排查和解決問題。本文將為您提供服務器被入侵后的排查步驟。 第一步&#xff1a;確認服務器被入侵 當發現…

用opencv繪制一個箭頭,沿著圓運動并留下運動軌跡(c++)

用opencv繪制一個箭頭&#xff0c;沿著圓運動并留下運動軌跡&#xff08;c&#xff09;。基于該例程可以簡單實現一個運動小車的模型。 using namespace cv;int main() {// 創建一個黑色背景的圖像&#xff0c;大小為400*400Mat image(400, 400, CV_8UC3, Scalar(0, 0, 0));//…

C語言進階之路-基本數據小怪篇

目錄 一、學習目標&#xff1a; 二、數據基本類型 整型 浮點型 / 實型 字符 字符串 布爾型數據 三、重要的雜七雜八知識點 常量與變量 標準輸入 sizeof運算符&#xff1a; 類型轉換 數據類型的本質 整型數據尺寸 可移植性整型 拿下第一個C語言程序 總結 一、學…

UE小計:頂部工具欄按鈕添加下拉列表,大綱列表、資源管理窗口右鍵添加按鍵

下拉列表 void FYouPluginsModule::StartupModule() {FYouToolStyle::Initialize();FYouToolStyle::ReloadTextures();FYouToolCommands::Register();PluginCommands MakeShareable(new FUICommandList);PluginCommands->MapAction(FYouToolCommands::Get().PackByCloudAc…

web前端之引入svg圖片、html引入點svg文件、等比縮放、解決裁剪問題、命名空間、object標簽、阿里巴巴尺量圖、embed標簽、iframe標簽

MENU 前言直接在頁面編寫svg使用img標簽引入通過css引入使用object標簽引入其他標簽參考資料 前言 web應用開發使用svg圖片的方式&#xff0c;有如下幾種方式 1、直接在頁面編寫svg 2、使用img標簽引入 3、通過css引入 4、使用object標簽引入 直接在頁面編寫svg 在html頁面直接…

LeetCode Hot100 101.對稱二叉樹

題目&#xff1a; 給你一個二叉樹的根節點 root &#xff0c; 檢查它是否軸對稱。 代碼&#xff1a; class Solution {public boolean isSymmetric(TreeNode root) {if(rootnull || (root.leftnull && root.rightnull)) {return true;}//用隊列保存節點LinkedList<…

高防CDN在網站搭建中的優劣勢分析

隨著網絡攻擊的日益增多和惡性化&#xff0c;網站安全性成為網站搭建中至關重要的一環。高防CDN&#xff08;Content Delivery Network&#xff09;作為一種有效的安全防護手段&#xff0c;扮演著保護網站免受惡意攻擊的角色。本文將從網站搭建的角度&#xff0c;深入分析高防C…

vue3+ts+vite 打包報錯 TS2304: Cannot find name ‘xxx‘

都說vue組合式api好&#xff0c;那必須來一套試試&#xff0c;而且element ui的demo全是lang"ts"了 改成組合式api沒問題&#xff0c;但是當加上lang"ts"之后就瘋狂報錯 src/components/table/tableshow.vue:7:28 - error TS2304: Cannot find name tempsh…

【網易云商】構建高效 SaaS 系統的技術要點與最佳實踐

SaaS 是什么 定義 相信大家都對云服務中的 IaaS、PaaS、SaaS 早就有所耳聞&#xff0c;現在更是衍生出了 aPaaS、iPaaS、DaaS 等等的類似概念。對于 SaaS 也有各種各樣的定義&#xff0c;本文給出的定義是&#xff1a; SaaS 是一種基于互聯網提供服務和軟件的交付模式&#xf…

水果編曲軟件FL Studio21.2下載安裝教程

簡稱FL&#xff0c;全稱&#xff1a;Fruity Loops Studio&#xff0c;因此國人習慣叫它"水果"。目前最新版本(包括測試版本)是FL Studio21.2&#xff0c;它讓你的計算機就像是全功能的錄音室&#xff0c;大混音盤&#xff0c;非常先進的制作工具&#xff0c;讓你的音…

工業以太網交換機未來發展中的幾個趨勢

隨著工業自動化不斷發展和智能制造的推進&#xff0c;工業以太網交換機在未來的應用中將面臨更多的發展機遇和挑戰。在工業以太網交換機的未來發展中&#xff0c;有幾個方面將成為趨勢。 網絡虛擬化 隨著工業自動化系統規模的不斷擴展&#xff0c;網絡虛擬化將成為未來的發展方…

總結1065

今日共計學習11h47m&#xff0c;今日圖書館冷清了不少&#xff0c;在最后關頭&#xff0c;越學心里越沒譜。做22年的真題做到懷疑人生&#xff0c;真題每年難度不一&#xff0c;可以出的很難&#xff0c;也可以出得相對簡單。出的難的&#xff0c;計算量大肯定是其中一部分。今…

四、防火墻-NAT Server

學習防火墻之前&#xff0c;對路由交換應要有一定的認識 NAT Server1.1.基本原理1.2.多出口場景下的NAT Server1.3.源進源出 —————————————————————————————————————————————————— NAT Server 一般對用戶提供一些可訪問的…