spring

IOC

Bean的裝配

自動化裝配

自動裝配就是讓Spring自動滿足bean依賴的一種方法爽柒,在滿足依賴的過程中,會在Spring應用上下文中尋找匹配某個bean需求的其他bean祠肥。為了聲明要進行自動裝配,我們可以借助Spring的@Autowired注解歧寺。

Spring從兩個角度來實現(xiàn)自動化裝配:

  • 組件掃描(component scanning):Spring會自動發(fā)現(xiàn)應用上下文中所創(chuàng)建的bean纵散。

  • 自動裝配(autowiring):Spring自動滿足bean之間的依賴。

通過Java代碼裝配bean

想要將第三方庫中的組件裝配到你的應用中人芽,在這種情況下,是沒有辦法在它的類上添加@Component@Autowired注解的绩脆,因此就不能使用自動化裝配的方案了萤厅。

通過@Configuration@Bean

通過XML裝配bean

該選擇構造器注入還是屬性注入呢?作為一個通用的規(guī)則靴迫,我傾向于對強依賴使用構造器注入惕味,而對可選性的依賴使用屬性注入。

    <!-- 1.通過其它bean -->
    <constructor-arg ref="compactDisc">
    <!-- 2.通過參數(shù) -->
    <constructor-arg value="sgt"/>
    <constructor-arg value="beatles"/>
    <!-- 3.通過list/set -->
    <constructor-arg>
        <list>
            <value> value1</value>
            <value> value2</value>
            <value> value3</value>
            <ref bean="bean1"></ref>
            <ref bean="bean2"></ref>
            <ref bean="bean3"></ref>
        </list>
        <set>
            <value> value4</value>
            <ref bean="bean4"></ref>
        </set>
    </constructor-arg>
</bean>

當Spring遇到這個<bean>元素時玉锌,它會創(chuàng)建一個CDPlayer實例名挥。<constructor-arg>元素會告知Spring要將一個ID為compactDisc的bean引用傳遞到CDPlayer的構造器中。

使用<constructor-arg>元素進行構造器參數(shù)的注入主守。除了使用“ref”屬性來引用其他的bean禀倔,還可以使用value屬性榄融,通過該屬性表明給定的值要以字面量的形式注入到構造器之中。

<list>元素是<constructor-arg>的子元素救湖,這表明一個包含值的列表將會傳遞到構造器中愧杯。其中,<value>元素用來指定列表中的每個元素鞋既。也可以使用<ref>元素替代<value>力九,實現(xiàn)bean引用列表的裝配。

<bean id="cdPlayer" class="soundSystem.CDPlayer">
    <property name="compactDisc" ref="compactDisc" />
    <property name="title" value="july"/>
    <property name="artist" value="jay"/>
    <property name="tracks">
        <list>
            <value> value1</value>
            <value> value2</value>
            <value> value3</value>
        </list>
    </property>
</bean>

<property>元素為屬性的Setter方法所提供的功能與<constructor-arg>元素為構造器所提供的功能是一樣的邑闺。在本例中跌前,它引用了ID為compactDisc的bean(通過ref屬性),并將其注入到compactDisc屬性中(通過setCompactDisc()方法陡舅。

bean的作用域

在默認情況下抵乓,Spring應用上下文中所有bean都是作為以單例(singleton)的形式創(chuàng)建的。也就是說蹭沛,不管給定的一個bean被注入到其他bean多少次臂寝,每次所注入的都是同一個實例。

在大多數(shù)情況下摊灭,單例bean是很理想的方案咆贬。初始化和垃圾回收對象實例所帶來的成本只留給一些小規(guī)模任務,在這些任務中帚呼,讓對象保持無狀態(tài)并且在應用中反復重用這些對象可能并不合理掏缎。

有時候,可能會發(fā)現(xiàn)煤杀,你所使用的類是易變的(mutable)眷蜈,它們會保持一些狀態(tài),因此重用是不安全的沈自。在這種情況下酌儒,將class聲明為單例的bean就不是什么好主意了,因為對象會被污染枯途,稍后重用的時候會出現(xiàn)意想不到的問題忌怎。

Spring定義了多種作用域,可以基于這些作用域創(chuàng)建bean酪夷,包括:

  • 單例(Singleton):在整個應用中榴啸,只創(chuàng)建bean的一個實例。

  • 原型(Prototype):每次注入或者通過Spring應用上下文獲取的時候晚岭,都會創(chuàng)建一個新的bean實例鸥印。

  • 會話(Session):在Web應用中,為每個會話創(chuàng)建一個bean實例。

  • 請求(Rquest):在Web應用中库说,為每個請求創(chuàng)建一個bean實例狂鞋。

在Web應用中,如果能夠?qū)嵗跁捄驼埱蠓秶鷥?nèi)共享的bean璃弄,那將是非常有價值的事情要销。例如,在典型的電子商務應用中夏块,可能會有一個bean代表用戶的購物車疏咐。如果購物車是單例的話,那么將會導致所有的用戶都會向同一個購物車中添加商品脐供。另一方面浑塞,如果購物車是原型作用域的,那么在應用中某一個地方往購物車中添加商品政己,在應用的另外一個地方可能就不可用了酌壕,因為在這里注入的是另外一個原型作用域的購物車。就購物車bean來說歇由,會話作用域是最為合適的卵牍,因為它與給定的用戶關聯(lián)性最大。

運行時值注入

將一個值注入到bean的屬性或者構造器參數(shù)中沦泌。

在Spring中娶牌,處理外部值的最簡單方式就是聲明屬性源并通過Spring的Environment來檢索屬性朝捆。

Spring一直支持將屬性定義到外部的屬性的文件中宿崭,并使用占位符值將其插入到Spring bean中愿阐。在Spring裝配中,占位符的形式為使用“${... }”包裝的屬性名稱回挽。

AOP

Spring AOP構建在動態(tài)代理基礎之上没咙,因此,Spring對AOP的支持局限于方法攔截千劈。如果你的AOP需求超過了簡單的方法調(diào)用(如構造器或?qū)傩詳r截)祭刚,那么你需要考慮使用AspectJ來實現(xiàn)切面。

AOP術語

通知(Advice)

切面的工作被稱為通知,通知定義了切面是什么以及何時使用墙牌。

Spring切面可以應用5種類型的通知:

  • 前置通知(Before):在目標方法被調(diào)用之前調(diào)用通知功能袁梗;

  • 后置通知(After):在目標方法完成之后調(diào)用通知,此時不會關心方法的輸出是什么憔古;

  • 返回通知(After-returning):在目標方法成功執(zhí)行之后調(diào)用通知;

  • 異常通知(After-throwing):在目標方法拋出異常后調(diào)用通知淋袖;

  • 環(huán)繞通知(Around):通知包裹了被通知的方法鸿市,在被通知的方法調(diào)用之前和調(diào)用之后執(zhí)行自定義的行為。

連接點(Join point)

連接點是在應用執(zhí)行過程中能夠插入切面的一個點。這個點可以是調(diào)用方法時焰情、拋出異常時陌凳、甚至修改一個字段時。切面代碼可以利用這些點插入到應用的正常流程之中内舟,并添加新的行為合敦。

切點(Poincut)

如果說通知定義了切面的“什么”和“何時”的話,那么切點就定義了“何處”验游。切點的定義會匹配通知所要織入的一個或多個連接點充岛。一個切面并不需要通知應用的所有連接點。切點有助于縮小切面所通知的連接點的范圍耕蝉。

我們通常使用明確的類和方法名稱崔梗,或是利用正則表達式定義所匹配的類和方法名稱來指定這些切點。

切面(Aspect)

切面是通知和切點的結合垒在。通知和切點共同定義了切面的全部內(nèi)容——它是什么蒜魄,在何時和何處完成其功能。

引入(Introduction)

引入允許我們向現(xiàn)有的類添加新方法或?qū)傩猿∏@缣肝覀兛梢詣?chuàng)建一個Auditable通知類,該類記錄了對象最后一次修改時的狀態(tài)踢关。這很簡單伞鲫,只需一個方法,setLastModified(Date)耘成,和一個實例變量來保存這個狀態(tài)榔昔。然后,這個新方法和實例變量就可以被引入到現(xiàn)有的類中瘪菌,從而可以在無需修改這些現(xiàn)有的類的情況下撒会,讓它們具有新的行為和狀態(tài)。

織入(Weaving)

織入是把切面應用到目標對象并創(chuàng)建新的代理對象的過程师妙。切面在指定的連接點被織入到目標對象中诵肛。

在目標對象的生命周期里有多個點可以進行織入:

  • 編譯期:切面在目標類編譯時被織入。這種方式需要特殊的編譯器默穴。AspectJ的織入編譯器就是以這種方式織入切面的怔檩。

  • 類加載期:切面在目標類加載到JVM時被織入。這種方式需要特殊的類加載器(ClassLoader)蓄诽,它可以在目標類被引入應用之前增強該目標類的字節(jié)碼薛训。AspectJ 5的加載時織入(load-timeweaving,LTW)就支持以這種方式織入切面仑氛。

  • 運行期:切面在應用運行的某個時刻被織入乙埃。一般情況下闸英,在織入切面時,AOP容器會為目標對象動態(tài)地創(chuàng)建一個代理對象介袜。Spring AOP就是以這種方式織入切面的甫何。

Spring AOP

代理類封裝了目標類,并攔截被通知方法的調(diào)用遇伞,再把調(diào)用轉發(fā)給真正的目標bean辙喂。當代理攔截到方法調(diào)用時,在調(diào)用目標bean方法之前鸠珠,會執(zhí)行切面邏輯巍耗。

因為Spring基于動態(tài)代理,所以Spring只支持方法連接點跳芳。這與一些其他的AOP框架是不同的芍锦,例如AspectJ和JBoss,除了方法切點飞盆,它們還提供了字段和構造器接入點娄琉。Spring缺少對字段連接點的支持,無法讓我們創(chuàng)建細粒度的通知吓歇,例如攔截對象字段的修改孽水。而且它不支持構造器連接點,我們就無法在bean創(chuàng)建時應用通知城看。

關于環(huán)繞通知

環(huán)繞通知是最為強大的通知類型女气。它能夠讓你所編寫的邏輯將被通知的目標方法完全包裝起來。實際上就像在一個通知方法中同時編寫前置通知和后置通知测柠。

關于這個新的通知方法炼鞠,它接受ProceedingJoinPoint作為參數(shù)。這個對象是必須要有的轰胁,因為你要在通知中通過它來調(diào)用被通知的方法谒主。通知方法中可以做任何的事情,當要將控制權交給被通知的方法時赃阀,它需要調(diào)用ProceedingJoinPointproceed()方法霎肯。需要注意的是,別忘記調(diào)用proceed()方法榛斯。如果不調(diào)這個方法的話观游,那么你的通知實際上會阻塞對被通知方法的調(diào)用。有可能這就是你想要的效果驮俗,但更多的情況是你希望在某個點上執(zhí)行被通知的方法懂缕。

有意思的是,你可以不調(diào)用proceed()方法王凑,從而阻塞對被通知方法的訪問提佣,與之類似吮蛹,你也可以在通知中對它進行多次調(diào)用。要這樣做的一個場景就是實現(xiàn)重試邏輯拌屏,也就是在被通知方法失敗后,進行重復嘗試术荤。

SpringMVC

spring mvc流程.png

[^] springMVC調(diào)用流程

  1. DispatcherServlet:`Spring MVC所有的請求都會通過一個前端控制器(front controller)Servlet倚喂。前端控制器是常用的Web應用程序模式,在這里一個單實例的Servlet將請求委托給應用程序的其他組件來執(zhí)行實際的處理瓣戚。任務是將請求發(fā)送給Spring MVC控制器(controller)端圈。

  2. controller控制器是一個用于處理請求的Spring組件。在典型的應用程序中可能會有多個控制器子库,DispatcherServlet需要知道應該將請求發(fā)送給哪個控制器舱权。所以DispatcherServlet以會查詢一個或多個處理器映射(handler mapping) 來確定請求的下一站在哪里。處理器映射會根據(jù)請求所攜帶的URL信息來進行決策仑嗅。

  3. 一旦選擇了合適的控制器宴倍,DispatcherServlet會將請求發(fā)送給選中的控制器〔旨迹控制器將業(yè)務邏輯委托給一個或多個服務對象進行處理鸵贬。

  4. 在完成邏輯處理后,通常會產(chǎn)生一些信息脖捻,這些信息需要返回給用戶并在瀏覽器上顯示阔逼。這些信息被稱為模型(model)。不過僅僅給用戶返回原始的信息是不夠的——這些信息需要以用戶友好的方式進行格式化地沮,一般會是HTML嗜浮。所以,信息需要發(fā)送給一個視圖(view)摩疑,通常會是JSP危融。控制器所做的最后一件事就是將模型數(shù)據(jù)打包未荒,并且標示出用于渲染輸出的視圖名专挪。它接下來會將請求連同模型和視圖名發(fā)送回DispatcherServlet

  5. DispatcherServlet將會使用視圖解析器(view resolver)來將邏輯視圖名匹配為一個特定的視圖實現(xiàn)。

  6. 既然DispatcherServlet已經(jīng)知道由哪個視圖渲染結果片排,那請求的任務基本上也就完成了寨腔。它的最后一站是視圖的實現(xiàn)(可能是JSP) ,在這里它交付模型數(shù)據(jù)率寡。請求的任務就完成了迫卢。視圖將使用模型數(shù)據(jù)渲染輸出,這個輸出會通過響應對象傳遞給客戶端冶共。

Spring事務

所謂的事物管理指的是“按照指定事物規(guī)則執(zhí)行提交或者回滾操作”乾蛤,而spring的事物管理每界,指的是spring對事物管理規(guī)則的抽象。具體來說就是spring不直接管理事物家卖,而是為了不同的平臺(如jdbc hibernate jpa 等)提供了不同的事物管理器 眨层,將具體的事物管理委托給相應的平臺實現(xiàn),spring并不關心具體事物管理的實現(xiàn)上荡,從而為事物管理提供了通用編程模型趴樱。

spring事務管理器

jdbc事物管理器

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
 </bean>

hibernate事物管理器

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

其它事務管理器

org.springframework.orm.jpaorg.springframework.transaction.jta.JtaTransactionManager酪捡,org.springframework.jms.connection.JmsTransactionManager

spring 事物的基本行為

事物的相關屬性就定義在java.sql.Connection.TransactionDefinition類中

    /**
     * 獲取傳播行為
     */
    int getPropagationBehavior();

    /**
     * 獲取隔離級別
     */
    int getIsolationLevel();

    /**
     * 獲取超時時間
     */
    int getTimeout();

    /**
     * 獲取只讀屬性
     */
    boolean isReadOnly();

    /**
     * 獲取事物的名稱 默認為classname+"."+methodName
     */
    String getName();

事物的傳播行為

所謂事物的傳播行為叁征,指的是被事物標記的方法(注解或者xml聲明),之間進行嵌套調(diào)用時事物的傳播規(guī)則逛薇。拿jdbc事物管理器來說捺疼,就是共用同一個jdbc connection,還是新建connection永罚,還是拋異常啤呼。這個規(guī)則就叫做事物的傳播行為。

傳播行為 說明
PROPAGATION_REQUIRED 如果存在事務尤蛮,則加入當前事務媳友。如果不存在事務,則新建产捞。 默認傳播行為
PROPAGATION_SUPPORTS 支持事務醇锚,如果不存在事務則以非事務的狀態(tài)運行。
PROPAGATION_MANDATORY 必須存在事務坯临,不存在拋異常焊唬。
PROPAGATION_NEVER 不支持事務,如當前存在事務則拋異常看靠。
PROPAGATION_REQUIRES_NEW 無論當前是否存在事務赶促,都新建事務。 僅支持JtaTransactionManager作為事務管理器挟炬。
PROPAGATION_NOT_SUPPORTED 不支持事務鸥滨,如當前存在事務則將當前事物掛起,以非事務的方式運行 僅支持JtaTransactionManager作為事務管理器谤祖。
PROPAGATION_NESTED 嵌套事務婿滓。如果當前不存在事務以PROPAGATION_REQUIRED的方式運行。如果存在事務則以嵌套事務的方式運行粥喜。 僅支持DataSourceTransactionManager作為事務管理器和部分JTA事務管理器

關于PROPAGATION_NESTED

@Transactional(propagation = Propagation.REQUIRED)
    void methodA(){
        //doSomethingA()
        ((ServiceName)AopContext.currentProxy()).methodB();
    }

    @Transactional(propagation = Propagation.NESTED)
    void methodB(){
        //doSomethingB()
        //successOrNot
    }

單獨調(diào)用methodB 時凸主,相當于 PROPAGATION_REQUIRED。當調(diào)用methodA時额湘,則以嵌套事物的方式運行卿吐,methodB作為methodA的子事物旁舰,提交和回滾都會受methodA的事物的影響。

一般我們用PROPAGATION_NESTED來執(zhí)行分支邏輯嗡官。當methodB執(zhí)行失敗的時候箭窜,則methodA 回滾到之前的保存點,然后執(zhí)行catch塊中的其它業(yè)務邏輯衍腥,就像methodB從未執(zhí)行過一樣绽快。這也是PROPAGATION_NESTED最常用的用法。

事物的隔離級別

事物的隔離級別紧阔,指的是并發(fā)情況下,事物之間的隔離度续担。不同的隔離級別擅耽,可以解決不同的隔離問題,也對應著不同的并發(fā)度物遇,使用的時候乖仇,要結合實際情況,按需選擇询兴。

問題 描述
臟讀 事物A讀到了事物B未提交的數(shù)據(jù)乃沙,如果事物B的操作被回滾了,那么事物A讀到的就是無效數(shù)據(jù)诗舰。
不可重復讀 事物A執(zhí)行select 查詢到結果集R1警儒,此時事物B執(zhí)行update 并提交,事物A再執(zhí)行同樣的select 查詢到結果集R2眶根。兩次查詢到的結果集不一致蜀铲。
幻讀 事物A執(zhí)行select 查詢到結果集R1,此事事物B執(zhí)行了 insert 或者 delete 操作 并提交属百,事物A再執(zhí)行同樣的select 查詢到結果集R2记劝。此時發(fā)現(xiàn)R2相比R1多了或者少了一些記錄

spring事務隔離級別

級別 描述 臟讀 不可重復讀 幻讀
ISOLATION_DEFAULT 使用數(shù)據(jù)庫隔離級別。
ISOLATION_READ_UNCOMMITTED 讀未提交 X X X
ISOLATION_READ_COMMITTED 讀已提交oracle 默認隔離級別族扰,利用快照讀解決臟讀 Y X X
ISOLATION_REPEATABLE_READ 可重復讀mysql 默認隔離級別厌丑,除了讀快照之外,事物啟動后不允許執(zhí)行update操作 Y Y X
ISOLATION_SERIALIZABLE 串行化 Y Y Y

事物的只讀屬性-readOnly

spring 事物的只讀屬性是通過設置渔呵,java.sql.Connection 的 readOnly 屬性來實現(xiàn)的怒竿。當設置了只讀屬性后,數(shù)據(jù)庫會對只讀事物進行一些優(yōu)化厘肮,如不啟用回滾段愧口,不啟用回滾日志等。

事物的超時時間-timeout

事物的超時指的是設置一個時間类茂,當執(zhí)行時間超過這個時間后耍属,拋異常并回滾托嚣。是通過設置一個截至時間來實現(xiàn)的,值得注意的是厚骗,這個超時時間只有特定情況下才會生效示启,如dao層使用jdbcTemplete 執(zhí)行sql

回滾規(guī)則-rollbackFor

回滾規(guī)則只得是spring 事物遇到哪種異常會回滾。默認只回滾RuntimeException和Error

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末领舰,一起剝皮案震驚了整個濱河市夫嗓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冲秽,老刑警劉巖舍咖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锉桑,居然都是意外死亡排霉,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門民轴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來攻柠,“玉大人,你說我怎么就攤上這事后裸」迮ィ” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵微驶,是天一觀的道長浪谴。 經(jīng)常有香客問我,道長祈搜,這世上最難降的妖魔是什么较店? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮容燕,結果婚禮上梁呈,老公的妹妹穿的比我還像新娘。我一直安慰自己蘸秘,他們只是感情好官卡,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著醋虏,像睡著了一般寻咒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上颈嚼,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天毛秘,我揣著相機與錄音,去河邊找鬼。 笑死叫挟,一個胖子當著我的面吹牛艰匙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抹恳,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼员凝,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奋献?” 一聲冷哼從身側響起健霹,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瓶蚂,沒想到半個月后糖埋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡窃这,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年阶捆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钦听。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖倍奢,靈堂內(nèi)的尸體忽然破棺而出朴上,到底是詐尸還是另有隱情,我是刑警寧澤卒煞,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布痪宰,位于F島的核電站,受9級特大地震影響畔裕,放射性物質(zhì)發(fā)生泄漏衣撬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一扮饶、第九天 我趴在偏房一處隱蔽的房頂上張望具练。 院中可真熱鬧,春花似錦甜无、人聲如沸扛点。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陵究。三九已至,卻和暖如春奥帘,著一層夾襖步出監(jiān)牢的瞬間铜邮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留松蒜,地道東北人扔茅。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像牍鞠,于是被迫代替她去往敵國和親咖摹。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354