1. Spring6 當中 獲取 Bean 的四種方式
@
- 1. Spring6 當中 獲取 Bean 的四種方式
- 每博一文案
- 1.1 第一種方式:透過構造方法獲取 Bean
- 1.2 第二種方式:透過簡單工廠模式獲取 Bean
- 1.3 第三種方式:透過 factory-bean 屬性獲取 Bean
- 1.4 第四種方式:透過 FactoryBean 介面 獲取 Bean
- 1.5 BeanFactroy 和 FactroyBean 的區別
- 2. 將Date 作為複雜型別進行注入(可以自定義 Date 時間型別的格式)
- 3. 總結
- 4. 最後:
每博一文案
比如:《殺死一隻是更鳥》中提到的
對應我們:我們努力升本,考研,每天都在努力學習,但是某天突然想到萬一沒有考上的話,那現在的努力又有什麼意義呢?
答案:在《殺死一隻是更鳥》裡有這樣一段話:
勇敢是,當你還未開始,你就知道自己會輸,可你依然要去做,而且無論如何都要把它堅持到底,你很少能贏,但有時也會。努力的這個過程本身就是有意義,能夠獲得理想的結果當然很好,但如果失敗了也沒關係。因為你的勇敢,從未辜負你的青春,而黎明的光亮,總有一刻,會照亮穿梭於黑暗之中的自己。
況且,你還不一定會輸呢。
Spring 為Bean 的獲取提供了多種方式,通常包括4種方式。(也就是說在Spring中為Bean物件的建立準備了多種方案,目的是:更加靈活)
- 第一種:透過構造方法例項化,獲取 Bean物件
- 第二種:透過簡單工廠模式例項化,獲取Bean物件
- 第三種:透過factory-bean 屬性,獲取Bean物件
- 第四種:透過對FactoryBean 介面的例項化,獲取Bean物件
1.1 第一種方式:透過構造方法獲取 Bean
簡單的說:就是透過在spring的配置檔案中,進行一個配置,從而調取其中 Bean 的構成方法,獲取到 對應的Bean物件。
準備工作:透過 maven 匯入 Spring6的框包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rainbowsea</groupId>
<artifactId>spring6-005-bean-instantiation-blog</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.11</version>
</dependency>
<!-- junit4 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
這裡我們建立一個User 的類,方便我們進行一個,測試。為了測試效果,更加明顯,這裡這個User類就定義成一個空的類吧
配置相關的 spring.xml 配置檔案資訊內容,告知 Spirng 框架,幫我們進行一個管理。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 第一種: 透過構造方法獲取 Bean -->
<bean id="user" class="com.rainbowsea.Bean.User"></bean>
</beans>
執行測試,看是否能夠,獲取到我們想要的這個 User 類物件。
import com.rainbowsea.Bean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
@org.junit.Test
public void test() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
User user = applicationContext.getBean("user", User.class);
System.out.println(user);
}
}
從上述結果,我們透過構造方法,獲取到了 Bean 物件。
1.2 第二種方式:透過簡單工廠模式獲取 Bean
第一步: 定義一個Bean,還是使用 User 物件
外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳 第二步: 編寫簡單工廠模式當中的工廠類。關於簡單工廠模式的內容,大家可以移步至:✏️✏️✏️ GoF之工廠模式-CSDN部落格
瞭解更多。注意: 這裡的 User 物件,本質上,還是我們程式設計師自己給 new 出來的,並不是 Spring 幫我們弄的。
/**
* 特點:它是簡單工廠模式(靜態工廠模式),是靜態的一個方法
*
*/
public class UserFactory {
public static User get() {
// 本質上,還是我們自己程式設計師自己 new 出來的
return new User();
}
}
第三步:在Spring配置檔案中指定建立該Bean的方法(使用factory-method屬性指定)
透過簡單工廠模式,你需要在Spring當中配置檔案種告訴 Spring框架,呼叫哪個類當中的哪個方法可以獲取到這個你要的 Bean; factory-method 指明方法()對應方法的小寫。
factory-method=
屬性我們這裡指定的是 UserFactory 工廠類當中靜態方法,也就是告訴Spring 框架,呼叫方法可以獲取到你要的Bean 物件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 第二種: 透過簡單工廠模式,你需要在Spring當中配置檔案種告訴 Spring框架,呼叫哪個類當中的哪個方法可以獲取到這個
你要的 Bean; factory-method 指明方法()對應方法的小寫 -->
<!-- factory-method= 屬性指定的時工廠類當中靜態方法,也就是告訴Spring 框架,呼叫方法可以獲取到你要的
Bean-->
<bean id="userFactory" class="com.rainbowsea.Bean.UserFactory" factory-method="get"></bean>
</beans>
第四步: 編寫測試程式
透過:
這樣一個配置,就讓我們告知了 Spring 框架,你呼叫那個類當中的哪裡方法,就可以獲取到我們想要的Bean 物件。
1.3 第三種方式:透過 factory-bean 屬性獲取 Bean
使用 factory-bean 屬性獲取 Bean,本質上是,使用23種設計模式當中的工廠方法模式(注意,這裡沒有錯,不瞭解的,可能會認為是,我寫錯了,並沒有寫錯這裡)。 想要了解關於”工廠方法模式的“,大家可以移步至✏️✏️✏️GoF之工廠模式-CSDN部落格,瞭解更多。
第一步:定義一個 Bean 物件。這裡我們還是使用 User 這裡類,進行試驗。
第二步: 既然是工廠方法模式,自然是少不了,工廠了。需要注意 :這裡是工廠方法模式,與靜態工廠模式不同,這個生產 Bena 物件的方法,不是靜態方法,而是例項化方法 。這也導致了,我們在接下來後續的 spring.xml 配置檔案上與第二種 方式有所差異的。注意其中的差異,所使用的標籤,不要弄錯了。
package com.rainbowsea.Bean;
/**
* 特點:它是簡單工廠模式(靜態工廠模式),是靜態的一個方法
*
*/
public class UserFactory {
// 工廠方法模式中的具體工廠角色中的方法是:例項方法
public User get() {
// 相同點是和靜態工廠方法模式是一樣的:都是我們自己程式設計師 new 的。
// 然後交給 Spring框架管理
return new User();
}
}
第三步:在Spring配置檔案中指定factory-bean以及factory-method
上面我們說到,工廠方法模式與靜態方法模式,不同點,上是工廠方法模式生產Bean 物件的方法,並不是一個 static() 方法 ,所以,使用的標籤屬性就有所不同了。
這裡我們需要用到以下,兩個標籤屬性,才能讓spirng 準確的呼叫哪個類當中的哪個物件的方法,獲取,返回給我們自己想要的 Bean 物件,這裡是User 這個 bean物件。
- factory-bean 指明哪個物件
- factory-method當中的哪個方法;可以獲取到你想要的 bean
簡單的說:告訴Spring 透過哪個物件,當中的哪個方法,可以獲取到我想要的 Bean 物件 。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 第三種:透過Spring提供的例項化方式,透過工廠方法模式,透過
factory-bean 指明哪個物件+factory-method當中的哪個方法;可以獲取到你想要的 bean-->
<!-- 簡單的說:就是告訴Spring框架,呼叫哪個物件中的哪個方法,就可以獲取到你想要的 Bean了-->
<bean id="userFactory" class="com.rainbowsea.Bean.UserFactory"> </bean>
<!-- 以下的配置很關鍵: factory-bean:告訴Spring框架呼叫哪個物件; factory-method 告訴Spring框架
呼叫哪個方法,可以獲取到你要的Bean-->
<bean id="userBean" factory-bean="userFactory" factory-method="get"></bean>
</beans>
第四步: 測試執行結果。
import com.rainbowsea.Bean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
@org.junit.Test
public void test() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
User user = applicationContext.getBean("userBean", User.class);
System.out.println(user);
}
}
1.4 第四種方式:透過 FactoryBean 介面 獲取 Bean
以上的第三種方式中,factory-bean的屬性值是我們自定義的,factory-method的屬性值也是我們自己定義的。
在Spring中,當你編寫的類直接實現FactoryBean介面之後,factory-bean不需要指定了,factory-method也不需要指定了。
factory-bean會自動指向實現FactoryBean介面的類,factory-method會自動指向getObject()方法。
package org.springframework.beans.factory;
import org.springframework.lang.Nullable;
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
第四種方式:簡單的說:就是對第三種方式的一種簡化,透過讓對應的工廠類是實現該介面implements FactoryBean ,Spring就知道該呼叫哪個物件,中的哪個方法,獲取到你要的 Bean 物件了 。從到到達了某種程度上的簡化。
第一步: 定義一個Bean
這裡我們還是使用 User 這裡類,進行試驗。
第二步: 編寫一個(工廠模式當中的)工廠類實現 FactoryBean介面
下面,我們來了解一下,FactoryBean介面下的這個三個方法的作用是幹啥的
// 返回我們所需要的 Bean 物件
T getObject() throws Exception;
例如:注意一點:這裡還是需要我們自己 new() 出對應所需要的 Bean 物件,而不是 Spirng 弄出來的
@Override
public User getObject() throws Exception {
return new User(); // 還是需要我們程式設計師自己 new() 出來
}
/**
* 這個方法在介面中有預設實現
* 預設返回 true,表示單例的
* 如果想多例的化,直接講這個修改為: return false 即可。
* @return
*/
default boolean isSingleton() {
return true;
}
例如:
@Override
public boolean isSingleton() {
return true; // 單例
}
這裡我們定義了一個 UserFactory 產生 User 的物件的工廠類,同時實現implements FactoryBean 該介面。
package com.rainbowsea.Bean;
import org.springframework.beans.factory.FactoryBean;
/**
* 特點:它是簡單工廠模式(靜態工廠模式),是靜態的一個方法
*
*/
public class UserFactory implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
// 本質上還是我們程式設計師自己 new ()出來的,並不是 Spring 弄出來
return new User();
}
// 這個方法可以不用管它。
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return true; // 單例
// false 多例
}
}
第三步:在Spring配置檔案中配置FactoryBean
由於我們這個public class UserFactory implements FactoryBean
生產 User 的工廠實現了 FactoryBean 介面,Spring 已經是知道,我們需要呼叫的是哪個物件當中的哪個方法,從而獲取對應的 user Bean物件了。所以對應其中的 spinrg.xml
只需要簡單的配置一下,即可。如下:
將方式的核心就在於:透過一個特殊的Bean(工廠Bean當中的方法)<該工廠實現了 FactoryBean 介面 >,來返回一個普通的Bean 物件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Spring框架中:獲取Bean的第四種方式:透過 FactoryBean 介面來實現指明 -->
<!-- 這種方式實際上就是第三種方式的簡化-->
<!-- 由於你編寫的類實現了FactoryBean介面,那麼這個類就是一個特殊的類,不需要你再手動指定: factory-bean;
factory-method 哪個物件,哪個方法了,你實現了 FactoryBean 介面,Spring框架就已經知道了,不需要再特殊指明瞭-->
<!-- 剩下指明是哪個特殊的類就可以了-->
<!-- 透過一個特殊的Bean,工廠Bean,來返回一個普通的Bean person物件-->
<bean id="userFactory" class="com.rainbowsea.Bean.UserFactory"></bean>
</beans>
第四步: 執行程式測試。
package com.rainbowsea.test;
import com.rainbowsea.Bean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
@org.junit.Test
public void test() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
User user = applicationContext.getBean("userFactory", User.class);
System.out.println(user);
}
}
FactoryBean在Spring中是一個介面。被稱為“工廠Bean”。“工廠Bean(透過工廠上的方法返回一個 對應的 Bean 物件)”是一種特殊的Bean。所有的“工廠Bean”都是用來協助Spring框架來建立其他Bean物件的。
1.5 BeanFactroy 和 FactroyBean 的區別
BeanFactory
Spring IoC容器的頂級物件,BeanFactory被翻譯為“Bean工廠”,在Spring的IoC容器中,“Bean工廠”負責建立Bean物件。 BeanFactory是工廠。
FactoryBean
FactoryBean:它是一個Bean,是一個能夠輔助Spring例項化其它Bean物件的一個Bean。
在Spring中,Bean可以分為兩類:
- 第一類:普通Bean
- 第二類:工廠Bean(記住:工廠Bean也是一種Bean,只不過這種Bean,比較特殊工廠Bean(透過工廠上的方法返回一個 對應的 Bean 物件),從而到達輔助Spring例項化其它Bean物件的效果。)
2. 將Date 作為複雜型別進行注入(可以自定義 Date 時間型別的格式)
在Spring 當中 為什麼要將 Date 作為複雜型別進行注入呢?
原因是,在Spring 如果將 Date 作為簡單型別進行注入的話,需要特定的時間格式,才能注入成功。
準備工作:定義一個 Bean 類,同時其中含有一個 Date 型別的屬性值。
package com.rainbowsea.Bean.myDate;
import java.util.Date;
public class Vip {
private Date birth;
public Vip(Date birth) {
this.birth = birth;
}
public Vip() {
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
@Override
public String toString() {
return "Vip{" +
"birth=" + birth +
'}';
}
}
演示如下:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'vipBean' defined in class path resource [spring2.xml]: Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'birth'; Cannot convert value of type 'java.lang.String' to required type 'java.util.Date' for property 'birth': no matching editors or conversion strategy found
對應Spring當中的 Date 作為簡單型別的注入,需要用如下它美國的格式時間格式,才能被識別為 Date 型別。特殊格式如下:
Mon Apr 29 20:03:58 CST 2024
雖然轉化成功了,但是這個格式,對於我們國人來說,不太友好,而且也不好記憶。
所以為了將Date 型別轉化為我們國人友好的型別的格式,我們就需要將 Date 定義為 複雜型別
進行 ref 注入。但是怎樣將 Date 作為複雜型別注入的同時又可以轉換為我們需要的格式呢。——這就需要用到上面我們所學習的透過 FactoryBean介面 獲取 Bean 物件了。其實呢,上面第二種方式,第三種方式,第四種方式都是可以實現的。但是第四種方式比較簡化,我們這裡就用第四種方式來解決。這個問題。
第一步: 定義一個含有 Date 型別的類,就還是使用上面哪個 Vip 類吧
第二步: 建立一個用於生產我們所需要的格式的 Date的工廠 同時該工廠又實現了 implements FactoryBean 介面。告訴Spring框架,呼叫其中的哪個物件當中的哪個方法,獲取到我們所需要的 Date 物件。
package com.rainbowsea.Bean.myDate;
import org.springframework.beans.factory.FactoryBean;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Date 工廠模式
* DateFactoryBean 這個工廠Bean 協助我們Spring 建立這個普通的Bean;Date
*/
public class DateFactor implements FactoryBean<Date> {
// 這個 String字串型別,作為我們Date型別,進行一個轉換
private String strDate;
public DateFactor() {
}
public DateFactor(String strDate) {
this.strDate = strDate;
}
public String getStrDate() {
return strDate;
}
public void setStrDate(String strDate) {
this.strDate = strDate;
}
@Override
public Date getObject() throws Exception {
// 透過 SimpleDateFormat 來自定義我們的 Date 的日期時間型別的格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
// 透過在 spring.xml 對DateFactor類當中的 String strDate 屬性進行賦值
Date date = simpleDateFormat.parse(this.strDate); // 將字串型別轉換為 Date 日期時間型別
return date; // 轉換後返回 Date 型別,進行一個賦值操作
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return true; // 單例 false 多例
}
}
上述程式碼的核心程式碼片段講解:
// 這個 String字串型別,作為我們Date型別,進行一個轉換 private String strDate; public Date getObject() throws Exception { // 透過 SimpleDateFormat 來自定義我們的 Date 的日期時間型別的格式 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 透過在 spring.xml 對DateFactor類當中的 String strDate 屬性進行賦值 Date date = simpleDateFormat.parse(this.strDate); // 將字串型別轉換為 Date 日期時間型別 return date; // 轉換後返回 Date 型別,進行一個賦值操作 }
透過定義一個Date 型別的工廠類 生產出,我們需要的格式的 Date 型別。
- 首先在其 DateFactor 工廠類當中,建立一個 String strDate 用於我們傳入日期時間,再透過 new SimpleDateFormat("yyyy-MM-dd") 來定義我們的Date 日期時間型別的格式。透過Date date = simpleDateFormat.parse(this.strDate); 將字串型別轉換為 Date 日期時間型別。最後返回一個我們所需要的格式的 Date 型別的日期時間型別。
第三步: 為我們這個 工廠類(生產我們所需的Date日期型別格式),配置到 Spring 當中去,並讓 Spirng 框架返回一個我們需要的 Date型別的 Bean 物件,同時作為複雜型別,賦值到 Vip 這個類當中的 birth 屬性的值。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 指明透過DateFactor 獲取到一個我們所需要的格式的 Date 型別-->
<bean id="myDateBean" class="com.rainbowsea.Bean.myDate.DateFactor">
<property name="strDate" value="1980-01-01"></property>
</bean>
<!-- 獲取到之後,作為複雜型別,賦值給 Vip 當中的 Date birth 屬性值-->
<bean id="vipBean" class="com.rainbowsea.Bean.myDate.Vip">
<property name="birth" ref="myDateBean"></property>
</bean>
</beans>
第四步: 執行程式測試
核心要素就是:透過一個(這裡時生產我們所需格式的 Date 型別的)工廠類實現 FactoryBean介面,被稱為“工廠Bean”。“工廠Bean(透過工廠上的方法返回一個對應的 Bean(這裡時 Date ) 物件)”是一種特殊的Bean。獲取到對應 Date 後,再作為 複雜型別作為其他類上的屬性的值存在。
3. 總結
第一種透過構造方法獲取 Bean:簡單的說:就是透過在spring的配置檔案中,進行一個配置,從而調取其中 Bean 的構成方法,獲取到 對應的Bean物件。
第二種方式:透過簡單工廠模式獲取 Bean;注意時工廠類中生產對應的Bean物件是靜態方法()。同時其中的 Bean 本質上還是程式設計師自己 new()出來的。
透過簡單工廠模式,你需要在Spring當中配置檔案種告訴 Spring框架,呼叫哪個類當中的哪個方法可以獲取到這個你要的 Bean; factory-method 指明方法()對應方法的小寫。
factory-method=
屬性我們這裡指定的是 UserFactory 工廠類當中靜態方法,也就是告訴Spring 框架,呼叫方法可以獲取到你要的Bean 物件。第三種方式:透過 factory-bean 屬性獲取 Bean;使用 factory-bean 屬性獲取 Bean,本質上是,使用23種設計模式當中的工廠方法模式。(注意 其中的工廠類當中的生產對應 Bean的方法是例項方法(不是靜態方法),其中的 Bean 本質上還是程式設計師自己 new()出來的 )
- 這裡我們需要用到以下,兩個標籤屬性,才能讓spirng 準確的呼叫哪個類當中的哪個物件的方法,獲取,返回給我們自己想要的 Bean 物件,這裡是User 這個 bean物件。
- factory-bean 指明哪個物件
- factory-method當中的哪個方法;可以獲取到你想要的 bean
第四種方式:透過 FactoryBean 介面 獲取 Bean;簡單的說:就是對第三種方式的一種簡化,透過讓對應的工廠類是實現該介面implements FactoryBean ,Spring就知道該呼叫哪個物件,中的哪個方法,獲取到你要的 Bean 物件了 。從到到達了某種程度上的簡化。
- 該方式的核心就在於:透過一個特殊的Bean(工廠Bean當中的方法)<該工廠實現了 FactoryBean 介面 >,來返回一個普通的Bean 物件。
BeanFactroy 和 FactroyBean 的區別
將Date 作為複雜型別進行注入(可以自定義 Date 時間型別的格式);
對應Spring當中的 Date 作為簡單型別的注入,需要用如下它美國的格式時間格式,才能被識別為 Date 型別。
核心要素就是:透過一個(這裡時生產我們所需格式的 Date 型別的)工廠類實現 FactoryBean介面,被稱為“工廠Bean”。“工廠Bean(透過工廠上的方法返回一個對應的 Bean(這裡時 Date ) 物件)”是一種特殊的Bean。獲取到對應 Date 後,再作為 複雜型別作為其他類上的屬性的值存在。
4. 最後:
“在這個最後的篇章中,我要表達我對每一位讀者的感激之情。你們的關注和回覆是我創作的動力源泉,我從你們身上吸取了無盡的靈感與勇氣。我會將你們的鼓勵留在心底,繼續在其他的領域奮鬥。感謝你們,我們總會在某個時刻再次相遇。”