Spring的示例分析

這篇文章將為大家詳細(xì)講解有關(guān)Spring的示例分析,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

專注于為中小企業(yè)提供網(wǎng)站建設(shè)、成都網(wǎng)站制作服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)乳源免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了成百上千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

WHY

在誕生之初,創(chuàng)建Spring的主要目的是用來(lái)替代更加重量級(jí)的企業(yè)級(jí)Java技術(shù),尤其是EJB。相對(duì)于EJB來(lái)說(shuō),Spring提供了更加輕量級(jí)和簡(jiǎn)單的編程模型。

WHAT

Spring是一個(gè)開(kāi)源框架,最早由RodJohnson創(chuàng)建,Spring是為了解決企業(yè)級(jí)應(yīng)用開(kāi)發(fā)的復(fù)雜性而創(chuàng)建的,使用Spring可以讓簡(jiǎn)單的JavaBean實(shí)現(xiàn)之前只有EJB才能完成的事情。Spring不僅僅限于服務(wù)端的開(kāi)發(fā),任何Java應(yīng)用都能在簡(jiǎn)單性、可測(cè)試性和松耦合等方面從Spring中獲益。

如今Spring在移動(dòng)開(kāi)發(fā)、社交API集成、NoSql數(shù)據(jù)庫(kù)、云計(jì)算及大數(shù)據(jù)方面都在涉足。隨著時(shí)間的推移EJB也采用了依賴注入(DependencyInjection,DI)和面向切面編程(Aspect-OrientedProgramming,AOP)的理念??傊琒pring最根本的使命就是簡(jiǎn)化Java開(kāi)發(fā)

HOW

為了降低Java開(kāi)發(fā)的復(fù)雜性,Spring采取了4鐘關(guān)鍵策略

基于POJO的輕量級(jí)和最小侵入性編程通過(guò)依賴注入和面向接口實(shí)現(xiàn)松耦合

基于切面和慣例進(jìn)行聲明式編程通過(guò)切面和模板減少樣式代碼

POJO潛能

很多框架通過(guò)強(qiáng)迫應(yīng)用繼承它們的類或?qū)崿F(xiàn)它們的接口從而導(dǎo)致應(yīng)用與框架綁定在一起,這就是侵入性編程,導(dǎo)致無(wú)法復(fù)用代碼塊。Spring竭力避免因自身的API而弄亂你的應(yīng)用代碼,在基于Spring構(gòu)建的應(yīng)用程序中,他的類通常沒(méi)有任何痕跡表明你使用了Spring

public class HelloWorldBean {
  public String sayHello(){
    return "Hello World";
  }
}

以上的實(shí)例代碼表示一個(gè)很簡(jiǎn)單普通的Java類(POJO),你看不出來(lái)他是一個(gè)Spring組件,Spring的非侵入式編程體現(xiàn)在這個(gè)類在Spring應(yīng)用和非Spring應(yīng)用中都可以發(fā)揮作用。僅僅這么一段代碼并沒(méi)有能實(shí)際體現(xiàn)Spring功能,還需要后面的知識(shí)。
依賴注入(將自身依賴的類注入的自身)

依賴注入這個(gè)此在Spring中并不是這么高大上,盡管現(xiàn)在已經(jīng)演變成一項(xiàng)復(fù)雜的編程技巧或者設(shè)計(jì)模式理念。在Spring中可以這么理解,注入依賴。一個(gè)具有實(shí)際意義的應(yīng)用都需要多個(gè)類進(jìn)行相互協(xié)作來(lái)完成特定的業(yè)務(wù)邏輯。傳統(tǒng)的做法是每個(gè)對(duì)象負(fù)責(zé)管理與自己有關(guān)的對(duì)象(這個(gè)有關(guān)的對(duì)象就是Spring中表述的所依賴的對(duì)象)的引用,不過(guò)這將會(huì)導(dǎo)致高度耦合和代碼難以測(cè)試

考慮如下代碼

/**這個(gè)拗口的類名是作者為了擬合一個(gè)模擬的場(chǎng)景特地取名
 * 這個(gè)類表示營(yíng)救少女的騎士
 * Created by Wung on 2016/8/25.
 */
public class DamselRescuingKnight implements Knight{
	private RescueDamselQuest quest;
	/**
   * 在它的構(gòu)造函數(shù)中自行創(chuàng)建了RescueDamselQuest
   * 這使得DamselRescuingKnight和在它的構(gòu)造函數(shù)中自行創(chuàng)建了RescueDamselQuest耦合在了一起
   */
	public DamselRescuingKnight(){
		this.quest = new RescueDamselQuest();
	}
	public void embarkOnQuest(){
		quest.embark();
	}
}

耦合具有兩面性,一方面,緊密耦合的代碼難以測(cè)試難以復(fù)用難以理解,并且會(huì)出現(xiàn)"打地鼠"式的BUG。另一方面,一定程度的耦合又是必要的,不同的類必須以適當(dāng)?shù)姆绞竭M(jìn)行交互。

問(wèn)題出現(xiàn)了,那么Spring是如何解決的呢

在Spring中,通過(guò)依賴注入(DI),對(duì)象之間的依賴關(guān)系由系統(tǒng)中負(fù)責(zé)協(xié)調(diào)各對(duì)象的第三方組件在創(chuàng)建對(duì)象的時(shí)候進(jìn)行設(shè)定。也就是說(shuō)對(duì)象只需要管理自己內(nèi)部的屬性而無(wú)需自行創(chuàng)建或者管理它們的依賴關(guān)系,依賴關(guān)系會(huì)被自動(dòng)注入到需要它們的對(duì)象當(dāng)中去。

/**
 * 這個(gè)騎士可以執(zhí)行各種冒險(xiǎn)任務(wù)而不在僅僅是之前那個(gè)營(yíng)救少女的任務(wù)
 * Created by Wung on 2016/8/25.
 */
public class BraveKnight implements Knight{
	private Quest quest;
	/**
   * BraveKnight沒(méi)有自行創(chuàng)建冒險(xiǎn)類型,而是在構(gòu)造的時(shí)候把冒險(xiǎn)任務(wù)作為參數(shù)傳入
   * 這是依賴注入的方式之一:構(gòu)造器注入
   */
	public BraveKnight(Quest quest){
		this.quest = quest;
	}
	public void embarkOnQuest(){
		quest.embark();
	}
}

BraveKnight沒(méi)有與任何特定的Quest實(shí)現(xiàn)發(fā)生耦合,只要某個(gè)任務(wù)實(shí)現(xiàn)了Quest接口,那么具體是哪種類型的冒險(xiǎn)就無(wú)所謂了,這就打到了DI的目的——松耦合

如果一個(gè)對(duì)象只通過(guò)接口來(lái)表明依賴關(guān)系,那么這種依賴關(guān)系就能夠在對(duì)象本身毫不知情的情況下用不同的具體實(shí)現(xiàn)來(lái)進(jìn)行替代。

那么現(xiàn)在來(lái)進(jìn)行實(shí)際意義的注入

對(duì)于上面那塊代碼我們來(lái)將一個(gè)具有具體實(shí)現(xiàn)的冒險(xiǎn)任務(wù)注入到勇敢騎士中去

/**屠龍的冒險(xiǎn)任務(wù)(這個(gè)作者好中二阿)
 * Created by Wung on 2016/8/25.
 */
public class SlayDragonQuest implements Quest{
	private PrintStream stream;
	public SlayDragonQuest(PrintStream stream){
		this.stream = stream;
	}
	public void embark() {
		stream.print("slay the dragon");
	}
}

那么現(xiàn)在問(wèn)題來(lái)了,在SlayDragonQuest中如何注入它所依賴的PrintStream對(duì)象,在BraveKnight中如何注入它所依賴的Quest對(duì)象。前面提到的Spring會(huì)將這些依賴進(jìn)行集中管理,創(chuàng)建應(yīng)用組件之間協(xié)作的行為通常稱為裝配(wiring)也就是注入。Spring提供了多種裝配的方式在后面會(huì)更加詳細(xì)的介紹,此處簡(jiǎn)單介紹基于XML的裝配和基于Java注解的裝配

<!--
    這就是一個(gè)裝配的過(guò)程,將SlayDragonQuest聲明為一個(gè)bean,取名為"quest"
    因?yàn)槭菢?gòu)造器注入所以使用constructor-arg屬性 value表示注入的值
    那么這個(gè)過(guò)程解決了之前的問(wèn)題,將PrintStream對(duì)象注入到SlayDragonQuest對(duì)象中
  -->
  <bean class="impl.SlayDragonQuest" id="quest">
    <constructor-arg value="#{T(System).out}">
  </constructor-arg></bean>
 
  <!--
    這個(gè)過(guò)程同上,BraveKnight聲明為一個(gè)bean取名為"knight"(不一定使用到這個(gè)名字)
    然后BraveKnight的構(gòu)造器參數(shù)要求為Quest類型此時(shí)傳入了另外一個(gè)bean的引用
    就是上面這個(gè)名字"quest"的bean的引用,此時(shí)也完成了對(duì)BraveKnight的構(gòu)造器注入
   -->
  <bean class="impl.BraveKnight" id="knight">
    <constructor-arg ref="quest">
  </constructor-arg></bean>

Spring提供了基于Java的配置,可作為XML的替代方案

/**基于Java的配置文件實(shí)現(xiàn)對(duì)象的裝配
 * Created by Wung on 2016/8/26.
 */
@Configuration
public class KnightConfig {
   
  @Bean
  public Knight knight(){
    return new BraveKnight(quest());
  }
 
  @Bean
  public Quest quest(){
    return new SlayDragonQuest(System.out);
  }
}

效果是相同的,具體的解釋在下一章中詳細(xì)描述?,F(xiàn)在再來(lái)回顧一下,一直說(shuō)Spring會(huì)自動(dòng)管理對(duì)象之間的依賴關(guān)系,那么這種管理者是什么。答案是Application Context(應(yīng)用上下文),它是Spring的一種容器,可以裝載bean的定義并將它們組裝起來(lái)。Spring應(yīng)用上下文全權(quán)負(fù)責(zé)對(duì)象的創(chuàng)建和組裝。實(shí)際上這個(gè)Context有好多中實(shí)現(xiàn)他們之間的區(qū)別僅僅是加載配置的方式不同,下面來(lái)看一種加載配置的方式

public class KnightMain {
 
  public static void main(String[] args){
    AnnotationConfigApplicationContext context = new
        AnnotationConfigApplicationContext(KnightConfig.class);
    //從配置文件中就可以獲取到bean的定義了
    Knight knight = context.getBean(Knight.class);
    knight.embarkOnQuest();
    context.close();
  }
 
}

應(yīng)用切面

DI能夠讓相互協(xié)作的軟件組件保持松耦合,而面向切面編程允許你把遍布應(yīng)用各處的功能分離出來(lái)形成可重用的組件,更詳細(xì)的說(shuō),它是促使軟件系統(tǒng)實(shí)現(xiàn)關(guān)注點(diǎn)奮力的一項(xiàng)技術(shù)。什么是關(guān)注點(diǎn)呢,諸如日志、事務(wù)管理、安全管理這樣的系統(tǒng)服務(wù)經(jīng)常需要融入到其他自身具有業(yè)務(wù)邏輯的組件中去,那么這些系統(tǒng)服務(wù)通常就被稱為橫切關(guān)注點(diǎn),因?yàn)樗鼈儠?huì)在多個(gè)地方被重用,跨越系統(tǒng)的多個(gè)組件。簡(jiǎn)單來(lái)說(shuō),就是你把需要重用的經(jīng)常會(huì)服務(wù)與各種其他組件的組件抽離出來(lái),但是抽離出來(lái)如何使用呢,其實(shí)就是在用的時(shí)候?qū)⒎椒ú迦氲叫枰褂玫牡胤?。但是根?jù)這個(gè)"切面"的術(shù)語(yǔ),應(yīng)該表述為將重用的組件抽離出來(lái)作為一個(gè)切面,在需要使用的時(shí)候?qū)⑶忻鏅M切進(jìn)組件。所以這樣就做到了核心應(yīng)用不需要知道這些切面的存在,切面也不會(huì)將業(yè)務(wù)邏輯融合在核心應(yīng)用中。

/**一個(gè)歌手類用來(lái)歌頌騎士也就是服務(wù)于騎士類
 * Created by Wung on 2016/8/26.
 */
public class Minstrel {
 
  private PrintStream stream;
 
  public Minstrel(PrintStream stream){
    this.stream = stream;
  }
  //在冒險(xiǎn)之前執(zhí)行
  public void singBeforeQuest(){
    stream.print("Begin");
  }
  //在冒險(xiǎn)之后執(zhí)行
  public void singAfterQuest(){
    stream.print("End");
  }
 
}
public class BraveKnight implements Knight{
	private Quest quest;
	private Minstrel minstrel;
	/**
   * BraveKnight沒(méi)有自行創(chuàng)建冒險(xiǎn)類型,而是在構(gòu)造的時(shí)候把冒險(xiǎn)任務(wù)作為參數(shù)傳入
   * 這是依賴注入的方式之一:構(gòu)造器注入
   */
	//  public BraveKnight(Quest quest){
	//    this.quest = quest;
	//  }
	public BraveKnight(Quest quest, Minstrel minstrel){
		this.quest = quest;
		this.minstrel = minstrel;
	}
	public void embarkOnQuest(){
		minstrel.singBeforeQuest();
		quest.embark();
		minstrel.singAfterQuest();
	}
}

這個(gè)時(shí)候這個(gè)勇敢的騎士開(kāi)始執(zhí)行,但是他發(fā)現(xiàn)在他的職責(zé)中不僅僅是冒險(xiǎn)了,現(xiàn)在竟然還要管理這個(gè)歌手要為他歌頌,然而這本身并不應(yīng)該屬于這個(gè)類應(yīng)該管理的。所以應(yīng)用切面的思想,我們需要將這個(gè)歌手的歌頌行為抽離出來(lái)成為一個(gè)切面,在騎士冒險(xiǎn)之前這個(gè)切面將會(huì)橫切進(jìn)去執(zhí)行singBeforeQuest方法在冒險(xiǎn)之后執(zhí)行singAfterQuest方法。那么這樣是不是就實(shí)現(xiàn)了騎士中不需要歌頌的代碼,歌手也不存在與騎士對(duì)象中,他將不僅僅贊頌騎士,也可以贊頌任何人只要?jiǎng)e人使用這個(gè)切面切入即可

  <!-- 意思就是將上述id為minstrel的bean配置為切面實(shí)際上就是把歌手配置為切面 -->
  aspect ref="minstrel">
    <!-- 
      定義切入點(diǎn),也就是在哪里會(huì)使用切面 
      expression="execution(* *.embarkOnQuest(..))
      是一種AspectJ的切點(diǎn)表達(dá)式語(yǔ)言后面會(huì)深入
      此處的意思是會(huì)在embarkOnQuest()方法處切入
      下面那個(gè)分別為前置通知和后置通知在切入點(diǎn)之前和之后執(zhí)行
    --> 
  </aop:after></aop:before></aop:pointcut>
</aop:</aop:config>

現(xiàn)在的情況是Minstrel仍然是獨(dú)立的一個(gè)POJO,Spring的上下文已經(jīng)將他變成了一個(gè)切面了。最重要的是此時(shí)騎士完全不知道這個(gè)切面的存在,這只是一個(gè)小小的栗子,實(shí)際上可以做很多重要的事情。

使用模板消除樣式代碼

有這樣一種情況,當(dāng)我們使用JDBC訪問(wèn)數(shù)據(jù)庫(kù)查詢數(shù)據(jù)的時(shí)候,完整的流程需要建立連接、創(chuàng)建語(yǔ)句對(duì)象、處理結(jié)果集、查詢、關(guān)閉各種連接,此外還需要各種異常的捕獲,然后對(duì)于各種場(chǎng)景的查詢都需要如此費(fèi)心費(fèi)力的重復(fù)。JDBC還不僅僅是唯一這樣會(huì)有大量的樣式代碼的情況,Spring旨在通過(guò)模板封裝來(lái)消除樣式代碼,比如Spring的jdbcTemplate。

容納你的Bean

在基于Spring的應(yīng)用中,你的應(yīng)用對(duì)象生存于Spring容器,容器負(fù)責(zé)創(chuàng)建對(duì)象裝配對(duì)象并且管理他們的生命周期。那什么是Spring的容器呢,容器并不是只有一種,Spring自帶了多個(gè)容器實(shí)現(xiàn)。分為兩類:bean工廠,是最簡(jiǎn)單的容器提供基本的DI支持。應(yīng)用上下文比較高級(jí)提供應(yīng)用框架級(jí)別的服務(wù)。大多數(shù)情況下應(yīng)用上下文更加受歡迎。

應(yīng)用上下文也分為多種,顯著的區(qū)別的是加載配置的方式不同

Spring的各種功能

Spring的示例分析

關(guān)于“Spring的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

分享名稱:Spring的示例分析
瀏覽地址:http://bm7419.com/article30/iehjpo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、搜索引擎優(yōu)化云服務(wù)器、用戶體驗(yàn)網(wǎng)站設(shè)計(jì)、全網(wǎng)營(yíng)銷推廣

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化