轉:Spring裝配bean
在Spring中,對象間的協作是通過IoC機制完成的。
反向控制也叫依賴注入(Dependency Injection,DI),簡單來說就是將JavaBean需要的
對象通過配置文件加載進來。
Spring提供了兩種裝配Bean的容器,一是BeanFactoy,另一個是ApplicationContext。
兩者做爲容器,所有的Bean都應該通過容器裝配,而容器也知道自己都裝配了哪些Bean。
Bean裝配實際上就是讓容器知道程序中都有哪些Bean,可以通過以下兩種方式實現:
配置文件(最爲常用,體現了依賴注入DI的思想)
編程方式(寫的過程中向BeanFactory去註冊)
ApplicationContext與BeanFactory都是接口,ApplicationContext是由BeanFactory
接口擴展而來,它增強了BeanFactory的功能。
Bean容器能夠加載的對象並不一定是嚴格遵循JavaBeans規範的Java類,任何可實例化的類都
可以通過Spring Bean容器加載進來。通常稱這些類爲POJO。
要記住,BeanFactory不僅僅只具備實例化Bean的功能,它還知道所有的Bean,可以配置和管理它們。
Spring給出一些BeanFactory的實現類,其中最爲常用的是XmlBeanFactory。
1、通過文件系統
Resource res = new FileSystemResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
2、通過類路徑
ClassPathResource res = new ClassPathResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
3、通過ApplicationContext加載
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
BeanFactory factory = (BeanFactory) appContext;
sping-frameword-1.2.7-with-dependencies中的dist裏面是spring的包
將其中的spring.jar加入工程的類路徑裏面,下一步是寫個javaBean
package bean ;
public class HelloBean
{
public HelloBean
{
System.out.println("init!");
}
private String msg ;
//加上getter和setter方法
};
public class Demo
{
public static void main(String[] args)
{
Resource res = new ClassPathResource("bean.xml") ;
//配置文件放在類路徑的根路徑下
BeanFactory factory = new XmlBeanFactory(res) ;
//在dist文件夾裏面有spring-beans的dtd文檔
HelloBean bean = (HelloBean)factory.getBean("hello") ;
//根據xml配置文件中的id號去找bean,然後從這個工廠中取出bean
System.out.println(bean.getMsg());
HelloBean bean1 = (HelloBean)factory.getBean("hello") ;
System.out.println(bean==bean1); //因爲配置文件中的singleton設置爲true,
//故是單例模式,所以兩個bean肯定一樣,所以打印true
//只有ApplicationContext才能實現bean的非延遲加載功能,所以要想讓bean中的
//"init!"字符串在"before getbean!"字符串之前顯示的話,那麼首先必須得是單例模式,
//然後還得設置lazy-init="false",纔可以做到,如果singleton="false"的話,是無法
//做到非延遲加載的!可以通過下面的代碼來驗證,看"before getbean!"和"init!"這兩個
//字符串出現的先後順序就一目瞭然了。
ApplicationContext factory = new ClassPathXmlApplicationContext("bean.xml");
System.out.println("before getbean!");
HelloBean bean2 = (HelloBean)factory.getBean("hello");
}
}
配置文件bean.xml:
將<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
拷貝進去……
<beans>
//singleton屬性表明容器的bean是否使用單例模式……
//默認情況下,beanFactory就是延遲加載的
<bean id="hello" class="bean.HelloBean" singleton="true"
lazy-init="false">
<property name="msg">
<value>Hello,Spring!</value>
</property>
</bean>
</beans>
//上面的配置文件將屬性的值注入到bean的屬性中,這就是依賴注入的一個例子
//同時將那個javaBean註冊到容器中
通常可以通過三種方式裝配Bean
通過setter方法
通過構造函數
自動裝配
其中,使用setter方法裝配Bean是最爲常用的。
如下代碼的執行結果是什麼?
FirstBean bean = (FirstBean)factory.getBean("my");
FirstBean bean1 = (FirstBean)factory.getBean("my");
System.out.println(bean==bean1);
結果依賴於bean元素的singleton屬性,如果設置true,則以單例模式加載bean,
則永遠指向同一個bean;反之則每次實例化一個。
也即在單例模式下,BeanFactory維護所有的bean
如果想讓一個單例模式的bean被清理掉的話,不能簡單的將bean置爲null,而是必須使用
destroySingletons方法
還有一個destroyBean(String beanName,Object bean)
這兩個方法都可以來垃圾回收單例模式中的bean
--------------------------------------------------------------
延遲加載:
如下代碼執行的結果是什麼?
System.out.println("before loading");
FirstBean bean = (FirstBean)factory.getBean("my");
System.out.println(“after loading”);
在bean的構造函數中,包含:
System.out.println(“bean init”);
結果依賴於bean的lazy-init屬性,如果設置爲true,則在第一次加載該bean時初始化;
否則在初始化容器時就加載所有bean。
延遲加載僅在bean單例模式下起作用。
-------------------------------------------------------------------------
初始化和清理:
Spring的初始化肯定是在依賴注入(屬性設置)全部完成後纔去做的。
框架提供的初始化方法肯定是先於我們自己定義的初始化方法的!比如,如果繼承了
InitializingBean的話,會有一個這個接口提供的初始化方法,叫做afterPropertySet,
它的執行就是先於你定義的初始化方法的……
同理,DisposableBean接口中也定義了一個清理的方法,這個方法肯定也是先於你定義的
清理方法的!
建議使用你自己定義的初始化和清理方法,不要使用容器提供的,這樣可以避免bean被污染!!!
在許多情況下,需要在對象加載後立即初始化資源,而在刪除對象前先清理資源
在spring中,提供了兩種方式實現初始化和清理工作。
通過設置bean的init-method和destroy-method指定初始與清理方法
通過實現InitializingBean及DisposableBean接口,由容器在加載與刪除bean時自動調用。
//既然定義了一個init方法,所以可以在javaBean中設置下面的初始化方法:
public void init()
{
}
//同樣銷燬方法也可以類似的定義:
public void destroy()
{
}
//特別注意,如果你想運行上面自定義的destroy方法的話,你必須首先執行
factory.destroySingletons();
//否則不會去執行你上面自定義的destroy方法的!
原型bean在創建之後就脫離了factory的管理,所以呢,對於原型bean,只能初始化,而
不可以清理
<bean id="first" class="mybeans.FirstBean" init-method="init"
destroy-method="destroy" >
<property name="message">
<value>Hi, Rod Johnson</value>
</property>
</bean>
可以通過destroySingletons方法刪除所有單例bean
原型bean在創建後即脫離BeanFactory的維護,所以只能調用初始化方法,而不能做清理工作。
===========================================================================
下午課程開始:
public class HelloBean implements BeanNameAware, BeanFactoryAware
{
private BeanFactory factory ;
private String name ;
public void setBeanName(String a)//由BeanNameAware繼承來
{
this.name = a ;
}
//由BeanFactoryAware繼承而來。
public void setBeanFactory(BeanFactory factory)
throws BeanException
{
this.factory = factory
}
}
-------------------------------------------------------
下面說說編程式加載Bean方式:
XmlBeanFactory提供兩種編程方式加載Bean:
registerSingleton和registerBeanDefinition,前者不參與bean生命週期
後者參與bean的生命週期。
public static void main(String[] args)
{
Resource res = new ClassPathResource("bean.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
factory.registerSingleton("bb",new HelloBean());
HelloBean bean = (HelloBean)factory.getBean("bb");
System.out.println(bean.getMsg());
factory.destroySingletons();
}
如果使用BeanDefinition的話
public static void main(String[] args)
{
Resource res = new ClassPathResource("bean.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
RootBeanDefinition rbd = new RootBeanDefinition();
rbd.setBeanClass(HelloBean.class);
rbd.setInitMethodName("init");
//上面這句話告訴Spring自定義的方法名字叫做init,如果不寫的話,自定義的
//初始化方法不會執行的。
/*
RootBeanDefinition rbd1 = new RootBeanDefinition(Integer.class);
ContructorArgumentValues cav = new ConstructorArgumentValues();
cav.addGenericArgumentValue("12");
rbd1.setConstructorArgumentValues(cav);
factory.registerBeanDefinition("aa",rbd1);
System.out.println(factory.getBean("aa"));
*/
factory.registerBeanDefinition("aa",rbd);
HelloBean bean = (HelloBean)factory.getBean("aa");
System.out.println(bean.getMsg());
factory.destroySingletons();
}
老師的關鍵代碼如下:
XmlBeanFactory factory = new XmlBeanFactory(res);
RootBeanDefinition rbd = new RootBeanDefinition();
rbd.setBeanClass(HelloBean.class);
rbd.setInitMethodName("init");
RootBeanDefinition rbdi = new RootBeanDefinition(Integer.class);
ConstructorArgumentValues cav = new ConstructorArgumentValues();
cav.addGenericArgumentValue("12");
rbdi.setConstructorArgumentValues(cav);
=====================================================================
bean裏面的屬性是各式各樣的,我們上面使用的實體類只是使用了String類型,根本沒有考慮
其他的類型
bean裝配方式:
通過Setter方法、通過構造函數、自動裝配三種方法都可以達到裝配Bean的目的。
其中使用setter方法裝配Bean是最爲常用的。
先說一下setter方法的裝配:
setter方法可以裝配基本類型、Bean類型、內部bean類型、集合類型、設置空值
所謂Bean類型屬性是指這個屬性類型是個javaBean,並且這個javaBean必須已經在Spring
中註冊過了!
對於基本數據類型,
可以包括八種基本類型以及其包裝類
<property name="" value="" />就可以了,不用在意具體類型,Spring會自動轉換的。
裝配基本類型:
包括八種基本類型及它們的包裝類,還有String類型。
不必關心具體類型,spring可以通過反射機制瞭解到屬性的類型信息
可以通過<property>的子元素<value>來設置基本類型的值,也可以通過其屬性value來設置,
效果完全相同。
<bean id="first" class="mybeans.FirstBean" >
<property name="message">
<value>Hi, Rod Johnson</value>
</property>
<property name="age" value="1" />
//注意不能同時使用value子元素和value屬性
</bean>
--------------------------------------------------------------------------
裝配bean類型屬性:
只有通過配置文件向容器註冊的bean才能通過注入機制設置到其它bean的屬性上。
使用<ref>子元素或ref屬性設置
Spring即是通過這種方式建立起bean間的依賴關係,實現強大的bean管理功能。
舉例說明:
BasicDataSource
引入包commons-dbcp、commons-pool以及commons-collections三個包引入
還有mysql的驅動程序
將BasicDataSource中的setter方法注入Spring中去。
在bean.xml中:
//將BasicDataSource中的setter方法中的對應值設置進去!
<beans>
<bean id="data" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///j2ee"/>
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="course" class="bean.CourseBean">
<property name="dataSource" ref="data"/>
//由於是bean,所以使用ref!
</bean>
</beans>
建立一個Bean,對應數據庫中的一個表
public class CourseBean
{
private int id ;
private String name ;
private DataSource dataSource ;
//加入getter和setter方法
public void save()
{
}
}
然後就可以進行一下數據庫的操作了……
在main函數中執行下面的代碼:
---------------------------------------------------------------
Resource res = new ClassPathResource("bean.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
CourseBean course = (CourseBean)factory.getBean("course");
//由於數據源和courseBean之間的依賴關係已經通過配置文件給配置好了,所以這裏
//只需要得到courseBean,就自然有了數據源的bean了。
course.setName("adsf");
course.save();
-----------------------------------------------------------------
所謂DAO就是既有值,又可以將這個值存入數據庫的對象,也就是數據庫訪問對象
Data Access Object
所謂VO就是僅僅有值,也就是value object,值對象。
上面的這個course就是DAO了。
上面的save方法可以簡單的寫成下面的樣子:
public void save()
{
try
{
Connection con = this.dataSource.getConnection();
String sql = "insert into courses (coursename,period)"+
"values(rtrim(?),rtrim(?))" ;
PreparedStatement pstmt = con.prepareStatement(sql) ;
pstmt.setString(1,this.coursename);
pstmt.setInt(2,this.period.intValue());
pstmt.executeUpdate();
}
catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
======================================================================
如果一個bean在使用前,其某個屬性的值必須已經通過注入機制注入,spring可以協助檢查這個屬性
是否被初始化。
bean的屬性dependency-check即用來實現這樣的功能,其可選值包括
none --不檢查
objects --僅檢查bean類型
simple --僅檢查基本類型(8種)和String類型
all --全檢查
default --默認,不檢查
此外,因爲可能會調用其它對象的方法,有時一個對象在使用前必須要求另外一個對象已經初始化完成
這種依賴關係可以通過depends-on屬性來實現,spring會保證在初始化當前對象前將depends-on
指定的對象也初始化出來。
如果依賴多個對象,使用逗號將它們的名字分開。
內部Bean
<bean id="outer" class="...">
<property name="target">
<bean class="com.mycompany.PersonImpl">
<property name="name">
<value>Tony</value>
</property>
</bean>
</property>
</bean>
----------------------------------------------------
Spring支持以下四種集合的裝配:
<list>--java.util.List
<set>--java.util.Set
<map>--java.util.Map
<props>--java.util.Properties
list:
<property name="someList">
<list>
<value>someValue</value>
<ref bean="myDataSource"/>
<list>
<value>anyValue</value>
</list>
</list>
</property>
set:
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource"/>
</set>
</property>
map:
<property name="someMap">
<map>
<entry>
<key><value>yup an entry</value></key>
<value>just some string</value>
</entry>
<entry>
<key><value>yup a ref</value></key>
<ref bean="myDataSource"/>
</entry>
</map>
</property>
props:
<property name="people">
<props>
<prop key="HarryPotter">
The magic property
</prop>
<prop key="JerrySeinfeld">
The funny property
</prop>
</props>
</property>
==========================================================
==========================================================
如果屬性沒有setter方法的話,需要考慮使用構造方法裝配pbean的屬性,這就是
構造裝配
一般在以下情況使用:
屬性沒有setter方法,是隻讀屬性
屬性只需要設置一次,以後就不會再更改
一般使用構造裝配只裝配少量屬性
注意在構造裝配下,構造函數中應該包含有需要裝配的屬性
比如:
<bean id="i" class="java.lang.Integer">
<constructor-arg value="23" />
</bean>
這就是利用構造函數將Integer注入到容器中去。
Integer i = (Integer)factory.getBean("i");
System.out.println(i);
-----------------------------------------------------
<bean id="first" class="mybeans.FirstBean">
<constructor-arg>
<value>http://www.sohu.com</value>
</constructor-arg>
<constructor-arg>
<value>http://localhost:8080</value>
</constructor-arg>
<property name="age" value="1" />
</bean>
多個參數時使用多個constructor-arg指定,出現次序決定了參數次序,或者使用index屬性指定
======================================================
自動裝配:
可以通過spring框架自動爲bean裝配屬性。
自動裝配只能裝配bean類型,即取代ref元素。
使用自動裝配只需在bean元素中加入屬性autowire,自動裝配可被手動裝配覆蓋。
也可以選擇在beans中加入default-autowire屬性,爲所有bean設置默認自動裝配。
“no“-不使用自動裝配,spring推薦。
“byName”-依據名稱或ID裝配bean,如果沒有找到,則不裝配,可依賴dependency-check
屬性檢查是否裝配。
“byType”-依據類型自動裝配,如果存在兩個以上同種類型,則拋出異常。
“constructor”-依據當前bean構造函數裝配,查找與構造函數參數同類型bean
“autodetect”-自動檢測,先通過constructor,再使用byType
Spring是不推薦使用自動裝配的,首先是系統開銷的問題,還有就是同名的設置可能會導致
意外的問題……
====================================================================
通過BeanFactory獲取Bean與直接new一個Bean是完全不同的。
不相同的地方在於:從factory中得到的bean是被注入依賴關係的bean,而new出來的bean
則沒有依賴關係,屬性是空的。
通過BeanFactory獲取的bean能將所有依賴注入到bean中,屬性的值會依設置而定。
New出來的bean屬性值必須主動設置。
在需要使用spring框架情況下,所有bean都應該由容器來管理。
===================================================================
單例和原型的問題:依賴於singleton參數,true爲單例模式。
延遲加載:體現在整個容器初始化的時候立刻加載bean還是等到使用這個bean的時候才加載。
factory.getBean的時候就已經是開始使用bean了,並不一定要訪問其中的屬性
纔算是使用。
只有ApplicationContext才能做到容器初始化的時候立刻加載bean,BeanFactory
是做不到的。
註冊bean的時候,name屬性是用的別名,id屬性標明真名。name一般是在web開發裏面去用,name
裏面是可以包含一些特殊符號的,用於告訴開發者當前的屬性代表什麼具體的實際意思。
setter方法、構造函數和自動裝配三種裝配bean的方式
=====================================================================
ApplicationContext:
ApplicationContext與BeanFactory的作用相類似,都起到裝配、管理Bean的作用。
不同的是,ApplicationContext在此基礎上增強了BeanFactory的功能,這包括國際化、
加載資源、發佈事件等等。
國際化的支持:
Spring提供了兩個實現了MessageSource接口的類,它們都在
org.springframework.context.support包中:
ResourceBundleMessageSource使用JFC中標準的java.util.ResourceBundle來操作資源
ReloadableResourceBundleMessageSource 可以在不重啓虛擬機的情況下重新加載資源。
ResourceBundleMessageSource是具體的類而且有setter方法,所以可以注入
根據setBasename,
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="bean.res" />
</bean>
千萬注意一點,只要是資源包的話,id必須起名字爲“messageSource”!!!!
這裏還需要在bean包下面建立一個資源包res.properties,
在裏面寫上:
msg=Hello,{0}
public static void main(String[] args)
{
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
String s = context.getMessage("msg",new Object[]{"Spring-Hibernate"},new Locale("zh"));
System.out.println(s);
}
這就打印出了“Hello,Spring-Hibernate”
--------------------------------------------------------
假如有多個資源包呢?
比如我又在bean包裏面建了一個ress.properties
m=M
那麼
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>bean.res</value>
<value>bean.ress</value>
</list>
</property>
</bean>
--------------------------------------------------------
可以通過IOC機制加載資源,如
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<value>springResource</value>
</property>
</bean>
或者
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>format</value>
<value>exceptions</value>
<value>windows</value>
</list>
</property>
</bean>
千萬注意一點,只要是資源包的話,id必須起名字爲“messageSource”!!!!
反向控制也叫依賴注入(Dependency Injection,DI),簡單來說就是將JavaBean需要的
對象通過配置文件加載進來。
Spring提供了兩種裝配Bean的容器,一是BeanFactoy,另一個是ApplicationContext。
兩者做爲容器,所有的Bean都應該通過容器裝配,而容器也知道自己都裝配了哪些Bean。
Bean裝配實際上就是讓容器知道程序中都有哪些Bean,可以通過以下兩種方式實現:
配置文件(最爲常用,體現了依賴注入DI的思想)
編程方式(寫的過程中向BeanFactory去註冊)
ApplicationContext與BeanFactory都是接口,ApplicationContext是由BeanFactory
接口擴展而來,它增強了BeanFactory的功能。
Bean容器能夠加載的對象並不一定是嚴格遵循JavaBeans規範的Java類,任何可實例化的類都
可以通過Spring Bean容器加載進來。通常稱這些類爲POJO。
要記住,BeanFactory不僅僅只具備實例化Bean的功能,它還知道所有的Bean,可以配置和管理它們。
Spring給出一些BeanFactory的實現類,其中最爲常用的是XmlBeanFactory。
1、通過文件系統
Resource res = new FileSystemResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
2、通過類路徑
ClassPathResource res = new ClassPathResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
3、通過ApplicationContext加載
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
BeanFactory factory = (BeanFactory) appContext;
sping-frameword-1.2.7-with-dependencies中的dist裏面是spring的包
將其中的spring.jar加入工程的類路徑裏面,下一步是寫個javaBean
package bean ;
public class HelloBean
{
public HelloBean
{
System.out.println("init!");
}
private String msg ;
//加上getter和setter方法
};
public class Demo
{
public static void main(String[] args)
{
Resource res = new ClassPathResource("bean.xml") ;
//配置文件放在類路徑的根路徑下
BeanFactory factory = new XmlBeanFactory(res) ;
//在dist文件夾裏面有spring-beans的dtd文檔
HelloBean bean = (HelloBean)factory.getBean("hello") ;
//根據xml配置文件中的id號去找bean,然後從這個工廠中取出bean
System.out.println(bean.getMsg());
HelloBean bean1 = (HelloBean)factory.getBean("hello") ;
System.out.println(bean==bean1); //因爲配置文件中的singleton設置爲true,
//故是單例模式,所以兩個bean肯定一樣,所以打印true
//只有ApplicationContext才能實現bean的非延遲加載功能,所以要想讓bean中的
//"init!"字符串在"before getbean!"字符串之前顯示的話,那麼首先必須得是單例模式,
//然後還得設置lazy-init="false",纔可以做到,如果singleton="false"的話,是無法
//做到非延遲加載的!可以通過下面的代碼來驗證,看"before getbean!"和"init!"這兩個
//字符串出現的先後順序就一目瞭然了。
ApplicationContext factory = new ClassPathXmlApplicationContext("bean.xml");
System.out.println("before getbean!");
HelloBean bean2 = (HelloBean)factory.getBean("hello");
}
}
配置文件bean.xml:
將<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
拷貝進去……
<beans>
//singleton屬性表明容器的bean是否使用單例模式……
//默認情況下,beanFactory就是延遲加載的
<bean id="hello" class="bean.HelloBean" singleton="true"
lazy-init="false">
<property name="msg">
<value>Hello,Spring!</value>
</property>
</bean>
</beans>
//上面的配置文件將屬性的值注入到bean的屬性中,這就是依賴注入的一個例子
//同時將那個javaBean註冊到容器中
通常可以通過三種方式裝配Bean
通過setter方法
通過構造函數
自動裝配
其中,使用setter方法裝配Bean是最爲常用的。
如下代碼的執行結果是什麼?
FirstBean bean = (FirstBean)factory.getBean("my");
FirstBean bean1 = (FirstBean)factory.getBean("my");
System.out.println(bean==bean1);
結果依賴於bean元素的singleton屬性,如果設置true,則以單例模式加載bean,
則永遠指向同一個bean;反之則每次實例化一個。
也即在單例模式下,BeanFactory維護所有的bean
如果想讓一個單例模式的bean被清理掉的話,不能簡單的將bean置爲null,而是必須使用
destroySingletons方法
還有一個destroyBean(String beanName,Object bean)
這兩個方法都可以來垃圾回收單例模式中的bean
--------------------------------------------------------------
延遲加載:
如下代碼執行的結果是什麼?
System.out.println("before loading");
FirstBean bean = (FirstBean)factory.getBean("my");
System.out.println(“after loading”);
在bean的構造函數中,包含:
System.out.println(“bean init”);
結果依賴於bean的lazy-init屬性,如果設置爲true,則在第一次加載該bean時初始化;
否則在初始化容器時就加載所有bean。
延遲加載僅在bean單例模式下起作用。
-------------------------------------------------------------------------
初始化和清理:
Spring的初始化肯定是在依賴注入(屬性設置)全部完成後纔去做的。
框架提供的初始化方法肯定是先於我們自己定義的初始化方法的!比如,如果繼承了
InitializingBean的話,會有一個這個接口提供的初始化方法,叫做afterPropertySet,
它的執行就是先於你定義的初始化方法的……
同理,DisposableBean接口中也定義了一個清理的方法,這個方法肯定也是先於你定義的
清理方法的!
建議使用你自己定義的初始化和清理方法,不要使用容器提供的,這樣可以避免bean被污染!!!
在許多情況下,需要在對象加載後立即初始化資源,而在刪除對象前先清理資源
在spring中,提供了兩種方式實現初始化和清理工作。
通過設置bean的init-method和destroy-method指定初始與清理方法
通過實現InitializingBean及DisposableBean接口,由容器在加載與刪除bean時自動調用。
//既然定義了一個init方法,所以可以在javaBean中設置下面的初始化方法:
public void init()
{
}
//同樣銷燬方法也可以類似的定義:
public void destroy()
{
}
//特別注意,如果你想運行上面自定義的destroy方法的話,你必須首先執行
factory.destroySingletons();
//否則不會去執行你上面自定義的destroy方法的!
原型bean在創建之後就脫離了factory的管理,所以呢,對於原型bean,只能初始化,而
不可以清理
<bean id="first" class="mybeans.FirstBean" init-method="init"
destroy-method="destroy" >
<property name="message">
<value>Hi, Rod Johnson</value>
</property>
</bean>
可以通過destroySingletons方法刪除所有單例bean
原型bean在創建後即脫離BeanFactory的維護,所以只能調用初始化方法,而不能做清理工作。
===========================================================================
下午課程開始:
public class HelloBean implements BeanNameAware, BeanFactoryAware
{
private BeanFactory factory ;
private String name ;
public void setBeanName(String a)//由BeanNameAware繼承來
{
this.name = a ;
}
//由BeanFactoryAware繼承而來。
public void setBeanFactory(BeanFactory factory)
throws BeanException
{
this.factory = factory
}
}
-------------------------------------------------------
下面說說編程式加載Bean方式:
XmlBeanFactory提供兩種編程方式加載Bean:
registerSingleton和registerBeanDefinition,前者不參與bean生命週期
後者參與bean的生命週期。
public static void main(String[] args)
{
Resource res = new ClassPathResource("bean.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
factory.registerSingleton("bb",new HelloBean());
HelloBean bean = (HelloBean)factory.getBean("bb");
System.out.println(bean.getMsg());
factory.destroySingletons();
}
如果使用BeanDefinition的話
public static void main(String[] args)
{
Resource res = new ClassPathResource("bean.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
RootBeanDefinition rbd = new RootBeanDefinition();
rbd.setBeanClass(HelloBean.class);
rbd.setInitMethodName("init");
//上面這句話告訴Spring自定義的方法名字叫做init,如果不寫的話,自定義的
//初始化方法不會執行的。
/*
RootBeanDefinition rbd1 = new RootBeanDefinition(Integer.class);
ContructorArgumentValues cav = new ConstructorArgumentValues();
cav.addGenericArgumentValue("12");
rbd1.setConstructorArgumentValues(cav);
factory.registerBeanDefinition("aa",rbd1);
System.out.println(factory.getBean("aa"));
*/
factory.registerBeanDefinition("aa",rbd);
HelloBean bean = (HelloBean)factory.getBean("aa");
System.out.println(bean.getMsg());
factory.destroySingletons();
}
老師的關鍵代碼如下:
XmlBeanFactory factory = new XmlBeanFactory(res);
RootBeanDefinition rbd = new RootBeanDefinition();
rbd.setBeanClass(HelloBean.class);
rbd.setInitMethodName("init");
RootBeanDefinition rbdi = new RootBeanDefinition(Integer.class);
ConstructorArgumentValues cav = new ConstructorArgumentValues();
cav.addGenericArgumentValue("12");
rbdi.setConstructorArgumentValues(cav);
=====================================================================
bean裏面的屬性是各式各樣的,我們上面使用的實體類只是使用了String類型,根本沒有考慮
其他的類型
bean裝配方式:
通過Setter方法、通過構造函數、自動裝配三種方法都可以達到裝配Bean的目的。
其中使用setter方法裝配Bean是最爲常用的。
先說一下setter方法的裝配:
setter方法可以裝配基本類型、Bean類型、內部bean類型、集合類型、設置空值
所謂Bean類型屬性是指這個屬性類型是個javaBean,並且這個javaBean必須已經在Spring
中註冊過了!
對於基本數據類型,
可以包括八種基本類型以及其包裝類
<property name="" value="" />就可以了,不用在意具體類型,Spring會自動轉換的。
裝配基本類型:
包括八種基本類型及它們的包裝類,還有String類型。
不必關心具體類型,spring可以通過反射機制瞭解到屬性的類型信息
可以通過<property>的子元素<value>來設置基本類型的值,也可以通過其屬性value來設置,
效果完全相同。
<bean id="first" class="mybeans.FirstBean" >
<property name="message">
<value>Hi, Rod Johnson</value>
</property>
<property name="age" value="1" />
//注意不能同時使用value子元素和value屬性
</bean>
--------------------------------------------------------------------------
裝配bean類型屬性:
只有通過配置文件向容器註冊的bean才能通過注入機制設置到其它bean的屬性上。
使用<ref>子元素或ref屬性設置
Spring即是通過這種方式建立起bean間的依賴關係,實現強大的bean管理功能。
舉例說明:
BasicDataSource
引入包commons-dbcp、commons-pool以及commons-collections三個包引入
還有mysql的驅動程序
將BasicDataSource中的setter方法注入Spring中去。
在bean.xml中:
//將BasicDataSource中的setter方法中的對應值設置進去!
<beans>
<bean id="data" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///j2ee"/>
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="course" class="bean.CourseBean">
<property name="dataSource" ref="data"/>
//由於是bean,所以使用ref!
</bean>
</beans>
建立一個Bean,對應數據庫中的一個表
public class CourseBean
{
private int id ;
private String name ;
private DataSource dataSource ;
//加入getter和setter方法
public void save()
{
}
}
然後就可以進行一下數據庫的操作了……
在main函數中執行下面的代碼:
---------------------------------------------------------------
Resource res = new ClassPathResource("bean.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
CourseBean course = (CourseBean)factory.getBean("course");
//由於數據源和courseBean之間的依賴關係已經通過配置文件給配置好了,所以這裏
//只需要得到courseBean,就自然有了數據源的bean了。
course.setName("adsf");
course.save();
-----------------------------------------------------------------
所謂DAO就是既有值,又可以將這個值存入數據庫的對象,也就是數據庫訪問對象
Data Access Object
所謂VO就是僅僅有值,也就是value object,值對象。
上面的這個course就是DAO了。
上面的save方法可以簡單的寫成下面的樣子:
public void save()
{
try
{
Connection con = this.dataSource.getConnection();
String sql = "insert into courses (coursename,period)"+
"values(rtrim(?),rtrim(?))" ;
PreparedStatement pstmt = con.prepareStatement(sql) ;
pstmt.setString(1,this.coursename);
pstmt.setInt(2,this.period.intValue());
pstmt.executeUpdate();
}
catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
======================================================================
如果一個bean在使用前,其某個屬性的值必須已經通過注入機制注入,spring可以協助檢查這個屬性
是否被初始化。
bean的屬性dependency-check即用來實現這樣的功能,其可選值包括
none --不檢查
objects --僅檢查bean類型
simple --僅檢查基本類型(8種)和String類型
all --全檢查
default --默認,不檢查
此外,因爲可能會調用其它對象的方法,有時一個對象在使用前必須要求另外一個對象已經初始化完成
這種依賴關係可以通過depends-on屬性來實現,spring會保證在初始化當前對象前將depends-on
指定的對象也初始化出來。
如果依賴多個對象,使用逗號將它們的名字分開。
內部Bean
<bean id="outer" class="...">
<property name="target">
<bean class="com.mycompany.PersonImpl">
<property name="name">
<value>Tony</value>
</property>
</bean>
</property>
</bean>
----------------------------------------------------
Spring支持以下四種集合的裝配:
<list>--java.util.List
<set>--java.util.Set
<map>--java.util.Map
<props>--java.util.Properties
list:
<property name="someList">
<list>
<value>someValue</value>
<ref bean="myDataSource"/>
<list>
<value>anyValue</value>
</list>
</list>
</property>
set:
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource"/>
</set>
</property>
map:
<property name="someMap">
<map>
<entry>
<key><value>yup an entry</value></key>
<value>just some string</value>
</entry>
<entry>
<key><value>yup a ref</value></key>
<ref bean="myDataSource"/>
</entry>
</map>
</property>
props:
<property name="people">
<props>
<prop key="HarryPotter">
The magic property
</prop>
<prop key="JerrySeinfeld">
The funny property
</prop>
</props>
</property>
==========================================================
==========================================================
如果屬性沒有setter方法的話,需要考慮使用構造方法裝配pbean的屬性,這就是
構造裝配
一般在以下情況使用:
屬性沒有setter方法,是隻讀屬性
屬性只需要設置一次,以後就不會再更改
一般使用構造裝配只裝配少量屬性
注意在構造裝配下,構造函數中應該包含有需要裝配的屬性
比如:
<bean id="i" class="java.lang.Integer">
<constructor-arg value="23" />
</bean>
這就是利用構造函數將Integer注入到容器中去。
Integer i = (Integer)factory.getBean("i");
System.out.println(i);
-----------------------------------------------------
<bean id="first" class="mybeans.FirstBean">
<constructor-arg>
<value>http://www.sohu.com</value>
</constructor-arg>
<constructor-arg>
<value>http://localhost:8080</value>
</constructor-arg>
<property name="age" value="1" />
</bean>
多個參數時使用多個constructor-arg指定,出現次序決定了參數次序,或者使用index屬性指定
======================================================
自動裝配:
可以通過spring框架自動爲bean裝配屬性。
自動裝配只能裝配bean類型,即取代ref元素。
使用自動裝配只需在bean元素中加入屬性autowire,自動裝配可被手動裝配覆蓋。
也可以選擇在beans中加入default-autowire屬性,爲所有bean設置默認自動裝配。
“no“-不使用自動裝配,spring推薦。
“byName”-依據名稱或ID裝配bean,如果沒有找到,則不裝配,可依賴dependency-check
屬性檢查是否裝配。
“byType”-依據類型自動裝配,如果存在兩個以上同種類型,則拋出異常。
“constructor”-依據當前bean構造函數裝配,查找與構造函數參數同類型bean
“autodetect”-自動檢測,先通過constructor,再使用byType
Spring是不推薦使用自動裝配的,首先是系統開銷的問題,還有就是同名的設置可能會導致
意外的問題……
====================================================================
通過BeanFactory獲取Bean與直接new一個Bean是完全不同的。
不相同的地方在於:從factory中得到的bean是被注入依賴關係的bean,而new出來的bean
則沒有依賴關係,屬性是空的。
通過BeanFactory獲取的bean能將所有依賴注入到bean中,屬性的值會依設置而定。
New出來的bean屬性值必須主動設置。
在需要使用spring框架情況下,所有bean都應該由容器來管理。
===================================================================
單例和原型的問題:依賴於singleton參數,true爲單例模式。
延遲加載:體現在整個容器初始化的時候立刻加載bean還是等到使用這個bean的時候才加載。
factory.getBean的時候就已經是開始使用bean了,並不一定要訪問其中的屬性
纔算是使用。
只有ApplicationContext才能做到容器初始化的時候立刻加載bean,BeanFactory
是做不到的。
註冊bean的時候,name屬性是用的別名,id屬性標明真名。name一般是在web開發裏面去用,name
裏面是可以包含一些特殊符號的,用於告訴開發者當前的屬性代表什麼具體的實際意思。
setter方法、構造函數和自動裝配三種裝配bean的方式
=====================================================================
ApplicationContext:
ApplicationContext與BeanFactory的作用相類似,都起到裝配、管理Bean的作用。
不同的是,ApplicationContext在此基礎上增強了BeanFactory的功能,這包括國際化、
加載資源、發佈事件等等。
國際化的支持:
Spring提供了兩個實現了MessageSource接口的類,它們都在
org.springframework.context.support包中:
ResourceBundleMessageSource使用JFC中標準的java.util.ResourceBundle來操作資源
ReloadableResourceBundleMessageSource 可以在不重啓虛擬機的情況下重新加載資源。
ResourceBundleMessageSource是具體的類而且有setter方法,所以可以注入
根據setBasename,
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="bean.res" />
</bean>
千萬注意一點,只要是資源包的話,id必須起名字爲“messageSource”!!!!
這裏還需要在bean包下面建立一個資源包res.properties,
在裏面寫上:
msg=Hello,{0}
public static void main(String[] args)
{
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
String s = context.getMessage("msg",new Object[]{"Spring-Hibernate"},new Locale("zh"));
System.out.println(s);
}
這就打印出了“Hello,Spring-Hibernate”
--------------------------------------------------------
假如有多個資源包呢?
比如我又在bean包裏面建了一個ress.properties
m=M
那麼
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>bean.res</value>
<value>bean.ress</value>
</list>
</property>
</bean>
--------------------------------------------------------
可以通過IOC機制加載資源,如
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<value>springResource</value>
</property>
</bean>
或者
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>format</value>
<value>exceptions</value>
<value>windows</value>
</list>
</property>
</bean>
千萬注意一點,只要是資源包的話,id必須起名字爲“messageSource”!!!!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.