Spring簡介及xml配置

Java Web發展史

  • 第一階段:JavaBean+Servlet+Jsp逐步發展
  • 第二階段:面對EJB重量級框架帶來的種種麻煩
  • 第三階段:SpringMVC/Struts+Spring+Hibernate/myBatis
  • 第四階段:享受SpringBoot"約定大於配置"的種種樂趣,不少繁瑣的配置都變成了約定
  • 第五階段:以Dubbo爲表明的SOA爲服務架構體系(Dubbo是阿里建立的)
  • 第六階段:比較前沿的技術,SpringCloud 微服務架構技術生態圈(基於SpringBoot,保證了開箱即用,須要什麼SpringCloud都有)

IoC 控制反轉

不僅是SpringIoC,其餘的框架也具備相同的IoC思想及應用:java

  • 控制: 控制對象的建立及銷燬(生命週期)
  • 反轉:將對象的控制權交給IoC容器

IoC容器約定

①全部Bean的生命週期交由IoC容器管理web

②全部被依賴的Bean經過構造方法執行注入spring

被依賴的Bean須要優先建立數據庫

Spring IoC容器使用方法

概述

經過Spring.xml文件實例化Bean.只要Spring.xml中配置了bean標籤,則就會根據class建立這個bean的實例.
把一個java bean交給Spring管理步驟:瀏覽器

一、建立一個xml格式的配置文件websocket

二、在xml文件中定義一個bean,給每一個bean設定一個idsession

三、經過ApplicationContext獲取Spring上下文架構

ApplicationContext context = new ClassPathXmlApplicatioinContext("文件名.xml");

四、獲取beanapp

`Bean bean = context.getBeal("第一步中給bean的id",Bean.class);

一、經過構造方法實例化Bean

步驟1:建立要實例化的類,並提供無參構造方法。框架

public class Bean {
    public Bean(){
        System.out.println("Bean被建立了");
    }

步驟2:spring.xml中配置

<bean id="bean的惟一標識" class="要實例化bean的路徑"></bean>

測試:

ApplicationContext context=new ClassPathXmlApplicationContext(spring.xml的路徑);
Bean bean=context.getBean("bean",Bean.class);
System.out.println(bean);

二、經過靜態工廠方法實例化Bean

經過Bean2的工廠的靜態方法實例化Bean.

步驟1:建立Bean2的工廠Bean2Factory類以及Bean2類,而且提供一個靜態、返回值類型爲Bean2的方法,返回new Bean2()

public class Bean2Factory {
    public static Bean2 getBean2(){
        return new Bean2();
    }
}

public class Bean2 {
    public Bean2(){
        System.out.println("Bean2被建立了。");
    }

步驟2:配置Spring.xml

<bean class="Bean2工廠的路徑" factory-method="Bean2工廠的靜態方法名" id="Bean2工廠的惟一標識"></bean>

測試:

ApplicationContext context=new ClassPathXmlApplicationContext("spring-ioc2.xml");
Bean2 bean=context.getBean("bean2factoryId",Bean2.class);
System.out.println(bean);

三、經過實例工廠方法實例化Bean

經過Bean3的工廠的實例方法實例化Bean.

步驟1:建立Bean3的工廠Bean3Factory類以及Bean3類,而且提供一個返回值類型爲Bean3的方法,方法返回new Bean3()

public class Bean3Factory {
    public  Bean3 getBean3(){
        return new Bean3();
    }
}

public class Bean3 {
    public Bean3(){
        System.out.println("Bean3被建立了。");
    }
}

步驟2:配置Spring.xml

<bean class="main.java.com.imooc2.Bean3Factory" id="bean3Factory"></bean>
<bean class="main.java.com.imooc2.Bean3" factory-bean="bean3Factory" factory-method="getBean3" id="bean3"></bean>

給bean取別名

有類Bean1,而且經過bean標籤實例化Bean1,能夠給Bean1的實例取多個名字。

方式一: bean標籤裏添加name屬性

<bean id="bean" class="main.java.com.imooc1.Bean" name="bean1_1,bean1_2"></bean>

方式二: 添加<alias>標籤

<bean id="bean" class="main.java.com.imooc2.Bean1" name="bean1_1,bean1_2"></bean>
<alias name="bean" alias="bean1_3"/><!-- alias只支持一個別名 -->

依賴注入的方式

image.png

1.經過構造方法注入Bean

image.png
簡化寫法:
image.png

2.經過Set()方法注入Bean

image.png

3.集合類型注入Bean

image.png

image.png

4.注入null空值

image.png

5.注入內部bean

image.png

Spring中Bean的做用域

一、Singleton做用域(單例模式)

經過Spring容器實現單例模式,具備侷限性:保證在一個Spring上下文(ApplicationContext)是單例模式,多個AppliactionContext單例模式就失效了。
image.png

二、prototype做用域(多例模式)

若是一個<bean>的做用域爲prototype,則該<bean>會被實例化屢次,有多個Bean會被建立(每次向Spring上下文請求該Bean都會new一個新的實例)。
image.png
Bean1依賴Bean2,總結起來:
image.png
對於藍框中的狀況,有時候咱們須要單個Bean1,多個Bean2,就要用到方法注入.

方法注入

image.png
Bean2代碼修改:
image.png
Spring.xml修改:
image.png
這樣即便Bean1是單例模式,每次拿到Bean1都會是不一樣的Bean2實例.

三、Web環境做用域

request做用域、session做用域、application做用域、websocket做用域(使用較少).....
request:每次瀏覽器刷新都會實例化一個新的bean;

session:瀏覽器刷新不會實例化新的bean,更換瀏覽器則會實例化新的bean;

application:bean實例化以後就不會改變,更換瀏覽器也不會。

SpringWeb上下文環境

在web.xml中定義:
image.png
不使用DispatcherServlet:
image.png
image.png
以RequestController爲例:
image.png
在spring.xml中添加:
image.png

  • request:每次瀏覽器刷新都會實例化一個新的bean;
  • session:瀏覽器刷新不會實例化新的bean,更換瀏覽器則會實例化新的bean;
  • application:bean實例化以後就不會改變,更換瀏覽器也不會。

image.png

四、自定義做用域

Spring內置的自定義SimpleThreadScope做用域
以自定義雙例模式爲例:

步驟1:實現Scope接口

(org.springframework.beans.factory.config.Scope)主要關注實現的get方法和remove方法。
image.png
get()方法:按照name參數,按照咱們本身定義的規則,去返回一個Bean,若是咱們定義的規則裏,Bean不存在,那麼將經過objectFactory去建立一個Bean。

雙例模式:一個bean的Id對應兩個實例,實現雙例模式,須要兩個Map集合,Map<String,Object> map1=new HashMap<String,Object>();Map<String,Object> map2=new HashMap<String,Object>();。

get()方法:

public Object get(String name, ObjectFactory<?> objectFactory) {
        if(!map1.containsKey(name)){   //判斷map1是否包含名爲name的Bean實例
            Object o=objectFactory.getObject();//若是不存在則建立一個ObjectFactory規則Bean
            map1.put(name, o);   //並把這個Bean放入集合,並命名爲name
            return o;
        }
        if(!map2.containsKey(name)){   //map2同map1操做
            Object o=objectFactory.getObject(); 
            map2.put(name, o);  
            return o;
        }

//若是map1和map2都包含這個Bean,也就是說Spring上下文經過Id獲取有兩個實例,則返回一個0或1
        int i=new Random().nextInt(2);
        if(i==0){
            return map1.get(name);//若是是0,則返回對象1
        }else{
            return map2.get(name);//若是是0,則返回對象2
        }
    }

remove()方法:和get方法相反,按照name參數,去移除一個Bean。

public Object remove(String name) {
        if(map1.containsKey(name)){
            Object o=map1.get(name);
            map1.remove(name);
            return o;
        }
        if(map2.containsKey(name)){
            Object o=map2.get(name);
            map2.remove(name);
            return o;
        }
        return null;    //說明沒拿到任何實例
    }

步驟2: spring.xml配置

<bean id="myScope" class="main.java.com.自定義做用域.MyScope"></bean>

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="myscope" value-ref="myScope"></entry>
        </map>
    </property>
</bean>

測試

@Test
public void testBean(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("spring-zidingyi.xml");
        for(int i=0;i<10;i++){
            Bean bean=ac.getBean(「myScope」", Bean.class);
            System.out.println(bean);
        }
    }

補充:SimpleThreadScope

Spring提供的線程內單例做用域:

  • 同一線程中Spring上下文會分配同一實例
  • 不一樣線程(Thread)中,則得到不一樣實例。

srping配置:

<bean id="myScope" class="main.java.com.自定義做用域.MyScope" ></bean>
<bean id="simpleThreadScope" class="org.springframework.context.support.SimpleThreadScope"></bean>

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
        <entry key="myscope" value-ref="myScope"></entry>
        <entry key="simpleThreadScope" value-ref="simpleThreadScope"></entry>
        </map>
    </property>
</bean>

<bean id="bean11" class="main.java.com.自定義做用域.Bean" scope="simpleThreadScope"></bean>

測試代碼:

public void testBean(){
        final ApplicationContext ac=new ClassPathXmlApplicationContext("spring-zidingyi.xml");

        for(int i=0;i<10;i++){
        new Thread(new Runnable(){
            @Override
            public void run() {
                    Bean bean=ac.getBean("bean11", Bean.class);
                    System.out.println(bean);
            }
        }).start();
    }
    }
}

默認Scope(單例)Bean的懶加載

Spring容器會在建立容器時提早初始化Singleton做用域的bean,可是若是Bean被標註了lazy-init=「true」,則該Bean只有在其被須要的時候纔會被初始化。(只對singleton做用域的bean有效)

<bean id="bean" class="main.java.com.Bean懶加載.Bean" scope="singleton" lazy-init="true"></bean>

多個bean使用懶加載:

<beans default-lazy-init=「true」></beans>

表示spring配置文件裏全部bean都是懶加載模式。
使用場景:
若是某個Bean在程序整個運行週期均可能不會被使用,那麼可考慮設定該Bean爲懶加載。

  • 優勢:儘量的節省了資源。
  • 缺點:可能會致使某個操做相應操做時間增長。

Bean初始化及銷燬

以singleton做用域爲例,假設有一個javaBean,該Bean的做用是鏈接數據庫,該Bean被建立以後,執行數據庫鏈接操做.

Bean初始化

若是須要在Bean實例化時執行一些邏輯,Spring提供了兩種方法:

  • 方法1:bean標籤裏的init-method屬性,該值爲Bean的某一方法,Spring實例化時,會調用Bean的該方法。
  • 方法2:讓Bean實現InitializingBean接口,Spring在實例化該Bean時,檢測到Bean實現了該接口,就會調用該接口所定義的相應方法。

Bean銷燬

若是須要在Bean銷燬以前執行一些邏輯,有兩種方法。

  • 方法1:bean標籤裏的destory-method屬性,該值爲Bean的某一方法,Spring銷燬該Bean時,會調用Bean的該方法。
  • 方法2:讓Bean實現DisposableBean接口,Spring在銷燬該Bean時,檢測到Bean實現了該接口,就會調用該接口所定義的相應方法。

案例1:

經過bean標籤的init-method和destory-method屬性來指定Bean初始化邏輯和銷燬邏輯。
代碼:

public class Bean {
    public void onInit(){
        System.out.println("Bean的初始化邏輯方法被執行了");
    }
    public void onDestory(){
        System.out.println("Bean的銷燬邏輯方法被執行了");
    }
}

spring.xml配置:

<bean class="main.java.com.Bean初始化及銷燬.Bean" 
      id="bean" 
      init-method="onInit" 
      destroy-method="onDestory"/>

測試代碼:

@Test
public void test(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("spring-initAnddestory.xml");
        Bean bean=ac.getBean("bean", Bean.class);
        System.out.println(bean);
    }

結果:bean的銷燬方法沒執行,由於當前是單例模式,因此Bean的初始化是在Spring上下文實例化完成的,Bean的銷燬是在Spring上下文的銷燬過程當中執行Bean的銷燬。(Spring上下文的銷燬定義到AbstractApplicationContext中)

改進:

@Test
public void test(){
        AbstractApplicationContext ac=new ClassPathXmlApplicationContext("spring-initAnddestory.xml");
        Bean bean=ac.getBean("bean", Bean.class);
        System.out.println(bean);
        ac.close();
}

注意:若是全部的Bean都有相同名稱的初始化方法和相同名稱的銷燬方法,能夠在spring.xml中定義:

<beans default-init-method="onInit"   
       default-destory-method="onDestory"/>
案例2:

實現相應接口,並實現相應方法
代碼:

public class Bean implements InitializingBean,DisposableBean{
    @Override
    public void destroy() throws Exception {
        System.out.println("Bean的銷燬邏輯方法被執行了");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean的初始化邏輯方法被執行了");
    }
}

spring.xml配置:

<bean class="main.java.com.Bean初始化及銷燬.Bean" id="bean"></bean>

Bean屬性繼承

應用場景

場景1:

ParentClass(屬性1,屬性2,屬性3,get和set方法)
子類1(屬性4,屬性5) 
子類2(屬性6,屬性7)

場景2:
子類1和子類2沒有父類,而是有一些相同的屬性。

類1:(屬性1,屬性2,屬性3,屬性4,屬性5)
類2:(屬性1,屬性2,屬性3,屬性6,屬性7)

這兩個場景下,經過Spring注入類1和類2的全部屬性,通常以下:

  • abstract="true":設置<bean>標籤只是定義性的,不會對它進行實例化操做。
  • parent屬性:在Bean的子類bean標籤添加,值爲父類的Id。

場景1:
spring.xml配置:

<bean id="bean" class="main.java.com.Bean繼承屬性.ParentClass" abstract="true">
<property name="attribute1" value="attribute1"></property>
<property name="attribute2" value="attribute2"></property> 
<property name="attribute3" value="attribute3"></property>
</bean>

<bean id="bean1" class="main.java.com.Bean繼承屬性.Class1" parent="bean">
<property name="attribute4" value="attribute4"></property>
<property name="attribute5" value="attribute5"></property>
</bean>   

<bean id="bean2" class="main.java.com.Bean繼承屬性.Class2" parent="bean">
<property name="attribute6" value="attribute6"></property>
<property name="attribute7" value="attribute7"></property>
</bean>

場景2:
類1和類2不繼承某一父類,只是存在相同屬性。

spring.xml配置:

<bean id="bean" abstract="true">
<property name="attribute1" value="attribute1"></property>
<property name="attribute2" value="attribute2"></property> 
<property name="attribute3" value="attribute3"></property>
</bean>

<bean id="bean1" class="main.java.com.Bean繼承屬性.Class1" parent="bean">
<property name="attribute4" value="attribute4"></property>
<property name="attribute5" value="attribute5"></property>
</bean>   

<bean id="bean2" class="main.java.com.Bean繼承屬性.Class2" parent="bean">
<property name="attribute6" value="attribute6"></property>
<property name="attribute7" value="attribute7"></property>
</bean>
相關文章
相關標籤/搜索