Spring為了簡化Java開發(fā)而產(chǎn)生,使用Spring可以讓簡單的JavaBean實現(xiàn)之前只有EJB才能完成的事情,在簡單性,可測試性和松耦合等方面從Spring獲益。
一、Spring是怎么簡化java開發(fā)的??
1、 基于POJO的輕量級和最小侵入性變成
2、通過依賴注入和面向接口實現(xiàn)松耦合
3、基于切面和慣例進行聲明式編程
4、通過切面和模板減少樣板式代碼
1、Spring不會在HelloWorld上導入亂糟糟的方法。
2、依賴注入Dependency Injection(DI)
- 為什么要用DI
因為應用之間是通過很多組件和類的相互協(xié)作來完成的。通常,每個對象負責管理與自己相互協(xié)作的對象的引用,這樣會導致高度耦合和難以測試的代碼。
也就是相互調用太多,代碼看起來太復雜。當一個組件需要修改的時候,所有涉及到它的其他組件都要進行修改。
這里講了依賴注入的方式之一,構造器注入。
public class DamselRescuingKnight implements Knight{
private RescueDamselQuest quest;
public DamselRescuingKnight(){
quest = new RescueDamselQuest();
}
public void embarkOnQuest() throws QuestException{
quest.embark();
}
}
- DamselRescuingKnight在他的構造函數(shù)中自行創(chuàng)建了RescueDamselQuest。所以騎士就和這個任務緊密的結合在一起了。而且難以測試embark()是否在embarkQuest()方法被調用的時候執(zhí)行。所以這種寫法很不好。
- 所以我們采用依賴注入。對象的依賴關系將由負責協(xié)調系統(tǒng)中各個對象的第三方組件在創(chuàng)建對象時設定。對象無需自行創(chuàng)建或者管理它們的依賴關系。依賴關系將被自動注入到需要它們的對象中去。
public class BraveKnight implements Knight{
private Quest quest;
public BraveKnight(Quest quest){
this.quest = quest; -->Quest被注入進來
}
public void embarkOnQuest() throws QuestException{
quest.embark();
}
}
- 這里沒有自行創(chuàng)建任務。而是在構造時把任務當做構造器參數(shù)傳入,即構造注入
- 而 且Quest是所有任務的接口。可以實現(xiàn)任意一種任務。重要的是騎士沒有與任何一個特定的任務發(fā)生耦合。
- 這樣就實現(xiàn)了松耦合。
- 如果一個對象只通過接口(而不是具體化實現(xiàn)或者初始化的過程)來表明依賴關系,那么這種依賴就能夠在對象本身毫不知情的情況下,用不同的具體實現(xiàn)進行替換。也就是改實現(xiàn)不用換接口。
- 可以采用mock測試
然后可以用Spring將SlayDragonQuest通過XML文件注入到BraveKnight當中。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
http://www.springframework.org/schema/cache
default-lazy-init="true">
<bean id="knight" class = "com.springinaction.knights.BraveKnight">
<constructor-arg ref="quest"></constructor-arg> -->通過Constructor-arg來告訴Spring額外的信息
</bean>
<bean id="quest"
class="com.springinaction.knight.SlayDragonQusest">
</bean>
</beans>
Spring通過Application Context應用上下文裝載Bean
Spring應用上下文全權負責對象的創(chuàng)建和組裝。
-
Spring自帶了幾種應用上下文的實現(xiàn),它們之間的主要區(qū)別是如何加載它們的配置
public class KnightMain{ public static void main(String[] args){ ApplicationContext context = new ClassPathXmlApplicationContext("knight.xml"); -->加載Spring上下文 Knight knight = (Knight) context.getBean("knight"); -->獲取knight Bean knight.embarkOnQuest(); -->使用knight } } 這里的main()方法創(chuàng)建了一個Spring上下文,該上下文加載了knight.xml文件。隨后它調用該上下文獲取一個ID為knight的Bean。得到Knight的對象之后,只需要調用embarkOnQuest()方法就可以執(zhí)行所賦予的任務。
3、應用切面 (AOP Aspect Oriented Programming)
允許你把遍布應用程序各處的功能分離出來形成可重用的組件。
- 為什么要用AOP?
因為系統(tǒng)由許多不同的組件組成,每個組件負責一塊特定的職責。有些系統(tǒng)服務跨越多個組件,被稱為橫切關注點。
如果將這些服務分散到各個組件中,代碼將會變得重復而混亂。每個模塊都要調用這些服務
所以AOP使這些服務模塊化,并以聲明的方式將他們應用到需要影響的組件中去。將他們想象成一個切面,覆蓋了多個組件。使這些組件更關注自身業(yè)務而不需要了解系統(tǒng)服務
- 如何實現(xiàn)?
在Spring配置文件中聲明它。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
http://www.springframework.org/schema/cache
default-lazy-init="true">
<bean id="knight" class = "com.springinaction.knights.BraveKnight">
<constructor-arg ref="quest"></constructor-arg>
</bean>
<bean id="quest"
class="com.springinaction.knight.SlayDragonQusest">
</bean>
<bean id="minstrel" class="com.springinaction.knights.Minstrel"> -->聲明Minstrel Bean
</bean>
<aop:config>
<aop:aspect ref="minstrel">
<aop:pointcut id="embark"
expression="execution(**.embarkOnQuest(..))"/> -->定義切面
<aop:before pointcut-ref="embark" -->聲明前置通知
method="singBeforeQuest"/>
<aop:after pointcut-ref="embark" -->聲明后置通知
method="singAfterQuest/>
</aop:aspect>
</aop:config>
</beans>
使用AOP配置的命名空間把Minstrel Bean聲明為一個切面:
- 先聲明Minstrel為一個Bean,然后在<aop:aspect>元素中引用該bean
這樣就不用在knight中每次調用Minstrel了
4、使用模板消除樣板式代碼:封裝
比如使用JDBC的時候,樣板式代碼是核心業(yè)務代碼的好幾倍,這時候用Spring就簡潔的多
Spring通過模板封裝來消除樣板式代碼。比如JDBCTemplate就可以簡化原來的代碼,因為都被封裝了。
二、Bean的容器和生命周期
在基于Spring的應用中,應用對象生存于Spring的容器中。
容器是Spring框架的核心。有兩種類型
- Bean工廠(Bean Factories)
- 應用上下文(Application Context)基于BeanFactory之上構建,并提供面向應用的服務。最常用
三種最常見的應用上下文
1、ClassPathXmlApplicationContext
從類路徑下的XML配置文件中加載上下文定義,把應用上下文定義文件當做資源
2、FileSystemXmlApplicationContext
讀取文件系統(tǒng)下的XML配置文件并加載上下文定義
3、XmlWebApplicationContext
讀取web應用下的XML配置文件并加載上下文定義
通過現(xiàn)有的應用上下文引用,可以調用應用上下文的getBean()方法從Spring容器中獲取Bean