準備開發環境
建立一個Maven專案
pom.xml新增依賴
resources下新增spring的組態檔applicationContext.xml
最終專案的結構如下:
構造方法範例化
:
準備一個BookDao和BookDaoImpl類
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
<?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 id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
</beans>
public class AppForInstanceBook {
public static void main(String[] args) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
在BookDaoImpl類中新增一個無參建構函式,並列印一句話,方便觀察結果。
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
執行程式,如果控制檯有列印建構函式中的輸出,說明Spring容器在建立物件的時候也走的是建構函式
public class BookDaoImpl implements BookDao {
private BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
執行程式,能執行成功,說明內部走的依然是建構函式,能存取到類中的私有構造方法,顯而易見Spring底層用的是反射
public class BookDaoImpl implements BookDao {
private BookDaoImpl(int i) {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
執行程式,程式會報錯,說明Spring底層使用的是類的無參構造方法。
接下來,我們主要研究下Spring的報錯資訊
錯誤資訊從下往上依次檢視,因為上面的錯誤大都是對下面錯誤的一個包裝,最核心錯誤是在最下面
Caused by: java.lang.NoSuchMethodException: com.itheima.dao.impl.BookDaoImpl.<init>
()
Caused by 翻譯為引起
,即出現錯誤的原因
java.lang.NoSuchMethodException:丟擲的異常為沒有這樣的方法異常
com.itheima.dao.impl.BookDaoImpl.<init>
():哪個類的哪個方法沒有被找到導致的異常,<init>
()指定是類的構造方法,即該類的無參構造方法
如果最後一行錯誤獲取不到錯誤資訊,接下來檢視第二層:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.itheima.dao.impl.BookDaoImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.itheima.dao.impl.BookDaoImpl.<init>
()
nested:巢狀的意思,後面的異常內容和最底層的異常是一致的
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.itheima.dao.impl.BookDaoImpl]: No default constructor found;
Caused by: 引發
BeanInstantiationException:翻譯為bean範例化異常
No default constructor found:沒有一個預設的建構函式被發現
看到這其實錯誤已經比較明顯,給大家個練習,把倒數第三層的錯誤分析下吧:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bookDao' defined in class path resource [applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.itheima.dao.impl.BookDaoImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.itheima.dao.impl.BookDaoImpl.<init>
()。
建立bean異常,錯誤建立bean:範例化bean失敗
因為每一個類預設都會提供一個無參建構函式,所以其實真正在使用這種方式的時候,我們什麼也不需要做。這也是我們以後比較常用的一種方式。
接下來研究Spring中的第二種bean的建立方式靜態工廠範例化
:
在講這種方式之前,我們需要先回顧一個知識點是使用工廠來建立物件的方式:
(1)準備一個OrderDao和OrderDaoImpl類
public interface OrderDao {
public void save();
}
public class OrderDaoImpl implements OrderDao {
public void save() {
System.out.println("order dao save ...");
}
}
(2)建立一個工廠類OrderDaoFactory並提供一個==靜態方法==
//靜態工廠建立物件
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
return new OrderDaoImpl();
}
}
(3)編寫AppForInstanceOrder執行類,在類中通過工廠獲取物件
public class AppForInstanceOrder {
public static void main(String[] args) {
//通過靜態工廠建立物件
OrderDao orderDao = OrderDaoFactory.getOrderDao();
orderDao.save();
}
}
(4)執行後,可以檢視到結果
如果程式碼中物件是通過上面的這種方式來建立的,如何將其交給Spring來管理呢?
這就要用到Spring中的靜態工廠範例化的知識了,具體實現步驟為:
(1)在spring的組態檔application.properties中新增以下內容:
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
class:工廠類的類全名
factory-mehod:具體工廠類中建立物件的方法名
對應關係如下圖:
(2)在AppForInstanceOrder執行類,使用從IOC容器中獲取bean的方法進行執行測試
public class AppForInstanceOrder {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
orderDao.save();
}
}
(3)執行後,可以檢視到結果
看到這,可能有人會問了,你這種方式在工廠類中不也是直接new物件的,和我自己直接new沒什麼太大的區別,而且靜態工廠的方式反而更復雜,這種方式的意義是什麼?
主要的原因是:
在工廠的靜態方法中,我們除了new物件還可以做其他的一些業務操作,這些操作必不可少,如:
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
System.out.println("factory setup....");//模擬必要的業務操作
return new OrderDaoImpl();
}
}
之前new物件的方式就無法新增其他的業務內容,重新執行,檢視結果:
介紹完靜態工廠範例化後,這種方式一般是用來相容早期的一些老系統,所以瞭解為主。
接下來繼續來研究Spring的第三種bean的建立方式範例工廠範例化
:
(1)準備一個UserDao和UserDaoImpl類
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("user dao save ...");
}
}
(2)建立一個工廠類OrderDaoFactory並提供一個普通方法,注意此處和靜態工廠的工廠類不一樣的地方是方法不是靜態方法
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
(3)編寫AppForInstanceUser執行類,在類中通過工廠獲取物件
public class AppForInstanceUser {
public static void main(String[] args) {
//建立範例工廠物件
UserDaoFactory userDaoFactory = new UserDaoFactory();
//通過範例工廠物件建立物件
UserDao userDao = userDaoFactory.getUserDao();
userDao.save();
}
(4)執行後,可以檢視到結果
對於上面這種範例工廠的方式如何交給Spring管理呢?
具體實現步驟為:
(1)在spring的組態檔中新增以下內容:
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
範例化工廠執行的順序是:
建立範例化工廠物件,對應的是第一行設定
呼叫物件中的方法來建立bean,對應的是第二行設定
factory-bean:工廠的範例物件
factory-method:工廠物件中的具體建立物件的方法名,對應關係如下:
factory-mehod:具體工廠類中建立物件的方法名
(2)在AppForInstanceUser執行類,使用從IOC容器中獲取bean的方法進行執行測試
public class AppForInstanceUser {
public static void main(String[] args) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.save();
}
}
(3)執行後,可以檢視到結果
範例工廠範例化的方式就已經介紹完了,設定的過程還是比較複雜,所以Spring為了簡化這種設定方式就提供了一種叫FactoryBean
的方式來簡化開發。
具體的使用步驟為:
(1)建立一個UserDaoFactoryBean的類,實現FactoryBean介面,重寫介面的方法
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//代替原始範例工廠中建立物件的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
//返回所建立類的Class物件
public Class<?> getObjectType() {
return UserDao.class;
}
}
(2)在Spring的組態檔中進行設定
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
(3)AppForInstanceUser執行類不用做任何修改,直接執行
這種方式在Spring去整合其他框架的時候會被用到。
檢視原始碼會發現,FactoryBean介面其實會有三個方法,分別是:
T getObject() throws Exception;
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
方法一:getObject(),被重寫後,在方法中進行物件的建立並返回
方法二:getObjectType(),被重寫後,主要返回的是被建立類的Class物件
方法三:沒有被重寫,因為它已經給了預設值,從方法名中可以看出其作用是設定物件是否為單例,預設true,從意思上來看,我們猜想預設應該是單例,如何來驗證呢?
思路很簡單,就是從容器中獲取該物件的多個值,列印到控制檯,檢視是否為同一個物件。
public class AppForInstanceUser {
public static void main(String[] args) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao1 = (UserDao) ctx.getBean("userDao");
UserDao userDao2 = (UserDao) ctx.getBean("userDao");
System.out.println(userDao1);
System.out.println(userDao2);
}
}
列印結果,如下:
通過驗證,會發現預設是單例,那如果想改成單例具體如何實現?
只需要將isSingleton()方法進行重寫,修改返回為false,即可
//FactoryBean建立物件
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//代替原始範例工廠中建立物件的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
public Class<?> getObjectType() {
return UserDao.class;
}
public boolean isSingleton() {
return false;
}
}
重新執行AppForInstanceUser,檢視結果
從結果中可以看出現在已經是非單例了,但是一般情況下我們都會採用單例,也就是採用預設即可。所以isSingleton()方法一般不需要進行重寫。
(1)bean是如何建立的呢
構造方法
(2)Spring的IOC範例化物件的三種方式分別是:
構造方法(常用)
靜態工廠(瞭解)
範例工廠(瞭解)
FactoryBean(實用)
這些方式中,重點掌握構造方法
和FactoryBean
即可。
需要注意的一點是,構造方法在類中預設會提供,但是如果重寫了構造方法,預設的就會消失,在使用的過程中需要注意,如果需要重寫構造方法,最好把預設的構造方法也重寫下。
本文來自部落格園,作者:|舊市拾荒|,轉載請註明原文連結:https://www.cnblogs.com/xiaoyh/p/16311025.html