欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring中Bean的三種實例化方式詳解

 更新時間:2022年06月13日 10:35:29   作者:|舊市拾荒|  
這篇文章主要給大家介紹了關(guān)于Spring中實例化bean的三種方式:構(gòu)造方法、靜態(tài)工廠和實例工廠,對我們學(xué)習(xí)有一定的參考價值,需要的小伙伴可以了解一下

一、環(huán)境準備

準備開發(fā)環(huán)境

  • 創(chuàng)建一個Maven項目
  • pom.xml添加依賴
  • resources下添加spring的配置文件applicationContext.xml

最終項目的結(jié)構(gòu)如下:

二、構(gòu)造方法實例化

在上述的環(huán)境下,我們來研究下Spring中的第一種bean的創(chuàng)建方式構(gòu)造方法實例化:

步驟1:準備需要被創(chuàng)建的類

準備一個BookDao和BookDaoImpl類

public interface BookDao {
    public void save();
}

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }

}

步驟2:將類配置到Spring容器

<?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>

步驟3:編寫運行程序

public class AppForInstanceBook {
    public static void main(String[] args) {
        ApplicationContext ctx = new 
            ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();

    }
}

步驟4:類中提供構(gòu)造函數(shù)測試

在BookDaoImpl類中添加一個無參構(gòu)造函數(shù),并打印一句話,方便觀察結(jié)果。

public class BookDaoImpl implements BookDao {
    public BookDaoImpl() {
        System.out.println("book dao constructor is running ....");
    }
    public void save() {
        System.out.println("book dao save ...");
    }

}

運行程序,如果控制臺有打印構(gòu)造函數(shù)中的輸出,說明Spring容器在創(chuàng)建對象的時候也走的是構(gòu)造函數(shù)

步驟5:將構(gòu)造函數(shù)改成private測試

public class BookDaoImpl implements BookDao {
    private BookDaoImpl() {
        System.out.println("book dao constructor is running ....");
    }
    public void save() {
        System.out.println("book dao save ...");
    }

}

運行程序,能執(zhí)行成功,說明內(nèi)部走的依然是構(gòu)造函數(shù),能訪問到類中的私有構(gòu)造方法,顯而易見Spring底層用的是反射

步驟6:構(gòu)造函數(shù)中添加一個參數(shù)測試

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底層使用的是類的無參構(gòu)造方法。

三、分析Spring的錯誤信息

接下來,我們主要研究下Spring的報錯信息

錯誤信息從下往上依次查看,因為上面的錯誤大都是對下面錯誤的一個包裝,最核心錯誤是在最下面

Caused by: java.lang.NoSuchMethodException: com.itheima.dao.impl.BookDaoImpl.<init>()

  • Caused by 翻譯為引起,即出現(xiàn)錯誤的原因
  • java.lang.NoSuchMethodException:拋出的異常為沒有這樣的方法異常
  • com.itheima.dao.impl.BookDaoImpl.<init>():哪個類的哪個方法沒有被找到導(dǎo)致的異常,<init>()指定是類的構(gòu)造方法,即該類的無參構(gòu)造方法

如果最后一行錯誤獲取不到錯誤信息,接下來查看第二層:

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:嵌套的意思,后面的異常內(nèi)容和最底層的異常是一致的

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.itheima.dao.impl.BookDaoImpl]: No default constructor found;

  • Caused by: 引發(fā)
  • BeanInstantiationException:翻譯為bean實例化異常
  • No default constructor found:沒有一個默認的構(gòu)造函數(shù)被發(fā)現(xiàn)

看到這其實錯誤已經(jīng)比較明顯,給大家個練習(xí),把倒數(shù)第三層的錯誤分析下吧:

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>()。

創(chuàng)建bean異常,錯誤創(chuàng)建bean:實例化bean失敗

因為每一個類默認都會提供一個無參構(gòu)造函數(shù),所以其實真正在使用這種方式的時候,我們什么也不需要做。這也是我們以后比較常用的一種方式。

四、靜態(tài)工廠實例化

接下來研究Spring中的第二種bean的創(chuàng)建方式靜態(tài)工廠實例化:

4.1 工廠方式創(chuàng)建bean

在講這種方式之前,我們需要先回顧一個知識點是使用工廠來創(chuàng)建對象的方式:

(1)準備一個OrderDao和OrderDaoImpl類

public interface OrderDao {
    public void save();
}

public class OrderDaoImpl implements OrderDao {
    public void save() {
        System.out.println("order dao save ...");
    }
}

(2)創(chuàng)建一個工廠類OrderDaoFactory并提供一個==靜態(tài)方法==

//靜態(tài)工廠創(chuàng)建對象
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        return new OrderDaoImpl();
    }
}

(3)編寫AppForInstanceOrder運行類,在類中通過工廠獲取對象

public class AppForInstanceOrder {
    public static void main(String[] args) {
        //通過靜態(tài)工廠創(chuàng)建對象
        OrderDao orderDao = OrderDaoFactory.getOrderDao();
        orderDao.save();
    }
}

(4)運行后,可以查看到結(jié)果

如果代碼中對象是通過上面的這種方式來創(chuàng)建的,如何將其交給Spring來管理呢?

4.2 靜態(tài)工廠實例化

這就要用到Spring中的靜態(tài)工廠實例化的知識了,具體實現(xiàn)步驟為:

(1)在spring的配置文件application.properties中添加以下內(nèi)容:

<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>

class:工廠類的類全名

factory-mehod:具體工廠類中創(chuàng)建對象的方法名

對應(yīng)關(guān)系如下圖:

(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)運行后,可以查看到結(jié)果

看到這,可能有人會問了,你這種方式在工廠類中不也是直接new對象的,和我自己直接new沒什么太大的區(qū)別,而且靜態(tài)工廠的方式反而更復(fù)雜,這種方式的意義是什么?

主要的原因是:

在工廠的靜態(tài)方法中,我們除了new對象還可以做其他的一些業(yè)務(wù)操作,這些操作必不可少,如:

public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        System.out.println("factory setup....");//模擬必要的業(yè)務(wù)操作
        return new OrderDaoImpl();
    }
}

之前new對象的方式就無法添加其他的業(yè)務(wù)內(nèi)容,重新運行,查看結(jié)果:

介紹完靜態(tài)工廠實例化后,這種方式一般是用來兼容早期的一些老系統(tǒng),所以了解為主。

五、實例工廠與FactoryBean

接下來繼續(xù)來研究Spring的第三種bean的創(chuàng)建方式實例工廠實例化:

5.1 環(huán)境準備

(1)準備一個UserDao和UserDaoImpl類

public interface UserDao {
    public void save();
}

public class UserDaoImpl implements UserDao {

    public void save() {
        System.out.println("user dao save ...");
    }
}

(2)創(chuàng)建一個工廠類OrderDaoFactory并提供一個普通方法,注意此處和靜態(tài)工廠的工廠類不一樣的地方是方法不是靜態(tài)方法

public class UserDaoFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

(3)編寫AppForInstanceUser運行類,在類中通過工廠獲取對象

public class AppForInstanceUser {
    public static void main(String[] args) {
        //創(chuàng)建實例工廠對象
        UserDaoFactory userDaoFactory = new UserDaoFactory();
        //通過實例工廠對象創(chuàng)建對象
        UserDao userDao = userDaoFactory.getUserDao();
        userDao.save();
}

(4)運行后,可以查看到結(jié)果

對于上面這種實例工廠的方式如何交給Spring管理呢?

5.2 實例工廠實例化

具體實現(xiàn)步驟為:

(1)在spring的配置文件中添加以下內(nèi)容:

<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

實例化工廠運行的順序是:

創(chuàng)建實例化工廠對象,對應(yīng)的是第一行配置

調(diào)用對象中的方法來創(chuàng)建bean,對應(yīng)的是第二行配置

  • factory-bean:工廠的實例對象
  • factory-method:工廠對象中的具體創(chuàng)建對象的方法名,對應(yīng)關(guān)系如下:

factory-mehod:具體工廠類中創(chuàng)建對象的方法名

(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)運行后,可以查看到結(jié)果

實例工廠實例化的方式就已經(jīng)介紹完了,配置的過程還是比較復(fù)雜,所以Spring為了簡化這種配置方式就提供了一種叫FactoryBean的方式來簡化開發(fā)。

5.3 FactoryBean的使用

具體的使用步驟為:

(1)創(chuàng)建一個UserDaoFactoryBean的類,實現(xiàn)FactoryBean接口,重寫接口的方法

public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    //代替原始實例工廠中創(chuàng)建對象的方法
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }
    //返回所創(chuàng)建類的Class對象
    public Class<?> getObjectType() {
        return UserDao.class;
    }
}

(2)在Spring的配置文件中進行配置

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

(3)AppForInstanceUser運行類不用做任何修改,直接運行

這種方式在Spring去整合其他框架的時候會被用到。

查看源碼會發(fā)現(xiàn),F(xiàn)actoryBean接口其實會有三個方法,分別是:

T getObject() throws Exception;

Class<?> getObjectType();

default boolean isSingleton() {
		return true;
}

方法一:getObject(),被重寫后,在方法中進行對象的創(chuàng)建并返回

方法二:getObjectType(),被重寫后,主要返回的是被創(chuàng)建類的Class對象

方法三:沒有被重寫,因為它已經(jīng)給了默認值,從方法名中可以看出其作用是設(shè)置對象是否為單例,默認true,從意思上來看,我們猜想默認應(yīng)該是單例,如何來驗證呢?

思路很簡單,就是從容器中獲取該對象的多個值,打印到控制臺,查看是否為同一個對象。

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);
    }
}

打印結(jié)果,如下:

通過驗證,會發(fā)現(xiàn)默認是單例,那如果想改成單例具體如何實現(xiàn)?

只需要將isSingleton()方法進行重寫,修改返回為false,即可

//FactoryBean創(chuàng)建對象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    //代替原始實例工廠中創(chuàng)建對象的方法
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    public Class<?> getObjectType() {
        return UserDao.class;
    }

    public boolean isSingleton() {
        return false;
    }
}

重新運行AppForInstanceUser,查看結(jié)果

從結(jié)果中可以看出現(xiàn)在已經(jīng)是非單例了,但是一般情況下我們都會采用單例,也就是采用默認即可。所以isSingleton()方法一般不需要進行重寫。

六、bean實例化小結(jié)

(1)bean是如何創(chuàng)建的呢

構(gòu)造方法

(2)Spring的IOC實例化對象的三種方式分別是:

構(gòu)造方法(常用)

靜態(tài)工廠(了解)

實例工廠(了解)

FactoryBean(實用)

這些方式中,重點掌握構(gòu)造方法和FactoryBean即可。

需要注意的一點是,構(gòu)造方法在類中默認會提供,但是如果重寫了構(gòu)造方法,默認的就會消失,在使用的過程中需要注意,如果需要重寫構(gòu)造方法,最好把默認的構(gòu)造方法也重寫下。

以上就是Spring中Bean的三種實例化方式詳解的詳細內(nèi)容,更多關(guān)于Spring Bean實例化的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論