Spring配置相關

不柴發表於2024-05-01

Spring

  • Spring技術是JavaEE開發必備技能,企業開發技術選型命中率>90%
  • 專業角度
    • 簡化開發:降低企業級開發的複雜性
    • 框架整合:高效整合其他技術,提高企業級應用開發與執行效率

初識Spring

瞭解Spring家族

  • Spring官網:https://spring.io/
  • Spring發展到今天已經形成了一種開發的生態圈,Spring提供了若干個專案,每個專案用於完成特定的功能
  • 重點學習
    • Spring Framework
    • Spring Boot
    • Spring Cloud

Spring Framework

Spring Framework系統架構

  • SpringFramework是Spring生態圈中最基礎的專案,是其他專案的根基

Spring Framework系統架構圖:

image.png

核心概念

  • IoC/DI
  • IoC(InversionofControl)控制反轉
    • 使用物件時,由主動new產生物件轉換為由外部提供物件,此過程中物件建立控制權由程式轉移到外部,此思想稱為控制反轉
  • Spring技術對Ioc思想進行了實現
    • Spring提供了一個容器,稱為Ioc容器,用來充當Ioc思想中的"外部
    • Ioc容器負責物件的建立、初始化等一系列工作,被建立或被管理的物件在Ioc容器中統稱為Bean
  • DI(DependencyInjection)依賴注入
    • 在容器中建立bean與bean之間的依賴關係的整個過程,稱為依賴注入
  • 目的:充分解耦
    • 使用Ioc容器管理bean(IoC)
    • 在Ioc容器內將有依賴關係的bean進行關係繫結(DI)

IoC入門

1、利用Maven匯入Spring的座標 spring-context

<dependency>  
    <groupId>org.springframework</groupId>  
    <artifactId>spring-context</artifactId>  
    <version>6.1.6</version>  
</dependency>

2、建立配置檔案:在 resources 目錄下建立 applicationContext.xml 檔案。

3、配置bean

# bean標籤標識配置bean
# id屬性表示bean的名字
# class屬性表示bean的定義型別

<bean id="" class=""></bean>

# 注意:bean定義時id屬性在同一個上下文中不能重複

4、獲取Ioc容器

public static void main(String args[]){
	//獲取IoC容器
	//ApplicationContext是一個介面,我們new一個它的實現物件
	//引數是我們的配置檔案
	ApplicationContext ctx = new ClassPathXmlApplicationContext
	("applicationContext.xml");
	//獲取bean
	//xml檔案下配置bean的id名
	BookService bs =  ctx.getBean("bookService");
	//這時候就獲取到Ioc容器中bean的物件了
}

DI入門

  1. 基於Ioc管理bean
  2. 透過配置進行依賴注入
<bean id="Dao" class="com.fyislo.dao.impl.Dao"/>

<bean id="Service" class="com.fyislo.service.impl.Service">
	# property標籤表示配置當前bean的屬性
	# name屬性表示我們配給誰?(屬性名稱)
	# ref屬性表示我們要把誰給對方(bean的id屬性)
	<property name="dao" ref="Dao"/>
</bean>

Bean

Bean的配置

使用 name 屬性,可以給bean配置多個別名。多個別名之間可以用逗號,分號,空格分隔。

<bean id="Dao" class="com.fyislo.dao.impl.Dao"/>

# name屬性可以給bean配置多個別名。多個別名之間可以用逗號,分號,空格分隔。
<bean id="Service" name="service service2" class="com.fyislo.service.impl.Service">
	<property name="dao" ref="Dao"/>
</bean>

注:獲取bean無論是透過id還是name獲取,如果無法獲取到,將丟擲異常 NoSuchBeanDefinitionExceptionNoSuchBeanDefinitionException: Nobeannamed'bookServiceImpl'available

bean的作用範圍

Spring給我們建立的bean預設是單例的。

如果需要非單例的bean,則需要在配置檔案 <bean> 的標籤中新增一個屬性: scope

  • scoper
    • singleton:單例(預設)
    • prototype:非單例
<bean id="Service" name="service service2" class="com.fyislo.service.impl.Service" scope="prototype">
	<property name="dao" ref="Dao"/>
</bean>
  • 適合交給容器進行管理的bean
    • 表現層物件
    • 業務層物件
    • 資料層物件
    • 工具物件
  • 不適合交給容器進行管理的bean
    • 封裝實體類的域物件

bean的例項化

1、使用構造方法完成建立bean(無參構造)

  • bean本質上就是物件
  • 無參構造如果不存在,將丟擲異常 BeanCreationException

2、透過靜態工廠建立bean(瞭解)

透過 class 屬性告訴工廠類,在透過factory-method屬性告訴Spring工廠裡面的哪個方法是造物件的。

<bean id="orderDao" class="factory.OrderDaoFactory" factory-method="getorderDad"/>

3、例項工廠建立bean

  1. 先配置工廠的bean
  2. 透過 factory-bean 指定例項工廠的bean
  3. 透過 factory-method 指定造物件的方法
<bean id="userFactory" class="factory.UserDaoFactory"/>

<bean id="orderDao" factory-method="getuserDao" factory-bean="userFactory"/>

4、使用 FactoryBean<T> 例項化

實現介面中的兩個方法。

public class UserDaoFactoryBean implements FactoryBean<UserDao>{
	//代替原始例項工廠中建立物件的方法
	//得到bean的例項
	public UserDao getobject() throws Exception{
		return new UserDaoImpl();
	}
	//得到bean的型別
	public Class<?> getobjectType(){
		//返回建立物件的位元組碼檔案
		return UserDao.class;
	}
	//設定該bean是單例還是非單例的
	//預設可以不寫該方法
	public boolean isSingleton(){
		//返回true:單例
		//返回false:非單例
		return true;
	}
}

這時候配置就很簡便了

<bean id="userDao" class="factory.UserDaoFactoryBean"/>

bean的生命週期

  • 生命週期:從建立到消亡的完整過程
  • bean生命週期:bean從建立到銷燬的整體過程
  • bean生命週期控制:在bean建立後到銷燬前做一些事情

<bean>標籤中init-method 屬性可以指定一個方法,在bean建立前執行一個方法。

<bean> 標籤中 destroy-method 屬性可以指定一個方法,在bean銷燬前執行的一個方法。

<bean id="" class="" init-method="init" destroy-method="destory"/>

關閉容器

public static void main(String args[]){
	//獲取IoC容器
	//ApplicationContext是一個介面,但是它沒有close()方法。
	//ClassPathXmlApplicationContext是它的實現類,有close()方法。
	ClassPathXmlApplicationContext ctx = new 
	ClassPathXmlApplicationContext
	("applicationContext.xml");

	//方法一:直接關閉容器
	ctx.close();
	//方法二:註冊關閉鉤子,在任何時間註冊都可以。
	//作用:在虛擬機器退出之前,把容器關完了再退出
	ctx.registerShutdownHook();
}

使用Spring介面來控制生命週期(這樣便不用去xml檔案中指定控制生命週期的方法)

實現 InitializingBeanDisposableBean 兩個介面

public class Service implements InitializingBean, DisposableBean{
	public void afterPropertiesSet() throws Exception{
		//設定屬性之後執行該方法
	}
	
	public void destroy() throws Exception{
		//
	}
}

Bean在初始化過程中經歷的階段

  • 初始化容器
    1. 建立物件(記憶體分配)
    2. 執行構造方法
    3. 執行屬性注入(set方法)
    4. 執行bean初始化方法
  • 使用bean
    1. 執行業務操作
  • 關閉/銷燬容器
    1. 執行bean銷燬方法

bean銷燬時機

  • 容器關閉前出發bean的銷燬
  • 關閉容器方式:
    • 手動關閉容器
      • ConfigurableApplicationContext介面close()操作
    • 註冊關閉鉤子,在虛擬機器退出前先關閉容器再退出虛擬機器
      • ConfigurableApplicationContext介面registerShutdownHook()操作

bean相關屬性

image.png

依賴注入

  • 依賴注入的兩種方式
    • 普通方法(set方法)
    • 構造方法
  • 依賴注入的兩種型別
    • 引用型別
    • 簡單型別(基本資料型別和String)
  • 依賴注入方式
    • setter注入
      • 簡單型別
      • 引用型別
    • 構造器注入
      • 簡單型別
      • 引用型別

setter方式注入

1、setter方式注入引用型別,在DI入門已有提過。

在xml檔案中配置 <bean> 標籤,並在其中配置 <property> 標籤即可

2、setter方式注入簡單型別

<bean id="Service" class="com.fyislo.service.impl.Service">
	# property標籤表示配置當前bean的屬性
	# name屬性表示我們配給誰?(屬性名稱)
	# 只需要把ref屬性替換成value屬性,即可完成簡單型別的注入
	<property name="int" value="123"/>
	<property name="string" value="name"/>
</bean>

構造器注入

1、構造器注入引用型別

將setter注入的set方法更換為有參構造即可,在xml的配置有所改變,如下:

<bean id="Service" class="com.fyislo.service.impl.Service">
	# 只需把property標籤更換為constructor-arg標籤即可
	<constructor-arg name="形參的名稱1" ref=""/>
	<constructor-arg name="形參的名稱2" ref=""/>
</bean>

2、構造器注入簡單型別

# 標準寫法:有指定形參的名稱
<bean id="Service" class="com.fyislo.service.impl.Service">
	# 只需把constructor-arg標籤的ref更換為value即可
	<constructor-arg name="形參的名稱1" value=""/>
	<constructor-arg name="形參的名稱2" value=""/>
</bean>
# 解決形參名稱耦合的問題
<bean id="Service" class="com.fyislo.service.impl.Service">
	# 不使用name指定形參名稱,使用type指定形參型別
	<constructor-arg type="int" value=""/>
	<constructor-arg type="java.lang.String" value=""/>
</bean>
# 解決引數型別重複問題,使用位置解決引數匹配
<bean id="Service" class="com.fyislo.service.impl.Service">
	# 使用index指定引數位置
	<constructor-arg index="0" value=""/>
	<constructor-arg index="1" value=""/>
</bean>

依賴注入方式選擇

  1. 制依賴使用構造器進行,使用setter注入有機率不進行注入導致null物件出現
  2. .可選依賴使用setter注入進行,靈活性強
  3. Spring框架倡導使用構造器,第三方框架內部大多數採用構造器注入的形式進行資料初始化,相對嚴謹
  4. 如果有必要可以兩者同時使用,使用構造器注入完成強制依賴的注入,使用setter注入完成可選依賴的注入
  5. 實際開發過程中還要根據實際情況分析,如果受控物件沒有提供setter方法就必須使用構造器注入
  6. 自己開發的模組推薦使用setter注入

依賴自動裝配

  • IoC容器根據bean所依賴的資源在容器中自動查詢並注入到bean中的過程稱為自動裝配
  • 自動裝配的方式
    • 按型別(常用)
    • 按名稱
    • 按構造方法
    • 不啟用自動裝配

前提:想要自動裝配,要提供set方法,xml配置檔案如下:

  • autowire可選值
    • byType:按型別
    • byName:按名稱
# 自動裝配,使用aotuwire屬性
# 該型別的bean物件在配置檔案中必須是唯一的
# 不唯一,它怎麼知道給你注入哪一個?
<bean id="" class="" autowire="byType"/>
  • 依賴自動裝配特徵
    • 自動裝配用於引用型別依賴注入,不能對簡單型別進行操作
    • 使用按型別裝配時(byType)必須保障容器中相同型別的bean唯一,推薦使用
    • 使用按名稱裝配時(byName)必須保障容器中具有指定名稱的bean,因變數名與配置耦合,不推薦使用
    • 自動裝配優先順序低於setter注入與構造器注入,同時出現時自動裝配配置失效

集合注入

<bean id="" class="">
	<property name="array">
		<array>
			<value>100</value>
			<value>30</value>
			<ref bean="beanId"/> # 引用型別
		</array>
	</property>
	<property name="list">
	 	<list>
	 		<value>adjkl</value>
	 		<value>30</value>
	 	</list>
 	</property>
 	<property name="list">
	  	<set>
	  		<value>adjkl</value>
	  		<value>30</value>
	  	</set>
  	</property>
  	<property name="list">
	   	<map>
	   		<entry key="name" value="zhangsan"/>
	   		<entry key="" value=""/>
	   	</map>
   </property>
   <property name="properties">
    	<props>
    		<prop key="key">value</prop>
    		<prop key="key">value</prop>
    	</props>
   </property>
</bean>

載入properties檔案

  1. 開啟context名稱空間
  2. 使用context空間載入properties檔案(載入的檔案從resources目錄中尋找)
  3. 使用屬性佔位符:${}讀取properties檔案中的屬性
<?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"
       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,把兩行末尾的beans更換為context
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd
       ">  

	# 1.開啟context名稱空間
	2.使用context空間載入properties檔案(載入的檔案從resources目錄中尋找)
	# 3. 使用屬性佔位符:${}讀取properties檔案中的屬性
	<context:property-placeholder location="resources目錄下的properties檔案"/>
	
    <bean id="service" class=
    "com.fyislo.service.Impl.BookServiecImpl">
        <property name="url" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.user}"/>  
    </bean>  
</beans>

載入properties檔案

image.png

依賴注入相關

image.png

容器

建立容器

1、載入類路徑下的配置檔案

//載入類路徑下的配置檔案
ApplicationContext act =  new ClassPathXmlApplicationContext("applicationContext.xml");

2、從檔案系統下載入配置檔案

//從檔案系統下載入配置檔案
ApplicationContext act = new FileSystemXmlApplicationContext("C:\software\project\JavaProject\JavaStudy\src\main\resources\applicationContext.xml");

載入bean的方式

# 根據名稱獲取bean,需要強轉
BookService bookService = (BookService) act.getBean("service");

# 根據名稱獲取bean,不需要強轉
BookService bookService = act.getBean("service",BookService.class);

# 根據型別獲取bean
BookService bookService = act.getBean(BookService.class);

# 載入多個配置檔案
ApplicationContext act =  new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");

ApplicationContext 的頂層介面是 BeanFactory ,它也可以建立IoC容器,但存在侷限性。

  • ApplicationContextBeanFactory 的區別
    • 它們載入bean的時機不同
      • ApplicationContext 是啟動容器後立即載入
      • BeanFactory 是延遲載入

如果需要 ApplicationContext 完成延時載入,可以給 bean 標籤新增一個屬性 lazy-init="true"

image.png

免責宣告:此片文章是個人學習筆記,存在借鑑,若有冒犯或侵權,聯絡可刪除。

相關文章