Spring 4.1.6(二)

前言

經過上一節,對spring的介紹,相信讀者,對spring,有了大致的瞭解。大量篇幅的文字,看着就有點讓人不耐煩,下面,我們就着手動起來。關於此係列的學習,依賴都是通過maven 去管理的。

Eclipse 安裝spring插件

工慾善其事必先利其器,在eclipse 安裝spring 插件將有利於我們的學習。

安裝的時候,一定要注意eclipse 的版本,另外,spring 官網,一般都是最新的插件,在哪找歷史的。

添加鏈接描述,可以參考這篇博客,安裝的步驟,就不說,網上一大堆。

Helloworld Spring

首先先添加Spring 的依賴

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.1.6.RELEASE</version>
</dependency>

定義一個POJO Java 對象類

public class HelloWord {
	private String message;

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
}

定義Beans.xml文件:

<?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="helloworld" class="test.HelloWord">
 <property name="message" value="hello spring"></property>//這裏的name 是你的屬性名,必須和POJO 對象的屬性一致,value 是傳入該屬性的值
 </bean>
</beans>

對於Bean 的Id ,我們一定要保證它的唯一性。

創建的Beans.xml 的目錄最好在maven工程下的src/main/java,這就是相當於傳統Java 項目的src(src是目錄的頂層),所以上面class,是從test開始的。還有注意的,Beans.xml 這個命名不是隨意的

在main 函數裏面測試:

	ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
		HelloWord h =  (HelloWord) context.getBean("helloworld");//這裏的就是Beans.xml的配置的bean 的id,去獲取該POJO 對象的。
	    System.out.println(h.getMessage());

ClassPathXmlApplicationContext 這個是負責加載配置文件,以及實例化所有的對象。

Spring 容器

容器負責創建對象,配置對象,管理對象的生命週期,從創建到消亡。這些對象,在Spring 中,被稱之爲Bean。配置Bean 的元數據庫,可以是在Xml、Java 註解或者Java 代碼中。(比如上面的例子,就是在Xml)。

下面是容器工作圖:

在這裏插入圖片描述

Spring 容器類型

分兩種:

  1. Spring BeanFactory Container

最簡單的容器

  1. Spring ApplicationContext Container

這個容器,比上面的更高級,對於企業級應用,推薦使用這個。它的功能包含上面容器所有的。

Bean 定義

對象在Spring 容器中管理,從稱之爲Bean。Bean 一個對象,但是該對象是被實例化了,組裝屬性的。這些Bean 被創通過你在配置的元數據,去創建。

Bean 的定義,被稱之爲配置元數據,你配置這些數據,去讓容器知道:

  1. 怎麼去創建Bean
  2. Bean 的生命週期
  3. Bean 的依賴

Bean 的元數據配置是通過下面一系列的方法:

property Description
class 這個屬性是必須的,指定Bean 的class
name 這個屬性是區分Bean 的,也是通過該屬性獲取Bean 對象,所以必須保證唯一性
scope 指明Bean 的作用域
constructor-arg 被用來指定依賴,後面有細講
properties 被用來指定依賴,後面有細講
autowiring mode 被用來指定依賴,後面有細講
lazy-initialization mode 懶加載,告訴容器創建Bean 實例,不是在開始,而是在第一次請求
initialization method 初始化方法,所有的屬性都由容器創建好了,回調的方法
destruction method 銷燬方法,所有的屬性都由容器創建好了,回調的方法
Bean 元數據配置方式
  1. 基於Xml
  2. 基於註解
  3. 基於Java 代碼

Bean 作用域

Scope Description
singleton(單例) 該Bean作用域是整個容器, 只有一個Bean 實例
prototype(原型) 該Bean作用域是,一個Bean可以有多個實例
request 這將bean定義範圍限定爲HTTP請求。 在Web應用中,爲每個請求創建一個bean實例。
session 這將bean定義範圍限定爲session。 在Web應用中,爲每個會話創建一個bean實例
Singleton

將上述Hello world 代碼,main 中的代碼,做如下的修改:

ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
		HelloWord h =  (HelloWord) context.getBean("helloworld");
		h.setMessage("i am new Spring");
	    System.out.println(h.getMessage());
		HelloWord h1 =  (HelloWord) context.getBean("helloworld");
	    System.out.println(h1.getMessage());

這裏句不需要修改Beans.xml,因爲Bean 默認就是這種作用域。

執行之後,你會發現兩次打印的一致。實際上,採用這種模式的作用域,容器將把第一次實例的對象,放到緩存中,之後所有的請求,都是在緩存中拿,而不是重新去創建新的實例。

prototype

這種作用域,容器會爲每一個Bean 創建新的實例。

基於上面的例子,我們修改Beans.xml:

 <bean id="helloworld" class="test.HelloWord" scope="prototype">

同樣運行,這次,就一樣的結果。說明每一個獲取的Bean 實例,是不同的。

Bean 生命週期

當一個Bean 需要使用的時候,它通過容器去創建,當不需要的,從容器上移除。

public class ExampleBean {
	public void init() {
		System.out.println("bean start init");
	}
	public void destorty() {
		System.out.println("bean is destory");
	}
}
 <bean id="examplebean" class="test.ExampleBean" init-method="init" destroy-method="destorty"></bean>//這裏填寫對應的init 的destory 方法名,這個你保持和Bean 的方法一致即可。
 

還可以實現InitializingBean or DisposableBean 接口,實現Bean 的初始化和銷燬,但是不建議,它會直接要你重寫方法民,靈活性不行。

當如果多個Bean 裏面都有這麼一樣的初始化、銷燬的方法,可以可以直接在Beans 標籤中,通過配置default-init-method and default-destroy-method 來減少重複性的設置。

如果上述你是web 應用,那麼關閉服務器,就可以發現執行了destory 方法,init 方法不用說,創建的時候直接執行。也可以通過AbstractApplicationContext 的registerShutdownHook 去模擬容器的關閉。

AbstractApplicationContext  context = new ClassPathXmlApplicationContext("Beans.xml");
		ExampleBean eb = (ExampleBean) context.getBean("examplebean");
		context.registerShutdownHook();

BeanPostProcessor

如果我們需要在Spring容器完成Bean的實例化、配置和其他的初始化前後添加一些自己的邏輯處理,我們就可以定義一個或者多個BeanPostProcessor接口的實現,然後註冊到容器中。

實例化Bean 的流程:

在這裏插入圖片描述

public class InitHelloWorld implements BeanPostProcessor {
         //Bean 初始化前
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("before init bean "+beanName);
		return bean;//這個地方在創建的時候,一定要注意就是返回bean 對象,否則會引起異常。
	}
	//Bean 初始化後
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("after init bean "+beanName);

		return bean;
	}

}
 <bean class="test.InitHelloWorld"></bean>//這個Bean 是沒有id的,你不需要管他

ApplicationContext 會自動檢測到所有實現該接口的Bean,並自動註冊到容器中,所以,你還是要在Beans.xml中定義。

隨便獲取一個之前配置的Bean,會發現執行上面兩個方法,在bean 初始化前後。

Bean 的繼承

一個子類的Bean可以繼承父類的Bean,可以重新相關的屬性,以及添加自己需要的。

原先的HelloWorld 類不動,在編寫一個子類:

public class SubHelloWorld {
	private String message;
	private String sonmessage;
	//相應的set、get方法省略,自行補充

}

這裏有一點需要注意:儘管是繼承,這裏必須要重新定義父類的屬性,否則儘管下面設置繼承關係,一樣沒辦法設置父類的屬性,並且這個父類屬性必須要和父類設置一樣。

注意這裏雖然是繼承關係,但是不需要像Java 一樣通過extends ,繼承的關係,在下面Bean配置的標籤parent 來體現:

<bean id="helloworld" class="test.HelloWord" scope="prototype">
 <property   name="message" value="hello spring" ></property>
 </bean>
 <bean id="subhelloworld" class="test.SubHelloWorld"  parent="helloworld">//parent 後面是跟的是父類Bean 的id
 <property name="sonmessage" value="i am son hello world"></property>//在這我們也可以設置父類的message 屬性,修改爲子類自己特有的,也可以不設置,就是父類的。
 
 </bean>

注意:一定你指定繼承關係,如果直接獲取子類的Bean,是可以獲取父類的屬性,無需多此一舉,在get父類的Bean。

Bean 模板

在Java se 中,我們都知道可以定義一個抽象類加上繼承,去實現一個公用的模板類,在Spring 也一樣。

在上述代碼,修改helloworld,將其定義成抽象的。

 <bean id="helloworld" class="test.HelloWord" abstract="true"></bean>

這樣父類可以定義一些屬性,子類可以直接用,或者重新賦值,子類還是要定義父類的屬性(一模一樣)。將父類定義成抽象的好處,父類就是一個純潔的Bean 定義模板。

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