Spring是Web框架,是容器框架,用于配置bean,并維護(hù)bean之間的關(guān)系的框架。
1. Spring在整個(gè)項(xiàng)目層次中的位置:1、引入spring開發(fā)包(最小配置)如下:
2、創(chuàng)建spring的一個(gè)核心文件(如struts中的struts-config.xml)applicationContext.xml文件。該文件一般放在src目錄下,該文件需引入xsd文件:可以從下載下來(lái)的開發(fā)包中的例子中粘貼過(guò)來(lái)。
上面我們看了配置單個(gè)bean的做法,但是當(dāng)兩個(gè)bean之間是嵌套的(就像某人有一只狗),該怎么設(shè)置呢?
使用spring ,沒有new對(duì)象,我們把創(chuàng)建對(duì)象的任務(wù)交給spring框架
spring的運(yùn)行原理圖:
spring開發(fā)提倡接口編程,配合di技術(shù)可以層與層的解耦
現(xiàn)在我們體驗(yàn)一下spring的di配合接口編程
例:
建立一個(gè)用戶驗(yàn)證接口,使用兩種不同的驗(yàn)證方法。兩種不同的驗(yàn)證方法都繼承用戶驗(yàn)證接口:
可以從ApplicationContext 應(yīng)用上下文容器中獲取bean也可以從BeanFactory中獲取bean。那他們有什么區(qū)別呢?
當(dāng)從ApplicationContext 中取bean時(shí),是這樣的:
怎么驗(yàn)證呢?很簡(jiǎn)單,因?yàn)樗抢梅瓷錂C(jī)制來(lái)實(shí)現(xiàn)的,所以在實(shí)例化對(duì)象時(shí)會(huì)調(diào)用該bean的默認(rèn)構(gòu)造函數(shù):
在該bean中加入默認(rèn)構(gòu)造函數(shù):
執(zhí)行該語(yǔ)句時(shí):
假如我們有需求:用我們自己的構(gòu)造函數(shù)來(lái)實(shí)例化這個(gè)bean。該怎么辦呢?→在該bean的配置中添加<constructor-arg>標(biāo)簽(通過(guò)構(gòu)造函數(shù)來(lái)注入值)
注意:
當(dāng)從BeanFactory中獲取bean時(shí):
當(dāng)我們開始使用bean時(shí):
由此可見:
1.如果使用ApplicationContext ,并且配置的bean如果是 singlton(默認(rèn)),不管你用不用,都被實(shí)例化.(好處就是可以預(yù)先加載,缺點(diǎn)就是耗內(nèi)存)
2.如果是 BeanFactory ,則當(dāng)你獲取beanfacotry時(shí)候,配置的bean不會(huì)被馬上實(shí)例化,當(dāng)你使用的時(shí)候,才被實(shí)例(好處節(jié)約內(nèi)存,缺點(diǎn)就是速度)
3.規(guī)定: 一般沒有特殊要求,應(yīng)當(dāng)使用ApplicatioContext完成(90%)
5. ApplicationContext 對(duì)象有3種應(yīng)用方法1. ClassPathXmlApplicationContext -> 通過(guò)類路徑
2. FileSystemXmlApplicationContext -> 通過(guò)文件路徑
舉例:
ApplicationContext ac=new FileSystemXmlApplicationContext("文件路徑beans.xml / applicationContext.xml");
3. XmlWebApplicationContext
6. bean生命周期6.1 利用ApplicationContext獲取bean時(shí),bean的生命周期① 實(shí)例化(當(dāng)我們的程序加載beans.xml文件),把我們的bean(前提是scope=singleton)實(shí)例化到內(nèi)存
② 調(diào)用set方法設(shè)置屬性
③ 如果你實(shí)現(xiàn)了bean名字關(guān)注接口(BeanNameAware) 則,可以通過(guò)setBeanName獲取Bean的id屬性值
④ 如果你實(shí)現(xiàn)了bean工廠關(guān)注接口(BeanFactoryAware),則可以獲取BeanFactory
⑤ 如果你實(shí)現(xiàn)了 ApplicationContextAware接口,則調(diào)用方法
//該方法傳遞ApplicationContext
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
System.out.println("setApplicationContext"+arg0);
}
⑥ 如果bean 和 一個(gè)BeanPostProcessor(前置處理器)關(guān)聯(lián),則會(huì)自動(dòng)去調(diào)用 Object postProcessBeforeInitialization方法
⑦ 如果你實(shí)現(xiàn)InitializingBean 接口,則會(huì)調(diào)用 afterPropertiesSet
⑧ 如果自己在<bean init-method=”init”/> 則可以在bean定義自己的初始化方法.
}
配置:
⑨ 如果bean 和 一個(gè)BeanPostProcessor(后置處理器)關(guān)聯(lián),則會(huì)自動(dòng)去調(diào)用 Object postProcessAfterInitialization方法
⑩ 使用我們的bean
11. 容器關(guān)閉
12. 可以通過(guò)實(shí)現(xiàn)DisposableBean 接口來(lái)調(diào)用方法 destory
13. 可以在<bean destory-method=”fun1”/> 調(diào)用定制的銷毀方法
12和13的使用和7、8一樣。
記住他們的順序。
小結(jié): 我們實(shí)際開發(fā)中往往,沒有用的這么的過(guò)程,常見的是:
1->2->6->10->9->11
只經(jīng)歷了以下的接口:
BeanNameAware,BeanFactoryAware,InitializingBean和自己配置的init-method方法。
7. 配置bean的細(xì)節(jié)7.1 scope 的說(shuō)明singleton(默認(rèn)):在整個(gè)Spring Ioc容器中,使用 scope="singleton" 的bean將只有一個(gè)實(shí)例。
prototype:每次通過(guò)容器的getBean方法獲取scope="prototype"的bean時(shí),都將產(chǎn)生一個(gè)新的bean實(shí)例。
request:每次HTTP請(qǐng)求,使用 scope=" request" 的bean都將產(chǎn)生一個(gè)新的bean實(shí)例。
session:對(duì)于每個(gè)HttpSession,使用 scope=" session" 的bean都將產(chǎn)生一個(gè)新的bean實(shí)例。
global session:每個(gè)全局的HttpSession對(duì)應(yīng)一個(gè)Bean實(shí)例。
? 盡量使用 scope=”singleton” ,不要使用prototype,因?yàn)檫@樣對(duì)我們的性能影響較大.
對(duì)有狀態(tài)的bean應(yīng)該使用prototype作用域,而對(duì)無(wú)狀態(tài)的bean則應(yīng)該使用singleton作用域。
注意
Spring不能對(duì)一個(gè)prototype bean的整個(gè)生命周期負(fù)責(zé)。程序每次請(qǐng)求該bean,Spring都會(huì)創(chuàng)建一個(gè)新的Bean實(shí)例,然后交給程序,然后就對(duì)該Bean實(shí)例不聞不問(wèn)了。這就意味著,任何配置好的析構(gòu)生命周期回調(diào)方法都將不會(huì)被調(diào)用。清除prototype作用域的對(duì)象并釋放任何prototype bean所持有的昂貴資源,都是客戶端代碼的職責(zé)。(讓Spring容器釋放被prototype作用域bean占用資源的一種可行方式是,通過(guò)使用bean的后置處理器,該處理器持有要被清除的bean的引用。)
7.2 給集合類型注入值①給List注入值:
②給數(shù)組注入值
和List一樣。
③給set注入值
④向Map注入值
⑤向?qū)傩约献⑷?/strong>
子集合的值是從其父集合中繼承和覆蓋而來(lái)的。
集合合并只能在spring2.0以后使用并且不同集合是不能合并的。
7.4 強(qiáng)類型集合在Java5以后才能使用。
public class Foo { private Map<String, Float> accounts; public void setAccounts(Map<String, Float> accounts) { this.accounts = accounts; }}
<beans> <bean id="foo" class="x.y.Foo"> <property name="accounts"> <map> <entry key="one" value="9.99"/> <entry key="two" value="2.75"/> <entry key="six" value="3.99"/> </map> </property> </bean></beans>7.5 嵌套Bean
如果某個(gè)Bean依賴的Bean不想被Spring容器直接訪問(wèn),可以使用嵌套bean。
<bean id="date" class="date.Date_"> <property name="year"> <bean class="date.Year_"> <property name="data" value="2015"/> </bean> </property> <property name="month"> <bean class="date.Month_"> <property name="data" value="2"/> </bean> </property> <property name="day"> <bean class="date.Day_"> <property name="data" value="7"/> </bean> </property></bean>
這樣,內(nèi)部的Bean不能被Spring容器訪問(wèn),因此不用擔(dān)心其他程序 修改嵌套的Bean,提高了程序的內(nèi)聚性,但降低了程序的靈活性。因此只有確定某個(gè)Bean實(shí)例無(wú)需通過(guò)Spring容器來(lái)訪問(wèn)時(shí),才考慮使用嵌套Bean。
7.6 組合屬性注入public class Date_ { private Year_ year=new Year_(); public Year_ getYear() { return year; } public void setYear(Year_ year) { this.year = year; }}
<bean id="next" class="date.Date_"> <property name="year.data" value="2015"/></bean>
設(shè)置屬性abstract="true"的Bean是抽象Bean,容器不會(huì)創(chuàng)建抽象Bean的實(shí)例,也因此,抽象Bean可以沒有class屬性。
<beanid="dateTemplate "abstract="true">
<!-- 定義依賴注入的屬性 --> <propertyname="month"ref="month"/></bean>
當(dāng)我們有大量的Bean要配置到Spring的配置文件中,而這些Bean的大部分配置信息都完全一樣,只有少量的信息不一樣,這時(shí)使用Bean繼承是一個(gè)很好的辦法:
將大部分相同信息配置為Bean模板(抽象Bean)后,將實(shí)際的Bean實(shí)例配置成為該Bean模板的子Bean即可。
子Bean無(wú)法從父Bean繼承如下屬性:depends-on、autowire、scope、lazy-init,這些屬性總是從子Bean中獲得,或者采用默認(rèn)值。子Bean配置可以增加新的配置信息,當(dāng)子Bean指定的配置信息與父Bean模板信息不一致時(shí),子Bean所制定的配置信息將覆蓋父Bean指定的配置信息。
</bean>
如果父Bean配置中有class屬性,則子Bean在和父Bean類相同的情況下可以省略掉class屬性:
</bean>
注意,繼承自抽象Bean繼承只是為了配置參數(shù)的復(fù)用,并且子Bean的類型不必與抽象Bean的類型(配置了的話)一樣。
這種繼承與Java語(yǔ)言的繼承一樣。
7.9 容器中的工廠Bean實(shí)現(xiàn)了FactoryBean接口的Bean成為工廠Bean,并且該Bean只能做為工廠Bean來(lái)使用。
}
配置,和普通bean的配置完全一樣:
<beanid="briton"class="factoryBean.PersonFactory"/>
測(cè)試:
}
由此可見,工廠Bean已經(jīng)無(wú)法作為正常的Bean使用了,客戶端請(qǐng)求該工廠Bean的id時(shí),得到是工廠Bean的產(chǎn)品(上面是一個(gè)Person)而非工廠Bean的本身。
7.10 獲得Bean本身的Id在前面的程序中,程序總是通過(guò)Bean的id從BeanFactory中獲取Bean實(shí)例。但是現(xiàn)在的需求是,我已經(jīng)知道了Bean,需要知道配置該Bean時(shí)指定的id屬性。
BeanNameAware接口提供了setBeanName方法來(lái)獲取部署在Spring配置文件中的Bean。
}
配置Bean:
<beanid="chinese"class="beanNameAware.Chinese"/>
獲取Bean:
}
從程序中我們看到,和獲取、使用普通Bean沒有任何區(qū)別。從程序執(zhí)行來(lái)看,Spring在實(shí)例化該Bean的時(shí)候,也調(diào)用了該Bean的setBeanName方法。
7.11 depengs-on該屬性用于指定當(dāng)前bean初始化之前或銷毀之前需要強(qiáng)制初始化的bean。該屬性只對(duì)singleton bean有效。指定多個(gè)bean是,多個(gè)bean之間可以用逗號(hào),空格,分號(hào)來(lái)分開。
在spring中空值和<null/>是不一樣的。
①<property>、<constructor-arg>、<entry>都支持value屬性,盡量使用。
②ref也可以是屬性。
③使用p命名空間配置屬性
xmlns:p="http://www.springframework.org/schema/p"
可以通過(guò)元素<beans>的default-autowire屬性指定,也可以通過(guò)<bean>元素的autowire屬性
①byName
②byType
尋找和屬性的類型相同的bean,找不到,裝不上;找到多個(gè),出現(xiàn)異常。
③constructor
、
④autodetect
再如:
⑤no
不自動(dòng)裝配
11. 分散配置有兩種方法:
①
PropertyPlaceholderConfigurer是個(gè)bean工廠后置處理器的實(shí)現(xiàn),可以將BeanFactory定義中的一些屬性值放到另一個(gè)單獨(dú)的標(biāo)準(zhǔn)Java Properties文件中。這就允許用戶在部署應(yīng)用時(shí)只需要在屬性文件中對(duì)一些關(guān)鍵屬性(例如數(shù)據(jù)庫(kù)URL,用戶名和密碼)進(jìn)行修改,而不用對(duì)主XML定義文件或容器所用文件進(jìn)行復(fù)雜和危險(xiǎn)的修改。
考慮下面的XML配置元數(shù)據(jù)定義,它用占位符定義了DataSource。我們?cè)谕獠康腜roperties文件中配置一些相關(guān)的屬性。在運(yùn)行時(shí),我們?yōu)樵獢?shù)據(jù)提供一個(gè)PropertyPlaceholderConfigurer,它將會(huì)替換dataSource的屬性值。
1 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 2 <property name="locations"> 3 <value>classpath:com/foo/jdbc.properties</value> 4 </property> 5 </bean> 6 <bean id="dataSource" destroy-method="close" 7 class="org.apache.commons.dbcp.BasicDataSource"> 8 <property name="driverClassName" value="${jdbc.driverClassName}"/> 9 <property name="url" value="${jdbc.url}"/>10 <property name="username" value="${jdbc.username}"/>11 <property name="passWord" value="${jdbc.password}"/>12 </bean>View Code
實(shí)際的值來(lái)自于另一個(gè)標(biāo)準(zhǔn)Java Properties
格式的文件:
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root
②使用<context:property-placeholder
但是使用這個(gè)的時(shí)候必須將命名空間引進(jìn)來(lái),如下所示:
1 <beans xmlns="http://www.springframework.org/schema/beans"2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"3 xmlns:context="http://www.springframework.org/schema/context"4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd6 http://www.springframework.org/schema/context7 http://www.springframework.org/schema/context/spring-context-2.5.xsd">View Code
這樣我們的bean配置文件就會(huì)很簡(jiǎn)單
在Spring 2.5中,context名字空間可能采用單一元素屬性占位符的方式(多個(gè)路徑提供一個(gè)逗號(hào)分隔的列表)
<context:property-placeholder location="classpath:com/foo/jdbc.properties"/>
PropertyPlaceholderConfigurer如果在指定的Properties文件中找不到你想使用的屬性,它還會(huì)在Java的System類屬性中查找。這個(gè)行為可以通過(guò)設(shè)置systemPropertiesMode屬性來(lái)定制,它有三個(gè)值:讓配置一直覆蓋、讓它永不覆蓋及讓它僅僅在屬性文件中找不到該屬性時(shí)才覆蓋。請(qǐng)參考PropertiesPlaceholderConfigurer的JavaDoc以獲得更多的信息。
|
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注