Spring回顧一
Spring是一個開源的控制反轉(Inversion of Control, IoC)和麪向切面的(AOP, Aspect-Oriented Programming)的容器框架,它的主要目的是簡化企業的開發。
所謂控制反轉就是應用本身不負責依賴對象的創建及維護,依賴對象的創建及維護是由外部容器負責的,這樣控制權就由應用轉移到了外部容器,控制權的轉移就是所謂反轉。
所謂依賴注入(Dependency Injection)就是指:在運行時,由外部容器動態地將依賴對象注入到組件中。
Spring的好處:
減低組件之間的耦合度,實現軟件各層之間的解耦
可以使用Spring提供的衆多服務,如:事務管理器,消息服務等等。
容器提供單例模式的支持
容器提供了AOP技術
容器提供了衆多的輔助類,使用這些類能夠加快應用的開發
Spring對於主流的應用框架提供了集成的支持
對於spring容器,提供了很多的服務,但這些服務不是默認爲應用打開的。如果提高服務較少則認爲是輕量級的,否則則認爲是重量級的。
spring用到的核心jar文件有兩個:
dist/spring.jar
lib/jakarta-commons/commons-logging.jar
如果使用了切面編程(AOP),還需要下列的jar文件
lib/aspectj/aspectjweaver.jar和aspectjrt.jar
lib/cglig/cglib-nodep-2.1-3.jar
如果使用了JSP-250中的註解,
如@Resource/@PostConstruct/@PreDestory,還需要下列jar文件
lib/j2ee/common-annotations.jar.
實例化Spring容器常用的兩種方式:
方法一:
在類路徑下尋找配置文件來實例化容器
ApplicationContext ctx =
new ClassPathXmlApplicationContext(new String[]{“bean.xml”});
方法二:
在文件系統路徑下尋找配置文件實例化容器
ApplicationContext ctx =
new FileSystemXmlApplicationContext(new String[]{“d:/beans.xml”});
編寫spring配置文件時不出現幫助信息
由於spring的schema文件位於網絡上,如果機器不能連接到網絡上,那麼在編寫配置信息時候無法出現提示信息,解決辦法有兩種:
1. 讓機器上網,eclipse會自動從網絡上下載schema文件並緩存到本地硬盤上。
2. 手動添加schema文件,方法如下:
windows->preferences->myeclipse->files and editors ->xml->xmllocation 點”add”,在出現的窗口中的Key Type中選擇URL,在location中選擇”File System”,然後在spring解壓目錄的dist/resources目錄中選擇spring-beans-2.5.xsd,回到設置窗口的時候不要急着關閉窗口,應把窗口中的Key Type改爲Schema location,Key
改爲http://www.springframework.org/schema/beans/srping-beans
-2.5.xsd.
<bean有id屬性和name屬性,name屬性可以包含特殊字符例如:”/sd/
三種實例化bean的方式:
1. 使用類構造器實例化:
<bean id=”orderService” class=”cn.itcast.OrderServiceBean”>
2. 使用靜態工廠的方法實例化:
<bean id=”personService” class=”cn.itcast.service.OrderFactory” factory-method=”createOrder” />
3. 使用實例化工廠的方法實例化:
<bean id=”personServiceFactory” class=”cn.itcast.service.OrderFactory” />
<bean id=”personSercie” factory-bean=”personServiceFactory” factory-method=”createOrder”>
Bean的作用域:
.singleton在每個Spring IoC容器中一個bean定義只有一個對象實例,默認情況下會在容器啓動時初始化bean.但我們可以指定Bean節點的lazy-init=”true”來延遲初始化bean,這時候,只有第一次獲取bean會才初始化bean。如:
<bean id=”xxx” class=”cn.itcast.OrderServiceBean” lazy-init=”true” />
如果想對所有的bean都應用延遲初始化,可以在跟節點beans設置default-laza-init=”true”,如下: <beans default-lazy-init=”true”>
.prototype 每次從從其獲取bean都是新的對象。
以下僅用於Web Bean
.request
.session.
.global session
Spring管理Bean的聲明週期:
init-method: bean初始化實例時,調用初始化方法。
destroy-method: bean被銷燬時執行的方法。
AbstractApplicationContext.close()方法用於關閉Spring容器
Spring的依賴注入:
使用內部bean,但該bean不能被其他bean使用:
<bean id=”orderService” class=”cn.itcast.service.OrderServiceBean”>
<property name=”orderDao”>
<bean class=”cn.itcast.service.OrderDaoBean” />
</property>
</bean>
JavaBean是一種特殊的Java類,主要用於傳遞 數據信息,這種java類中的方法主要用於訪問私有的字段,且方法名符合某種命名規則。
如果要在兩個模塊之間傳遞多個信息,可以將這些信息封裝到一個JavaBean中,這種JavaBean的實例對象稱之爲值對象(Value Object,簡稱VO)。這些信息在類中用私有字段來存儲,如果讀取或設置這些字段的值,則需要通過一些相應的方法來訪問。JavaBean的屬性是根據啓動的setter和getter方法來確定的,而不是根據其中的成員變量。如果方法名爲setId,中文意思即爲設置id,至於你把它設置到那個變量上,則不用關心,如果方法名爲getId,則屬性名即爲id.
JDK中提供了對JavaBean進行操作的一些API。這套API就稱爲內省。
spring集合類型的封裝:
<property name="sets">
<set>
<value>value1</value>
<value>value2</value>
<value>vaule3</value>
<value>value4</value>
</set>
</property>
<property name="lists">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<property name="maps">
<map>
<entry key="key1" value="value1" />
<entry key="key2" value="value2" />
</map>
</property>
<property name="props">
<props>
<prop key="p1">v1</prop>
</props>
</property>
spring依賴注入的實現:
private static class MyApplicationContect {
public static Object getBean(String name) throws Exception {
Map<String, String> nsMap = new HashMap<String, String>();
// 加入命名空間
nsMap.put("ns", "http://www.springframework.org/schema/beans");
// 創建beans/bean的路徑
XPath xsub = document.createXPath("/ns:beans/ns:bean[@id='" + name + "']");
// 設置命名空間
xsub.setNamespaceURIs(nsMap);
Element ele = (Element)xsub.selectSingleNode(document);;
System.out.println(ele.attributeValue("class"));
Object retValue = Class.forName(ele.attributeValue("class")).newInstance();
for (Iterator<?> iter=ele.elementIterator("property"); iter.hasNext();) {
Element property = (Element)iter.next();
String propName = property.attributeValue("name");
if (property.attributeValue("value") != null) {
String strValue = property.attributeValue("value");
Class<?> paraType = retValue.getClass().getDeclaredField(propName).getType();
Object value = ConvertUtils.convert(strValue, paraType);
setProperty(retValue, propName, value);
//BeanUtils.setProperty(retValue, propName, strValue);
} else {
String ref = property.attributeValue("ref");
Object obj2 = getBean(ref);
setProperty(retValue, propName, obj2);
//BeanUtils.setProperty(retValue, propName, obj2);
}
}
return retValue;
}
private static void setProperty(Object object, String propertyName,
Object propertyValue) throws IntrospectionException,
IllegalAccessException, InvocationTargetException {
PropertyDescriptor propertyX = new PropertyDescriptor(propertyName, object.getClass());
Method methodSetX = propertyX.getWriteMethod();
methodSetX.setAccessible(true);
methodSetX.invoke(object, propertyValue);
}
}
依賴注入共有三種:
使用構造器注入
使用屬性setter方法注入
使用Field注入(用於註解注入)
注入依賴對象可以採用手工裝配或自動裝配,在實際應用中建議使用手工裝配,因爲自動裝配會產生未知情況,開發人員無法預見最終的裝配結果。
手工裝配依賴對象,在這種方式中又有兩種編程方式。
1. 在xml配置中,通過在bean節點下配置(通過構造器注入,通過setter方法注入)
2. 在java代碼中使用@Autowired或@Resource註解方式進行裝配。但我們需要在xml配置文件中配置下面的
<context:annotation-config />這個配置方式註冊了多個註釋進行解析處理的處理器
:AutowireAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor
注:@Resource註解在spring安裝目錄的lib/j2ee/common-annotations.jar
在java代碼中使用@Autowired或@Resource註解方式進行裝配,這兩個註解的區別是:@Autowired默認按類型裝配,@Resource默認按名稱裝配,當找不到與名稱匹配的bean時,纔會按類型裝配。
@Autowired
private PersonDao personDao; // 用於字段上
@Autowired
public void setOrderDao(OrderDao orderDao) { // 用於屬性的setter方法上
}
@Autowired註解是按類型裝配依賴對象,默認情況下它要求依賴對象必須存在,如果允許null值,可以設置它的required屬性爲false,如果我們想使用按名稱裝配,可以結合@Qualified註解一起使用。如下:
Autowired @Qualifer(“personDaoBean”);
private PersonDao personDao;
@Resrouce註解和@Autowired一樣,也可以標註在字段或屬性的setter方法,但它默認按名稱裝配,名稱可以通過@Resource的name屬性指定,如果沒有指定name屬性,當註解標註在字段上,即默認取字段的名稱作爲bean名稱尋找依賴對象,當註解標註在屬性的setter方法上,即默認取屬性名作爲bean名稱尋找依賴對象。
@Resource(name=”personDaoBean”)
private PersonDao personDao // 用於字段上
注意:如果沒有指定name屬性,並且按照默認的名稱仍然找不到依賴對象時,@Resource註解會回退到按類型裝配,但一旦指定了name屬性,就只能按名稱裝配了。
自動裝配的實現:<bean id=”” class=”” autowire=”byType”>
autowire屬性取值如下:
.byType: 按類型裝配,可以根據屬性的類型,在容器中尋找跟類型匹配的bean,如果發現多個,那麼就會拋出異常,如果沒有找到,即屬性值爲null
.byName 按名稱裝配,可以根據屬性的名稱,在容器中尋找跟屬性名相同的bean.如果沒有找到,即屬性值爲null.
.constructor與byType的方式類似,不同之處在於它應用於構造器參數,如果在容器中沒有找到與構造器參數類型一致的bean,那麼將會拋出異常。
autodeleted,通過bean類的自省機制(introspection來決定是使用constructor還是byType方式進行自動裝配。如果發現默認的構造器,那麼將使用byType方式。
spring2.5爲我們引入了組件自動掃描機制,他可以在類路徑下尋找標註了@Component,@Service,@Controller,@Repository註解的類,並把這些類納入進spring容器中管理,它的作用和在xml文件中使用bean節點配置組件是一樣的,要使用自動掃描機制,我們需要在配置文件中配置以下信息:
<context:component-scan base-package=”cn.itcast”>
其中base-package爲需要掃描的包(含子包)
@Service用於標註業務層組件、@Controller用於標註控制層組件(如struts中的action)、@Repository用於標註數據訪問組件,即DAO組件,而@Component泛指組件,當組件不好歸類時,我們可以使用這個註解進行註冊。