spring學習筆記——spring Hello world 普通java專案版 分析類的載入與裝配
上一篇展示了spring的web版hello world,本篇來一個普通java專案中運用spring的demo,裡面有對singleton與prototype的討論,可以很清晰的看到spring對實體的注入策略。
因為是個demo,後來看工廠後處理器以及bean前、bean後處理器的時候加入了一個簡單地BeanPostProcessorImpl實現類,在此一起展現。
專案結構:
建專案、導包、建立好目錄結構後,我們來寫bo.DoSth類,很簡單的輸出字串。
注意此處在初始化的時候把字串初始化為了“haha"
下面看上一層的view.OutputView,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; } }
這個類有一個自己的私有欄位。viewText我們也把它初始化為“haha”。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; } }
下面來寫配置檔案:
<?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由於是單例模式,只有一次裝配過程。