歡迎您光臨本站 註冊首頁

Spring事務管理高級應用難點剖析(2)

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0

  應用分層的迷惑

  Web、Service及DAO三層劃分就像西方國家的立法、行政、司法三權分立一樣被奉為金科玉律,甚至有開發人員認為如果要使用Spring事務管理就一定先要進行三層的劃分.這個看似荒唐的論調在開發人員中頗有市場.更有甚者,認為每層必須先定義一個介面,然後再定義一個實現類.其結果是:一個很簡單的功能,也至少需要3個介面,3個類,再加上視圖層的JSP和JS等,打牌都可以轉上兩桌了,這種誤解貽害不淺.

  對將「面向介面編程」奉為圭臬,認為放之四海而皆準的論調,筆者深不以為然.是的,「面向介面編程」是MartinFowler,RodJohnson這些大師提倡的行事原則.如果拿這條原則去開發架構,開發產品,怎麼強調都不為過.但是,對於我們一般的開發人員來說,做的最多的是普通工程項目,往往最多的只是一些對資料庫增、刪、查、改的功能.此時,「面向介面編程」除了帶來更多的類文件外,看不到更多其它的好處.

  Spring框架提供的所有附加的好處(AOP、註解增強、註解MVC等)唯一的前提就是讓POJO的類變成一個受Spring容器管理的Bean,除此以外沒有其它任何的要求.下面的實例用一個POJO完成所有的功能,既是Controller,又是Service,還是DAO:

  清單5.MixLayerUserService.java

  62.packageuser.mixlayer;

  63.importorg.springframework.beans.factory.annotation.Autowired;

  64.importorg.springframework.jdbc.core.JdbcTemplate;

  65.importorg.springframework.stereotype.Controller;

  66.importorg.springframework.web.bind.annotation.RequestMapping;

  67.//①.將POJO類通過註解變成SpringMVC的Controller

  68.@Controller

  69.publicclassMixLayerUserService{

  70.

  71.//②.自動注入JdbcTemplate

  72.@Autowired

  73.privateJdbcTemplatejdbcTemplate;

  74.

  75.//③.通過SpringMVC註解映URL請求

  76.@RequestMapping("/logon.do")

  77.publicStringlogon(StringuserName,Stringpassword){

  78.if(isRightUser(userName,password)){

  79.Stringsql="UPDATEt_useruSETu.score=u.score ?WHEREuser_name=?";

  80.jdbcTemplate.update(sql,20,userName);

  81.return"success";

  82.}else{

  83.return"fail";

  84.}

  85.}

  86.privatebooleanisRightUser(StringuserName,Stringpassword){

  87.//dosth...

  88.returntrue;

  89.}

  90.}

  通過@Controller註解將MixLayerUserService變成Web層的Controller,同時也是Service層的服務類.此外,由於直接使用JdbcTemplate訪問數據,MixLayerUserService還是一個DAO.來看一下對應的Spring配置文件:

  清單6.applicationContext.xml

  91.<?xmlversionxmlversion="1.0"encoding="UTF-8"?>

  92.<beansxmlnsbeansxmlns="http://www.springframework.org/schema/beans"

  93.xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  94.xmlns:context="http://www.springframework.org/schema/context"

  95.xmlns:p="http://www.springframework.org/schema/p"

  96.xmlns:aop="http://www.springframework.org/schema/aop"

  97.xmlns:tx="http://www.springframework.org/schema/tx"

  98.xsi:schemaLocation="http://www.springframework.org/schema/beans

  99.http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

  100.http://www.springframework.org/schema/context

  101. http://www.springframework.org/schema/context/spring-context-3.0.xsd

  102. http://www.springframework.org/schema/aop

  103. http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

  104. http://www.springframework.org/schema/tx

  105.http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

  106.

  107.<context:component-scanbase-packagecontext:component-scanbase-package="user.mixlayer"/>

  108.

  109.<beanclassbeanclass="org.springframework.web.servlet.mvc.annotation

  110. .AnnotationMethodHandlerAdapter"/>

  111.

  112.

  113.<beanclassbeanclass="org.springframework.web.servlet.view

  114. .InternalResourceViewResolver"

  115.pp:prefix="/WEB-INF/jsp/"p:suffix=".jsp"/>

  116.

  117.

  118.<beanidbeanid="dataSource"

  119.class="org.apache.commons.dbcp.BasicDataSource"

  120.destroy-method="close"

  121.p:driverClassName="oracle.jdbc.driver.OracleDriver"

  122.p:url="jdbc:oracle:thin:@localhost:1521:orcl"

  123.p:username="test"

  124.p:password="test"/>

  125.

  126.<beanidbeanid="jdbcTemplate"

  127.class="org.springframework.jdbc.core.JdbcTemplate"

  128.p:dataSource-ref="dataSource"/>

  129.

  130.

  131.<beanidbeanid="jdbcManager"

  132.class="org.springframework.jdbc.datasource.DataSourceTransactionManager"

  133.p:dataSource-ref="dataSource"/>

  134.

  135.

  136.<aop:configproxy-target-classaop:configproxy-target-class="true">

  137.<aop:pointcutidaop:pointcutid="serviceJdbcMethod"

  138.expression="execution(public*user.mixlayer.MixLayerUserService.*(..))"/>

  139.<aop:advisorpointcut-refaop:advisorpointcut-ref="serviceJdbcMethod"

  140.advice-ref="jdbcAdvice"order="0"/>

  141.</< span>aop:config>

  142.<tx:adviceidtx:adviceid="jdbcAdvice"transaction-manager="jdbcManager">

  143.<tx:attributes>

  144.<tx:methodnametx:methodname="*"/>

  145.</< span>tx:attributes>

  146.</< span>tx:advice>

  147.</< span>beans>

  在①處,我們定義配置了AnnotationMethodHandlerAdapter,以便啟用SpringMVC的註解驅動功能.而②和③處通過Spring的aop及tx命名空間,以及Aspject的切點表達式語法進行事務增強的定義,對MixLayerUserService的所有公有方法進行事務增強.要使程序能夠運行起來還必須進行web.xml的相關配置:

  清單7.web.xml

  1.<?xmlversionxmlversion="1.0"encoding="GB2312"?>

  2.<web-appversionweb-appversion="2.4"xmlns="http://java.sun.com/xml/ns/j2ee"

  3.xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  4.xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee

  5.http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  6.<context-param>

  7.<param-name>contextConfigLocation</< span>param-name>

  8.<param-value>classpath*:user/mixlayer/applicationContext.xml</< span>param-value>

  9.</< span>context-param>

  10.<context-param>

  11.<param-name>log4jConfigLocation</< span>param-name>

  12.<param-value>/WEB-INF/classes/log4j.properties</< span>param-value>

  13.</< span>context-param>

  14.

  15.<listener>

  16.<listener-class>

  17.org.springframework.web.util.Log4jConfigListener

  18.</< span>listener-class>

  19.</< span>listener>

  20.<listener>

  21.<listener-class>

  22.org.springframework.web.context.ContextLoaderListener

  23.</< span>listener-class>

  24.</< span>listener>

  25.

  26.<servlet>

  27.<servlet-name>user</< span>servlet-name>

  28.<servlet-class>

  29.org.springframework.web.servlet.DispatcherServlet

  30.</< span>servlet-class>

  31.

  32.<init-param>

  33.<param-name>contextConfigLocation</< span>param-name>

  34.<param-value>classpath:user/mixlayer/applicationContext.xml</< span>param-value>

  35.</< span>init-param>

  36.<load-on-startup>1</< span>load-on-startup>

  37.</< span>servlet>

  38.<servlet-mapping>

  39.<servlet-name>user</< span>servlet-name>

  40.<url-pattern>*.do</< span>url-pattern>

  41.</< span>servlet-mapping>

  42.</< span>web-app>

  這個配置文件很簡單,唯一需要注意的是DispatcherServlet的配置.默認情況下SpringMVC根據Servlet的名字查找WEB-INF下的-servlet.xml作為SpringMVC的配置文件,在此,我們通過contextConfigLocation參數顯式指定SpringMVC配置文件的確切位置.

  將org.springframework.jdbc及org.springframework.transaction的日誌級別設置為DEBUG,啟動項目,並訪問http://localhost:8088/logon.do?userName=tom應用,MixLayerUserService#logon方法將作出響應,查看後台輸出日誌:

  清單8執行日誌

  43.13:24:22,625DEBUG(AbstractPlatformTransactionManager.java:365)-

  44.Creatingnewtransactionwithname

  45. [user.mixlayer.MixLayerUserService.logon]:PROPAGATION_REQUIRED,ISOLATION_DEFAULT

  46.13:24:22,906DEBUG(DataSourceTransactionManager.java:205)-

  47.AcquiredConnection[org.apache.commons.dbcp.PoolableConnection@6e1cbf]

  48. forJDBCtransaction

  49.13:24:22,921DEBUG(DataSourceTransactionManager.java:222)-

  50.SwitchingJDBCConnection

  51. [org.apache.commons.dbcp.PoolableConnection@6e1cbf]tomanualcommit

  52.13:24:22,921DEBUG(JdbcTemplate.java:785)-

  53.ExecutingpreparedSQLupdate

  54.13:24:22,921DEBUG(JdbcTemplate.java:569)-

  55.ExecutingpreparedSQLstatement

  56. [UPDATEt_useruSETu.score=u.score ?WHEREuser_name=?]

  57.13:24:23,140DEBUG(JdbcTemplate.java:794)-

  58.SQLupdateaffected0rows

  59.13:24:23,140DEBUG(AbstractPlatformTransactionManager.java:752)-

  60.Initiatingtransactioncommit

  61.13:24:23,140DEBUG(DataSourceTransactionManager.java:265)-

  62.CommittingJDBCtransactiononConnection

  63. [org.apache.commons.dbcp.PoolableConnection@6e1cbf]

  64.13:24:23,140DEBUG(DataSourceTransactionManager.java:323)-

  65.ReleasingJDBCConnection[org.apache.commons.dbcp.PoolableConnection@6e1cbf]

  66. aftertransaction

  67.13:24:23,156DEBUG(DataSourceUtils.java:312)-

  68.ReturningJDBCConnectiontoDataSource

  日誌中粗體部分說明了MixLayerUserService#logon方法已經正確運行在事務上下文中.Spring框架本身不應該是複雜化代碼的理由,使用Spring的開發者應該是無拘無束的:從實際應用出發,去除掉那些所謂原則性的介面,去除掉強制分層的束縛,簡單才是硬道理.


[火星人 ] Spring事務管理高級應用難點剖析(2)已經有893次圍觀

http://coctec.com/docs/java/show-post-60404.html