1. 程式人生 > >spring學習筆記——spring Hello world 普通java專案版 分析類的載入與裝配

spring學習筆記——spring Hello world 普通java專案版 分析類的載入與裝配

上一篇展示了spring的web版hello world,本篇來一個普通java專案中運用spring的demo,裡面有對singleton與prototype的討論,可以很清晰的看到spring對實體的注入策略。

因為是個demo,後來看工廠後處理器以及bean前、bean後處理器的時候加入了一個簡單地BeanPostProcessorImpl實現類,在此一起展現。

專案結構:

建專案、導包、建立好目錄結構後,我們來寫bo.DoSth類,很簡單的輸出字串。

注意此處在初始化的時候把字串初始化為了“haha"

package bo;

public class DoSth {
	private String text = null;
	public DoSth(){
		this.text = "haha";
	}
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
	
}
下面看上一層的view.OutputView,
package view;

import bo.DoSth;

public class OutputView {
	private String viewText = null;
	private DoSth doSth = null;
	
	public OutputView() {
		this.viewText = "haha";
	}
	public String outPut(){
		return this.doSth.getText();
	}
	public DoSth getDoSth() {
		return doSth;
	}
	public void setDoSth(DoSth doSth) {
		this.doSth = doSth;
	}
	public String getViewText() {
		return viewText;
	}
	public void setViewText(String viewText) {
		this.viewText = viewText;
	}
	
}
這個類有一個自己的私有欄位。viewText我們也把它初始化為“haha”。

下面來寫配置檔案:

<?xml version="1.0" encoding="UTF-8"?>
<beans
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context-3.1.xsd">
		
	<context:component-scan base-package="bo" />
	
<bean id="doSth" class="bo.DoSth" p:text="hehe" />
<bean id="view" class="view.OutputView" p:doSth-ref="doSth" scope="prototype" /></beans>
檔案頭裡有很多冗餘的引用,太懶,沒刪掉。關於Spring的schema列表請移步【http://blog.csdn.net/gklifg/article/details/15337099

配置有三條:註解掃描bo包;裝配doSth物件;裝配view物件;

在doSth裝配時使用p名稱空間指定了text屬性的值,這樣會覆蓋掉構造方法中初始化操作。

Spring預設的物件作用域(為什麼叫作用域?很不貼切啊)是Singleton。而view的配置中我們制定了其作用域為prototype。那麼如果我們多次使用Spring獲取view物件,會得到多個獨立的veiw例項。然而doSth用了預設的Singleton,所以即使有多個view物件,這些物件中的doSth屬性也都是指向同一個doSth例項。下面的例子可以很好地展示這個結構。

然後開始java普通專案呼叫Spring框架的關鍵,建立ApplicationContext介面物件,這裡採用的是FileSystemXmlApplicationContext,用相對路徑很方便的就能找到對應的配置檔案。對於這個路徑,spring提供了幾種路徑字首,來適應不同型別資源的載入。檢視列表請移步:http://blog.csdn.net/gklifg/article/details/15336951

對於Spring的呼叫還有更底層的呼叫方法,即建立BeanFactory物件,奈何本人也是剛開始學習Spring對其方法不甚瞭解,而且大多數情況下ApplicationContext作為BeanFactory的高階形態可以滿足絕大部分程式設計需求。

package main;


import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;


import view.OutputView;


public class HelloSpring {
	public static void main(String []args){
		ApplicationContext ctx = new FileSystemXmlApplicationContext("/src/applicationContext.xml");
		OutputView view = (OutputView) ctx.getBean("view");
		System.out.println("view.outPut: "+view.outPut());
		System.out.println("view.viewText: "+view.getViewText());
		view.setViewText("hehehe");
		view.getDoSth().setText("hehehe");
		OutputView view2 = (OutputView)ctx.getBean("view");
		System.out.println("view2.outPut: "+view2.outPut());
		System.out.println("view2.viewText: "+view2.getViewText());
	}
}
在FileSystemXmlApplicationContext的構造方法中新增xml配置的url

向ApplicationContext索取OutPutView,底層的物件裝配都有Spring自動完成了,拿來就可以用,

得到view後先輸出其中doSth物件中的資訊,又輸出view自身的資訊

修改view自身資訊

修改doSth資訊

重新獲取一個新的view物件view2,後先輸出其中doSth物件中的資訊,又輸出view2自身的資訊

結果如下:

view.outPut: hehe
view.viewText: haha
view2.outPut: hehehe
view2.viewText: haha

由於對doSth的裝配配置覆蓋了其構造方法,doSth中text變成了hehe,view中的text仍是初始的haha,對view中的doSth更改為hehehe後,在view2中doSth也變為hehehe,這說明兩個view中的doSth指向的是同一個例項,而view2自身的text值仍是初始化時的haha,說明view2是獨立於view的新例項。

下面加入工廠後處理器和bean前、bean後處理器來觀察spring建立物件的過程:

package bo;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component("beanPostPrcessorImpl")
public class BeanPostProcessorImpl implements BeanPostProcessor,BeanFactoryPostProcessor {

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
		// TODO Auto-generated method stub
		System.out.println(beanName+" bean後方法");
		return bean;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
		// TODO Auto-generated method stub
		System.out.println(beanName+" bean前方法");
		return bean;
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory factory)
			throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("------工廠後處理器載入的類列表:------");
		for(String s:factory.getBeanDefinitionNames()){
			System.out.println(s);
		}
		System.out.println("----------------------:------");
	}


}

處理器只需實現兩個介面,並加上component註解就可以被Spring識別了,可插拔,非常方便。

再次執行程式結果:

------工廠後處理器載入的類列表:------
beanPostPrcessorImpl
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
view
doSth
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
----------------------:------

2013-11-11 13:22:35 org.springframework.be....//日誌資訊...

doSth bean前方法
doSth bean後方法
view bean前方法
view bean後方法
view.outPut: hehe
view.viewText: haha
view bean前方法
view bean後方法
view2.outPut: hehehe
view2.viewText: haha

可以清晰到看到view、doSth先後被載入,在記憶體中開闢出空間以便注入屬性資訊;而doSth首先完成裝配,接下來才是view。且view在兩次getBean中裝配了兩遍,但doSth由於是單例模式,只有一次裝配過程。