Spring| 上下文和Bean的生命週期3

需要解決的問題:
1.如何使用多個Spring-context的配置文件來生成Spring的上下文?
2.各種上下文的使用方式?


一.Spring容器介紹

在基於Spring的應用中,你的應用對象生存於Spring容器(container)中。如圖1.4所示,Spring容器負責創建對象,裝配它們,配置它們並管理它們的整個生命週期,從生存到死亡(在這裏,可能就是new到finalize())。
在這裏插入圖片描述

Spring容器分成兩類:

  • bean工廠容器
  • Spring上下文容器 (主要研究對象)

Spring容器並不是只有一個。Spring自帶了多個容器實現,可以歸爲兩種不同的類型。bean工廠(由org.springframework. beans. factory.eanFactory接口定義)是最簡單的容器,提供基本的DI支持。應用上下文(由org.springframework.context.ApplicationContext接口定義)基於BeanFactory構建,並提供應用框架級別的服務,例如從屬性文件解析文本信息以及發佈應用事件給感興趣的事件監聽者。雖然我們可以在bean工廠和應用上下文之間任選一種,但bean工廠對大多數應用來說往往太低級了,因此,應用上下文要比bean工廠更受歡迎。我們會把精力集中在應用上下文的使用上,不再浪費時間討論bean工廠。


二.Spring的ApplicationContext(上下文)

Spring自帶了多種類型的應用上下文。 下面是幾種常見的上下文:(5種)

  • AnnotationConfigApplicationContext: 從一個或多個基於Java的配置類中加載Spring應用上下文。
  • AnnotationConfigWebApplicationContext: 從一個或多個基於Java的配置類中加載Spring Web應用上下文。
  • ClassPathXmlApplicationContext: 從類路徑下的一個或多個XML配置文件中加載上下文定義, 把應用上下文的定義文件作爲類資源。
  • FileSystemXmlapplicationcontext: 從文件系統下的一個或多個XML配置文件中加載上下文定義。
  • XmlWebApplicationContext: 從Web應用下的一個或多個XML配置文件中加載上下文定義。

Web應用中兩種模式:(第8章節詳細介紹)

  • 1.AnnotationConfigWebApplicationContext
  • 2.XmlWebApplicationContext

非Web下的三種使用方式如下:
首先看一下本次測試的項目結構:
在這裏插入圖片描述

每個測試都會有一個 spring-content-4XXX.xml 的配置,其基本內容如下,每個配置文件只是user實例屬性中name的注入值有區別,這裏是爲了方便觀察輸出的測試結果

<?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="user" class="com.yveshe.chapter1.User">
		<constructor-arg name="name" value="yveshe-XXX" />
		<constructor-arg name="age" value="18" />
		<constructor-arg name="role" ref="role" />
	</bean>

	<bean id="role" class="com.yveshe.chapter1.Role">
		<property name="id" value="4d53a9ab-e858-4369-8240-46dd497ace3e"></property>
		<property name="name" value="系統管理員"></property>
		<property name="desc" value="擁有整個系統的管理權限"></property>
	</bean>

</beans>

  • 1.文件系統的方式:

    ApplicationContext context = new FileSystemXmlApplicationContext("spring-content-4xxx.xml");
    

    資源存放結構如下:
    在這裏插入圖片描述

    測試類和測試結果如下:(注意觀察name屬性的值)

    /**
     * 從文件系統下的一個或多個XML配置文件中加載上下文定義
     *
     * @author YvesHe
     *
     */
    public class FileSystemXmlapplicationcontextTest {
    
        public static void main(String[] args) {
            String configLocation = "conf//chapter1//spring-content-4FileSystemXmlapplicationcontextTest.xml"; // 相對路徑,也支持絕對路徑
            configLocation = "D://git//spring-study//conf//chapter1//spring-content-4FileSystemXmlapplicationcontextTest.xml";
            FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(configLocation);
            User bean = context.getBean(User.class);
            context.close();
    
            System.out.println(JsonUtil.toJson(bean, true)); // 輸出用戶信息
        }
    }
    
    
    /**輸出結果:
    {
        "age":18,
        "name":"yveshe-FileSystemXmlapplicationcontextTest",
        "role":{
            "desc":"擁有整個系統的管理權限",
            "id":"4d53a9ab-e858-4369-8240-46dd497ace3e",
            "name":"系統管理員"
        }
    }
    **/
    
  • 2.類路徑方式(包含Jar中配置文件)

     ApplicationContext context = new ClassPathXmlApplicationContext("spring-content-4xxx.xml");
    

    使用FileSystemXmlApplicationContext和使用ClassPathXmlApp-licationContext的區別在於: FileSystemXmlApplicationContext在指定的文件系統路徑下查找spring上下文的配置文件; 而ClassPathXmlApplicationContext是在所有的類路徑(包含JAR文件)下查找spring上下文配置文件

    2.1首先我們來看看直接使用classpath下的配置文件來構建Spring上下文的例子:
    資源存放結構在classpath下:
    在這裏插入圖片描述
    測試類和測試結果如下:(注意觀察name屬性的值)

    /**
     * 類路徑下的一個或多個XML配置文件中加載上下文定義
     *
     * @author YvesHe
     *
     */
    public class ClassPathXmlApplicationContextTest {
    
        public static void main(String[] args) {
            String configLocation = "spring-content-4ClassPathXmlApplicationContextTest.xml";
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
            User bean = context.getBean(User.class);
            context.close();
            System.out.println(JsonUtil.toJson(bean, true)); // 輸出用戶信息
        }
    }
    
    /**輸出結果:
    {
        "age":18,
        "name":"yveshe-ClassPathXmlApplicationContextTest",
        "role":{
            "desc":"擁有整個系統的管理權限",
            "id":"4d53a9ab-e858-4369-8240-46dd497ace3e",
            "name":"系統管理員"
        }
    }
    **/
    

    2.2接下里看下使用ClassPathXmlApplicationContext來讀取Jar包中配置文件來構建Spring的上下文方式:

    spring-context.jar中只有一個配置文件沒有其他多餘的內容
    在這裏插入圖片描述
    測試代碼以及結果如下: (注意觀察name屬性的值)

    /**
     * 類路徑下的一個或多個XML配置文件中加載上下文定義
     *
     * @author YvesHe
     *
     */
    public class ClassPathXmlApplicationContextInJarTest {
    
        public static void main(String[] args) {
            String configLocation = "spring-content-4ClassPathXmlApplicationContextInJarTest.xml";
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
            User bean = context.getBean(User.class);
            context.close();
            System.out.println(JsonUtil.toJson(bean, true)); // 輸出用戶信息
        }
    }
    
    /**輸出結果:
    {
        "age":18,
        "name":"yveshe-ClassPathXmlApplicationContextInJarTest",
        "role":{
            "desc":"擁有整個系統的管理權限",
            "id":"4d53a9ab-e858-4369-8240-46dd497ace3e",
            "name":"系統管理員"
        }
    }
    **/
    
  • 3.Java配置類方式
    如果你想從Java配置中加載應用上下文, 那麼可以使用AnnotationConfigApplicationContext, 在這裏不需要指定加載Spring應用上下文所需的XML文件, 而是通過一個配置類加載bean的。配置結構如下
    在這裏插入圖片描述

@Configuration
@ComponentScan(basePackageClasses = com.yveshe.chapter1.AnnotationConfigApplicationContextTest.class)
public class SpringContextConf {

    @Bean
    public Role someName() {
        Role role = new Role();
        role.setDesc("擁有整個系統的管理權限");
        role.setId("4d53a9ab-e858-4369-8240-46dd497ace3e");
        role.setName("系統管理員");
        return role;
    }

    @Bean
    public User someName2() {
        User user = new User();
        user.setAge(18);
        user.setName("yveshe-AnnotationConfigApplicationContextTest");
        user.setRole(this.someName());
        return user;
    }
}

@Configuration:
表明這個類是一個配置類, 該類應該包含在Spring應用上下文中如何創建bean的細節。

@Bean:
類似XMl配置中Bean標籤的配置

@ComponentScan:
類似XML配置中配置掃描包的設置(basePackageClasses: 配置掃描包的路徑爲該類所在包),方法名稱可以隨意取.

測試代碼以及結果如下: (注意觀察name屬性的值)

/**
 * 從一個或多個基於Java的配置類中加載Spring應用上下文
 *
 * @author YvesHe
 *
 */
public class AnnotationConfigApplicationContextTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringContextConf.class);
        User bean = context.getBean(User.class);
        context.close();
        System.out.println(JsonUtil.toJson(bean, true)); // 輸出用戶信息
    }
}


/**輸出結果:
{
    "age":18,
    "name":"yveshe-AnnotationConfigApplicationContextTest",
    "role":{
        "desc":"擁有整個系統的管理權限",
        "id":"4d53a9ab-e858-4369-8240-46dd497ace3e",
        "name":"系統管理員"
    }
}
**/

三.Spring中Bean的Lifecycle(生命週期)

在傳統的Java應用中, bean的生命週期很簡單。 使用Java關鍵字new進行bean實例化, 然後該bean就可以使用了。 一旦該bean不再被使用,則由Java自動進行垃圾回收。
相比之下, Spring容器中的bean的生命週期就顯得相對複雜多,下圖展示的是 bean裝載到Spring應用上下文中的一個典型的生命週期過程:
在這裏插入圖片描述
bean在Spring容器中從創建到銷燬經歷了若干階段, 每一階段都可以針對Spring如何管理bean進行個性化定製.

正如你所見, 在bean準備就緒之前, bean工廠執行了若干啓動步驟。接下來對上圖進行詳細描述:

  • 1. Spring對bean進行實例化;
  • 2. Spring將值和bean的引用注入到bean對應的屬性中;
  • 3. 如果bean實現了BeanNameAware接口, Spring將bean的ID傳遞給setBean-Name()方法;
  • 4. 如果bean實現了BeanFactoryAware接口, Spring將調用setBeanFactory()方法, 將BeanFactory容器實例傳入;
  • 5. 如果bean實現了ApplicationContextAware接口, Spring將調用setApplicationContext()方法, 將bean所在的應用上下文引用傳入進來;
  • 6. 如果bean實現了BeanPostProcessor接口, Spring將調用它們的post-ProcessBeforeInitialization()方法;
  • 7. 如果bean實現了InitializingBean接口, Spring將調用它們的after-PropertiesSet()方法。 類似地, 如果bean使用initmethod聲明瞭初始化方法, 該方法也會被調用;
  • 8. 如果bean實現了BeanPostProcessor接口, Spring將調用它們的post-ProcessAfterInitialization()方法;
  • 9. 此時, bean已經準備就緒, 可以被應用程序使用了, 它們將一直駐留在應用上下文中, 直到該應用上下文被銷燬;
  • 10. 如果bean實現了DisposableBean接口, Spring將調用它的destroy()接口方法。 同樣, 如果bean使用destroy-method聲明瞭銷燬方法, 該方法也會被調用。

現在你已經瞭解瞭如何創建和加載一個Spring容器。 但是一個空的容器並沒有太大的價值, 在你把東西放進去之前, 它裏面什麼都沒有。爲了從Spring的DI中受益, 我們必須將應用對象裝配進Spring容器中。 接下來我們將對bean裝配進行更詳細的探討。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章