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系統架構圖:
核心概念
- 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入門
- 基於Ioc管理bean
- 透過配置進行依賴注入
<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
- 先配置工廠的bean
- 透過
factory-bean
指定例項工廠的bean - 透過
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檔案中指定控制生命週期的方法)
實現 InitializingBean
和 DisposableBean
兩個介面
public class Service implements InitializingBean, DisposableBean{
public void afterPropertiesSet() throws Exception{
//設定屬性之後執行該方法
}
public void destroy() throws Exception{
//
}
}
Bean在初始化過程中經歷的階段
- 初始化容器
- 建立物件(記憶體分配)
- 執行構造方法
- 執行屬性注入(set方法)
- 執行bean初始化方法
- 使用bean
- 執行業務操作
- 關閉/銷燬容器
- 執行bean銷燬方法
bean銷燬時機
- 容器關閉前出發bean的銷燬
- 關閉容器方式:
- 手動關閉容器
- ConfigurableApplicationContext介面close()操作
- 註冊關閉鉤子,在虛擬機器退出前先關閉容器再退出虛擬機器
- ConfigurableApplicationContext介面registerShutdownHook()操作
- 手動關閉容器
bean相關屬性
依賴注入
- 依賴注入的兩種方式
- 普通方法(set方法)
- 構造方法
- 依賴注入的兩種型別
- 引用型別
- 簡單型別(基本資料型別和String)
- 依賴注入方式
- setter注入
- 簡單型別
- 引用型別
- 構造器注入
- 簡單型別
- 引用型別
- 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>
依賴注入方式選擇
- 制依賴使用構造器進行,使用setter注入有機率不進行注入導致null物件出現
- .可選依賴使用setter注入進行,靈活性強
- Spring框架倡導使用構造器,第三方框架內部大多數採用構造器注入的形式進行資料初始化,相對嚴謹
- 如果有必要可以兩者同時使用,使用構造器注入完成強制依賴的注入,使用setter注入完成可選依賴的注入
- 實際開發過程中還要根據實際情況分析,如果受控物件沒有提供setter方法就必須使用構造器注入
- 自己開發的模組推薦使用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檔案
- 開啟context名稱空間
- 使用context空間載入properties檔案(載入的檔案從resources目錄中尋找)
- 使用屬性佔位符:${}讀取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檔案
依賴注入相關
容器
建立容器
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容器,但存在侷限性。
ApplicationContext
和BeanFactory
的區別- 它們載入bean的時機不同
ApplicationContext
是啟動容器後立即載入BeanFactory
是延遲載入
- 它們載入bean的時機不同
如果需要 ApplicationContext
完成延時載入,可以給 bean
標籤新增一個屬性 lazy-init="true"
免責宣告:此片文章是個人學習筆記,存在借鑑,若有冒犯或侵權,聯絡可刪除。