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

基于SpringIOC創(chuàng)建對象的四種方式總結(jié)

 更新時間:2021年06月21日 08:56:33   作者:_板藍根_  
這篇文章主要介紹了基于SpringIOC創(chuàng)建對象的四種方式總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

我們平時創(chuàng)建對象的方式無非就是以下兩種:

有參構(gòu)造 、無參構(gòu)造

我們來看看在Spring中怎么處理這兩種情況

首先我們先創(chuàng)建一個實體類:

package com.MLXH.pojo;
public class User {
    private String name;
    private String sex;
    private int age;
    public User() {
        System.out.println("User的無參構(gòu)造");
    }
    public User(String name) {
        System.out.println("User的有參構(gòu)造");
        this.name = name;
    }
    public User(String name, int age) {
        System.out.println("User的第二種有參構(gòu)造");
        this.name = name;
        this.age = age;
    }
    public User(String name, String sex, int age) {
        System.out.println("User的第三種有參構(gòu)造");
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    public void setName(String name) {
        System.out.println(name);
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Spring創(chuàng)建對象的方式:

通過有參構(gòu)造

  • 通過下標
  • 通過參數(shù)名 【推薦】
  • 通過參數(shù)類型

通過無參構(gòu)造

  • 默認會用無參構(gòu)造

注意點:實體類中一定要有一個無參構(gòu)造方法

接下來我們看一下Spring是如何裝配這些對象的:

<?xml version="1.0" encoding="UTF-8"?>
<!--suppress SpringFacetInspection -->
<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">
	<!--無參構(gòu)造-->
	<bean id="user" class="com.MLXH.pojo.User">
    </bean>
    <!--無參構(gòu)造,執(zhí)行set方法-->
    <bean id="user1" class="com.MLXH.pojo.User">
        <property name="name" value="寒雪1"/>
    </bean>
    <!--使用構(gòu)造器的參數(shù)下標進行賦值-->
    <bean id="user2" class="com.MLXH.pojo.User">
        <constructor-arg index="0" value="寒雪2"/>
        <constructor-arg index="1" value="18"/>
    </bean>
    <!--通過名字進行賦值-->
    <bean id="user3" class="com.MLXH.pojo.User">
        <constructor-arg name="name" value="寒雪3"/>
        <constructor-arg name="age" value="3"/>
    </bean>
    <!--通過類型進行賦值-->
    <bean id="user4" class="com.MLXH.pojo.User">
        <constructor-arg type="java.lang.String" value="寒雪4"/>
        <constructor-arg type="java.lang.Integer" value="18"/>
        <constructor-arg type="java.lang.String" value="男"/>
    </bean>
</beans>

測試類

package com.MLXH.pojo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserTest {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = (User)context.getBean("user1");
        System.out.println(user.toString());
    }
    @Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = (User) context.getBean("user2");
        System.out.println(user);
    }
    @Test
    public void test3(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = (User) context.getBean("user3");
        System.out.println(user);
    }
}

結(jié)果:運行第一個測試類的結(jié)果:

在這里插入圖片描述

分析:我們針對輸出的結(jié)果進行分析,我們拿到的是user1對象,那么為什么會輸出這么多的語句呢?

原因是我們執(zhí)行了spring的配置文件bean.xml的全部內(nèi)容,當執(zhí)行

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

語句時,會加載beans.xml中的全部內(nèi)容,因此其中所有的裝配信息都會進行加載,會按照我們裝配的順序進行加載。

注意:

<bean id="user1" class="com.MLXH.pojo.User">
        <property name="name" value="寒雪1"/>
</bean>

看似像是執(zhí)行了有參構(gòu)造,但其實是執(zhí)行了無參構(gòu)造,然后通過set方法將,name賦值進去的…就像是執(zhí)行了這樣的代碼:

User user1 = new User();
user1.setName="寒雪1";

這只是執(zhí)行了Test1的,其他的類似…

SpringIOC——控制反轉(zhuǎn)中創(chuàng)建對象的細節(jié)

在剛開始使用Java的時候,創(chuàng)建對象的方式多半是使用 new+對應的構(gòu)造方法,為了進一步提高對象的安全性和降低耦合,開始使用工廠模式和單例模式,通過調(diào)用工廠里的方法獲取對象,再后來通過反射加配置文件的方式,在創(chuàng)建對象的過程中進一步降低耦合。

那么SpringIOC里創(chuàng)建對象的過程是怎樣的呢?具體來說:SpringIOC是什么時候創(chuàng)建對象的?通過哪種方法創(chuàng)建的對象?創(chuàng)建的對象是單例的還是多例的?創(chuàng)建的對象是由誰來保管和控制的?

這些問題不僅僅是Spring需要考慮的,而且是程序員應該考慮的,我們創(chuàng)建對象的效率和對內(nèi)存的使用率很大程度上影響到開發(fā)代碼的優(yōu)劣性。

接下來,我們就通過Spring創(chuàng)建對象的過程,一步步來討論一下Spring框架IOC組件部分,創(chuàng)建對象的細節(jié)。

一、Spring創(chuàng)建對象的過程(在此之前我們已經(jīng)配置好了Spring的配置文件)

啟動spring容器(根據(jù)Spring配置文件不同創(chuàng)建不同的Spring容器)

//啟動spring容器(根據(jù)Spring配置文件不同創(chuàng)建不同的Spring容器)
ApplicationContextcontext =
newClassPathXmlApplicationContext(
"resources/spring_ioc.xml");

這里實現(xiàn)的步驟如下:

1.讀取resources文件下spring_ioc.xml

2.Xml解析spring_ioc.xml

3.把解析xml里的內(nèi)容存儲到內(nèi)存的map集合中

4.從map集合中讀取集合內(nèi)容,就是<Bean></Bean>清單里的內(nèi)容

5.遍歷集合中的所有數(shù)據(jù),并反射實例化對象

Class.forName(“com.spring.ioc.Hello”).newInstance()

從容器中取出對象,以及使用對象

//從spring容器中獲取對象hello
Hello hello = (Hello)context.getBean("Hello");
//使用hello對象調(diào)用sayHello方法
hello.sayHello();

以上關(guān)鍵的兩個環(huán)節(jié)中,需要重點理解的是spring容器為什么能創(chuàng)建保管對象,因為Spring在初始化的時候,就將Bean 里的屬性調(diào)入放入到一個map集合中區(qū)維護了,這個map集合的key=”id”,value=”object” (反射實例化的對象),spring容器在底層就相當于這個map<id,object>,而Bean就被存放在這個map中。

當我們把spring容器啟動好以后,也就是context對象創(chuàng)建完成后,通過調(diào)用context對象里的getBean()方法來從map中用key尋找value,從而獲取對象。

細化分析:啟動Spring容器時,將Bean存儲到Map集合中,需要調(diào)用反射來實例化Bean中封裝的類路徑,那么xml配置文件中每存儲一個不同的Bean,就會實現(xiàn)一次反射,產(chǎn)生一個實例對象,也就是說,Spring容器中產(chǎn)生的對象僅和xml配置文件相關(guān),與取出對象操作無關(guān),Spring可以實例化一個類多次(<Bean/>中id不同,class相同),也可以只實例化一個類一次,但多次調(diào)用。單例的創(chuàng)建時間是在Spring容器啟動時。

二、創(chuàng)建對象的四種方式

由上我們知道Spring底層是通過反射來創(chuàng)建對象的,那我們在創(chuàng)建類的時候,可以創(chuàng)建實體類,抽象類,接口等等,spring底層反射到底使用什么方法來創(chuàng)建對象呢?這就需要考慮我們是創(chuàng)建什么對象了。

1. 無參構(gòu)造

反射是通過無參構(gòu)造來實例化類的,所以,如果我們創(chuàng)建一個實體類,并想將類產(chǎn)生的實例放到spring容器中,必須保證這個類有無參構(gòu)造。當這個類中未寫構(gòu)造器時,java編譯器會在編譯時自動添加一個無參構(gòu)造,但是如果這個類中有含參構(gòu)造時,只能通過人工添加無參構(gòu)造來實現(xiàn)反射,這一點在以后的開發(fā)設(shè)計中要牢記。

2. 靜態(tài)工廠設(shè)計模式

那抽象類怎么實例化呢?抽象類無法直接實例化,只能通過添加靜態(tài)工廠的方式,在工廠中添加靜態(tài)方法返回抽象類的getInstance()方法,從而獲取實例對象。

這時,我們需要一個抽象類,一個工廠類,而且xml中的配置文件也需要發(fā)生變化,<Bean>中class類的加載路徑需要指定為工廠類,而且需要指定新的屬性為:factory-method=”get抽象類的實例對象方法”。

例:我們需要用util包下的Calendar這個抽象日期類。

靜態(tài)工廠代碼為:

        package staticfactory;
        import java.util.Calendar;
        public class StaticFactory {
               public static Calendar getCalendar(){
                      return Calendar.getInstance();
               }
         }

Xml文件中的Bean應該修改成:

<bean id="cal" class="staticfactory.StaticFactory" factory-method="getCalendar"/>

測試可使用:雙擊test2方法右鍵run as》JUnit得到當前電腦的系統(tǒng)時間。

@Test
publicvoid test2(){
      //啟動spring容器
     ApplicationContextcontext =
     newClassPathXmlApplicationContext("staticfactory/applicationContext.xml");
     Calendar calendar = (Calendar)context.getBean("cal");
     System.out.println(calendar.getTime());
}

無法直接實例化的類就可以使用靜態(tài)工廠法。

此時Spring中并未創(chuàng)建工廠這個類,而是根據(jù)<Bean/>中的factory—method屬性,直接調(diào)用工廠的getCalendar靜態(tài)方法,產(chǎn)生的實例只有一個,就是工廠中,getCalendar靜態(tài)方法通過調(diào)用Calendar.getInstance()方法產(chǎn)生的實例。

3. 實例工廠設(shè)計模式

靜態(tài)工廠設(shè)計模式不會創(chuàng)建工廠類對象,而是直接調(diào)用靜態(tài)工廠的靜態(tài)方法。而工廠方法設(shè)計模式會創(chuàng)建類,然后通過xml中配置去訪問其方法。

例:同樣是需要Calendar這個抽象類

package methodfactory;
import java.util.Calendar;
public class MethodFactory {
       publicMethodFactory() {
      System.out.println("如果創(chuàng)建工廠類的實例,必定會打印這句話!");
       }
       publicCalendar getCalendar(){
      returnCalendar.getInstance();
       }
}

Xml中的配置由一個變?yōu)閮蓚€(這也證明了上述結(jié)論,配置文件中<Bean/>的個數(shù)影響產(chǎn)生的實例對象的個數(shù))

<bean id="methodFacotry" class="methodfactory.MethodFactory"/>
<bean id="cal" factory-bean="methodFacotry"  factory-method="getCalendar"/>

測試可使用:雙擊test2方法右鍵run as》JUnit得到當前電腦的系統(tǒng)時間。

@Test
public void test(){
//啟動spring容器
ApplicationContext context =
newClassPathXmlApplicationContext("methodfactory/applicationContext.xml");
Calendar calendar = (Calendar)context.getBean("cal");
System.out.println(calendar.getTime());
}

輸出結(jié)果為上述打印的那句話和系統(tǒng)時間,兩個<Bean/>產(chǎn)生兩個實例對象。

4. Spring工廠設(shè)計模式

這是Spring框架自身提供的工廠,它需要實現(xiàn)FactoryBean接口,實現(xiàn)代碼就必須寫在getObject()方法中。Spring工廠實現(xiàn)一個接口就可以了,簡單方便。

例:

創(chuàng)建SpringFactory類實現(xiàn)FactoryBean接口,定義泛型<Calendar>

package springfactory;
import java.util.Calendar;
import org.springframework.beans.factory.FactoryBean;
public class SpringFactory implements FactoryBean<Calendar>{
public SpringFactory() {
System.out.println("我是一個spring工廠類");
}
               
public Calendar getObject()throws Exception {
return Calendar.getInstance();
}
               
public Class<?> getObjectType() {
return Calendar.class;
}
               
public boolean isSingleton() {
return false;
}
}

配置xml文件中的Bean元素:

<bean id="cal"class="springfactory.SpringFactory"/>

測試可使用:雙擊test3方法右鍵run as》JUnit得到當前電腦的系統(tǒng)時間。

@Test
public void test3(){
//啟動spring容器
ApplicationContext context =
newClassPathXmlApplicationContext("springfactory/applicationContext.xml");
Calendar calendar = (Calendar)context.getBean("cal");
System.out.println(calendar.getTime());
}

三、Spring創(chuàng)建對象是單例還是多例?+懶加載

單例就是指在在Spring容器中的對象只有一個,每次從spring容器中取出不會產(chǎn)生新的對象。

多例就是每次從Spring容器中取出對象的時候會產(chǎn)生新的對象,內(nèi)存中存在多個對象。

默認情況下,spring中創(chuàng)建的對象都是單例,并且維護其生命周期。單例對象的生命周期與spring容器共命運,同生共死。

但如果對象是多例的,那么Spring容器只負責對象的創(chuàng)建,不負責維護其生命周期,也就是說如果容器關(guān)閉,對象并未銷毀,需要用戶自行關(guān)閉。

具體實現(xiàn)代碼是在Bean標簽中插入屬性

 
<bean id="Hello" class="com.spring.ioc.Hello"scope="prototype"/>

Scope屬性代表了spring創(chuàng)建對象是單例還是多例。

那么單例多例各有什么優(yōu)缺點呢?

單例的好處就是,spring創(chuàng)建后,那就不會再頻繁創(chuàng)建,緩存在map中,省內(nèi)存。壞處,對象里的數(shù)據(jù)不安全,即線程不安全

多例的好處就是隨時用隨時創(chuàng)建,線程安全,缺點是占用內(nèi)存。

單例多例各有各的特點,思考一個問題,如果Spring容器中要使用很多次單例,那么單例是不是喪失了它的優(yōu)勢呢?即使沒有業(yè)務調(diào)用這些對象,這些對象依然在spring容器加載的時候產(chǎn)生,不僅僅浪費了容器的容量,還延長了加載時間,這時候我們就需要用懶加載,堆單例模式進行改造了。

首先我們可以在全局配置(第一個<Bean/>)中添加default-lazy-init="true",這樣就默認使用懶加載。

或者在單例的配置中添加:

<bean id="Hello"class="com.spring.ioc.Hello" scope="singleton"lazy-init="true"/>

另外,多例模式都是懶加載,當多例模式的懶加載被設(shè)置為false時,會報錯!

四、對象的創(chuàng)建和保管(初始化+銷毀)

Spring 容器執(zhí)行過程

1.new Instance----調(diào)用構(gòu)造方法創(chuàng)建對象

2.Init-method------執(zhí)行初始化方法

3.對象調(diào)用方法。

4.容器關(guān)閉,執(zhí)行銷毀方法 ,如果scope=”property”時讓其不負責對象的銷毀

總結(jié)

通過對Spring內(nèi)對象產(chǎn)生的細節(jié)進行探究,了解Spring底層創(chuàng)建實例的方式,通過熟練使用這些方式,掌握對Spring框

架的理解,這樣對程序員的自我成長是很好的~

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 深入理解Java設(shè)計模式之組合模式

    深入理解Java設(shè)計模式之組合模式

    這篇文章主要介紹了JAVA設(shè)計模式之組合模式的的相關(guān)資料,文中示例代碼非常詳細,供大家參考和學習,感興趣的朋友可以了解下
    2021-11-11
  • spring springMVC中常用注解解析

    spring springMVC中常用注解解析

    這篇文章主要介紹了spring springMVC中常用注解,本文給大家介紹的非常詳細,需要的朋友可以參考下
    2018-05-05
  • springcloud LogBack日志使用詳解

    springcloud LogBack日志使用詳解

    這篇文章主要介紹了springcloud LogBack日志使用,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10
  • Struts2框架初學接觸

    Struts2框架初學接觸

    本文主要給大家從初學者的角度介紹了Struts2框架結(jié)構(gòu)和基本頁面代碼等內(nèi)容,一起來學習一下。
    2017-11-11
  • ArrayList源碼和多線程安全問題分析

    ArrayList源碼和多線程安全問題分析

    這篇文章主要介紹了ArrayList源碼和多線程安全問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,下面小編和大家一起來學習一下吧
    2019-05-05
  • 淺談spring容器中bean的初始化

    淺談spring容器中bean的初始化

    下面小編就為大家?guī)硪黄獪\談spring容器中bean的初始化。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • 實例代碼講解JAVA 觀察者模式

    實例代碼講解JAVA 觀察者模式

    這篇文章主要介紹了JAVA 觀察者模式的的相關(guān)資料,文中代碼非常詳細,幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-06-06
  • Spring使用xml方式整合第三方框架流程詳解

    Spring使用xml方式整合第三方框架流程詳解

    這篇文章主要介紹了Spring使用xml方式整合第三方框架流程,Spring會在應用上下文中為某個bean尋找其依賴的bean,Spring中bean有三種裝配機制,分別是:在xml中顯式配置、在java中顯式配置、隱式的bean發(fā)現(xiàn)機制和自動裝配
    2023-02-02
  • Java如何實現(xiàn)Unicode和中文相互轉(zhuǎn)換

    Java如何實現(xiàn)Unicode和中文相互轉(zhuǎn)換

    這篇文章主要介紹了Java如何實現(xiàn)Unicode和中文相互轉(zhuǎn)換問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 已有的springcloud+mybatis項目升級為mybatis-plus的方法

    已有的springcloud+mybatis項目升級為mybatis-plus的方法

    這篇文章主要介紹了已有的springcloud+mybatis項目升級為mybatis-plus,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03

最新評論