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
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...