Spring IOC 複習

来源:https://www.cnblogs.com/whteway/archive/2019/12/11/12019734.html
-Advertisement-
Play Games

Inversion of Control 將創建對象的權利交給框架,包括DI(Dependency Injection,依賴註入)和DL(Dependency Lookup,依賴查找),能削減電腦程式的耦合,即解除代碼中的依賴關係 應用 xml 1. 建立maven工程 2. 導入jar包,pom ...


Inversion of Control

將創建對象的權利交給框架,包括DI(Dependency Injection,依賴註入)和DL(Dependency Lookup,依賴查找),能削減電腦程式的耦合,即解除代碼中的依賴關係

應用

xml

  1. 建立maven工程

  2. 導入jar包,pom.xml中加入spring-context依賴

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
  3. 創建配置文件,在resources目錄下新建bean.xml文件,並導入約束

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    </beans>
  4. 配置bean,在bean.xml中的beans標簽中加入bean標簽配置bean

    1. 使用預設構造函數,如果類中無預設構造函數則無法創建
    <bean id="bean的唯一標識(名字)" class="全限定類名"></bean>
    1. 使用某個類(工廠)的某個方法創建對象
    <bean id="beanId" factory-bean="工廠類的全限定類名" factory-method="方法名"></bean> 
    1. 使用某個類(靜態工廠)的某個靜態方法創建對象
    <bean id="beanId" class="全限定類名" factory-method="方法名"></bean>

    bean標簽還有兩個屬性init-method和destroy-method指定構造方法和銷毀方法

  5. 依賴註入

    在bean中需要的數據或其他類的對象都由spring提供,只需配置,但不適合註入常變的數據

    能註入的數據有三類:基本類型和String,其他bean,複雜類型/集合類型

    註入方式有三種,在bean標簽內用一個標簽代表一個參數:

    構造函數註入

    <constructor-arg type(不常)="類型的全限定名" index(不常)="參數序號,從0開始" name(常用)="參數名" value="基本類型值" ref="引用其他bean"></constructor-arg>

    ​ 優:獲取bean對象時註入數據是必須的,否則無法創建成功

    ​ 弊:改變了bean的實例化方式,在創建對象時如果用不到這些數據也必須提供

    set方法註入(常用)

    <property name="set方法對應名" value="基本類型值" ref="其他bean"></property>

    ​ 優:創建對象時沒有明確的限制,可以直接使用預設構造函數

    ​ 弊:set方法可能不執行,如果某個成員必須有值,此方法不能保證

    複雜類型的註入需要在參數標簽中再加標簽array,list,set,map,props

    <property name="listPropName">
        <array>
            <value>...</value>
            ...
        </array>
    </property>
    <property name="mapPropName">
        <map>
            <entry key="keyName" value="值"></entry>
            <entry key="keyName">
                <value>值</value>
            </entry>
        </map>
    </property>

    ​ List結構的用list,array,set都一樣,Map結構的用map,props都一樣

  6. 獲取bean,在java代碼中

    //獲取核心容器對象,也可以用BeanFactory代替ApplicationContext
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    //根據id獲取Bean對象
    ClassOfBean bean = (ClassOfBean)ac.getBean("beanId");
    • ApplicationContext的三個常用實現類

    ​ ClassPathXmlApplicationContext: 可以載入類路徑下的配置文件

    ​ FileSystemXmlApplicationContext: 可以載入磁碟任意路徑(有訪問許可權)下的配置文件

    ​ AnnotationConfigApplicationContext: 用於讀取註解創建容器

    • ApplicationContext和BeanFactory的區別

    ​ 前者在構建容器時採用立即載入的方式,一讀取完配置文件就馬上創建bean

    ​ 後者在構建視窗時採用延遲載入的方式,當獲取bean時才真正創建對象

註解

用xml文件 bean.xml文件中的約束的標簽為

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 告知spring在創建容器時要掃描的包 -->
    <context:component-scan base-package="包路徑"></context:component-scan>
</beans>

不用xml文件

創建一個配置類,類上加

@Configuration指定當前類是一個配置類,獲取容器時作為參數傳入的配置類可以不加

@ComponentScan(basePackages="包路徑")指定要掃描的包,basePackages可以換成value

​ 獲取容器時用new AnnotationConfigApplicationContext(配置類.class)

@Import 導入其他配置類,被導入的類不用再加@Configuration

@PropertySource("classpath:路徑/文件名") 用指定properties文件的位置,屬性value

@PropertySources 有多個properties文件的時候用

​ 導入配置文件後可以用@Value(${...})讀取

與bean有關的註解
  • @Bean 用於將當前方法的返回值作為bean存入ioc容器中,屬性name指定beanId預設值為當前方法的名稱,如果方法有參數,spring框架會去容器中查找 有沒有可用的bean對象,查找方式同Autowired

  • 用於創建對象的,相當於bean標簽

    @Component 作用:把當前對象存入spring容器中;屬性:value:指定bean的id,預設是當前類名且首字母小寫;@Controller @Service @Repository與@Component完全一樣,體現三層架構

  • 用於註入數據的,相當於property標簽

    @Autowired 作用:自動按照類型註入,如果容器中有唯一一個類匹配該數據的類型則註入,若沒有匹配類型則報錯,如果有多個則通過變數名尋找beanId對應的那個bean註入;位置:類上,方法上,變數上

    @Qualifier 作用:在按照類型註入的基礎上再按照名稱註入,在給類成員註入時不能單獨使用必須和@Autowired一起,但在給方法參數註入時可以;屬性:value用於指定beanId

    以上三種只能註入bean,不基本類型和String,複雜類型必須用xml配置

    @Value 作用:用於註入基本類型和String;屬性:value用於指定數據的值,可以使用SpEL(spring的EL表達式:${表達式})

    @Resource 作用:直接按照bean的id註入,可以獨立使用;屬性:name指定beanId

  • 用於改變作用範圍的,相當於bean標簽的scope屬性

    @Scope 作用:指定bean的作用範圍;屬性:value一般取singleton(預設)或prototype

  • 和生命周期相關的,相當於bean標簽的init-method和destroy-method屬性(不常用)

    @PostConstruct

    @PreDestroy


與Junit整合

  1. 添加spring-test和junit依賴,spring5.x要求junit 4.12及以上

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
  2. 使用Junit提供的一個註解@RunWith把原有的main方法替換成spring提供的

    @RunWith(SpringJUnit4ClassRunner.class)

  3. 告知spring的運行器,是基於xml還是註解,並說明位置

    @ContextConfiguration

    ​ locations: 指定xml文件位置

    ​ classes: 指定註解類所在位置

常見問題

  • bean的作用範圍

    ​ bean標簽和@Component註解的scope屬性:用於指定bean的作用範圍

    ​ 取值:singleton 單例的(常用)

    ​ prototype 多例的(常用)

    ​ request 作用於web應用的請求範圍

    ​ session 作用於web應用的會話範圍

    ​ global-session 集群環境的會話範圍(全局會話範圍),若不是集群環境,則為session

  • bean的生命周期

    ​ singleton: 容器創建時對象創建(ApplicationContext),容器銷毀時對象銷毀

    ​ prototype: 使用對象時創建對象,當對象長時間不用且長時間沒有別的對象引用時,由java的垃圾回收器回收


原理

  • ioc只需要導入spring-context依賴

  • 閱讀源碼:github下載源碼,導入idea,運行調試加註釋

  • spring項目啟動後,會掃描所有類,找到符合bean標準(加註釋或xml配置)的類,通過一個描述類(BeanDefinition)存放bean的信息,isSingleton屬性預設為true,再將描述類存入一個map(BeanDefinationMap)中

  • 掃描之後bean的獲取:通過BeanDefinationMap里的key(bean名)找到value(BeanDefination)的class屬性進行反射,找到bean對應的類。與class名沒有關係,可以通過自己實現BeanFactory介面,從beanFactory中獲取描述類BeanDefinition,setBeanClass(another.class)將bean和class的對應關係更改

  • 掃描前BeanDefinationMap中已有7個bean,包括AppConfig

  • main() --> AnnotationConfigApplicationContext(AppConfig.class) --> refresh() --> invokeBeanFactoryPostProcessors(beanFactory)(掃描並存入bean)

  • 後置處理器BeanPostProcessors的子類會被自動掃描並對bean進行多層代理,預設有九次(進入依賴註入等操作),實現此介面可以對bean的創建過程進行干預

  • Spring上下文或環境:為了實現IOC或AOP所需要的各種Spring組件的集合,如BeanDefination,BeanPostProcessor(後置處理器),DefaultListableBeanFactory,BeanDefinitionMap,單例池等等

  • 掃描只是將bean對應的類的信息存入map中,並不會實例化類,即lazy(懶載入)

  • factoryBean是一個特殊的bean,beanFactory是bean工廠

  • 單例bean第一次被實例化後就會存入名為singleObjects的map(單例池)中,再次getBean()時就不會new,(保證單例)

  • Spring容器:不止單例池,還包括其他IOC組件

  • 迴圈依賴:

    單例bean的迴圈依賴

    isSingletonCurrentlyInCreation判斷這個bean是否在創建過程中

    單例池只存放完整的bean

    get(A) --> new A --> auto B --> get(B) --> new B --> auto A --> get(A)

    獲取A,新建A,發現A需要註入B且單例池中沒有B且B不在創建過程中,獲取B,發現B需要註入A且單例池中沒有A且A正在創建過程中,獲取A並註入B,將B註入A,將A放入單例池


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 使用eXpressApp框架構建的應用程式由幾個功能塊組成。下圖顯示了基本塊,指出了何時以及如何創建這些塊,最後顯示了可以擴展應用程式的領域。本主題後面將給出每個應用程式構建塊的概述。 ...
  • ```java /* java.lang.Math類是數學相關的工具類,裡面提供的大量靜態方法,完成與數學運算的操作 public static double abs(double num):獲取絕對值。 public static double ceil(double num):向上取整。 pub... ...
  • 哈希表是個啥? 小白 : 慶哥,什麼是哈希表?這個哈希好熟悉,記得好像有HashMap和HashTable之類的吧,這是一樣的嘛?
  • 一、類之間的關係 1.泛化關係(UML圖:實線空心三角形箭頭,箭頭指向被繼承方) 類和類、介面與介面之間的繼承稱為泛化關係 public class A {} class B extends A{} public interface A{} class B extends A{} 2.實現關係(​U ...
  • 在開發web的時候,如果是以前已存在的項目,項目下載下來後,為了使用測試庫的數據,會直接將整個測試庫(如sqlite3)拿到本機來。這種情況下,如果執行的順序不對,很容易在執行migrate的時候出現資料庫已存在的錯誤: django.db.utils.OperationalError: (1050 ...
  • model詳解 Django中遵循 Code Frist 的原則,即:根據代碼中定義的類來自動生成資料庫表。 創建表 基本結構 from django.db import models # Create your models here. class userinfo(models.Model): ...
  • 第一步: 刪除該app名字下的migrations文件。 第二步: 進入資料庫,找到django_migrations的表,刪除該app名字的所有記錄。 delete from django_migrations; 第三步: python manage.py makemigrations pytho ...
  • 前兩天剛和媳婦兒從福岡旅游回來,這次久違的再去日本,感受良多啊! 首先是心情,之前是拿了老爸和自己所有的積蓄去上學,有一種為了人生未來而背水一戰的包袱在身上 結果遇到金融危機,沒有錢提前付下一年的學費也沒有時間找工作,最後不得不回國,失敗了! 這次和媳婦去玩,一切行程都是媳婦安排,從機票到大巴票到三 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...