亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

annuaire recherche
前言 簡介 概覽 使用場景 Spring 2.0和 2.5的新特性 簡介 控制反轉(zhuǎn)(IoC)容器 新的bean作用域 更簡單的XML配置 可擴(kuò)展的XML編寫 Annotation(注解)驅(qū)動配置 在classpath中自動搜索組件 面向切面編程(AOP) 更加簡單的AOP XML配置 對@AspectJ 切面的支持 對bean命名pointcut( bean name pointcut element)的支持 對AspectJ裝載時織入(AspectJ load-time weaving)的支持 中間層 在XML里更為簡單的聲明性事務(wù)配置 對Websphere 事務(wù)管理的完整支持 JPA 異步的JMS JDBC Web層 Spring MVC合理的默認(rèn)值 Portlet 框架 基于Annotation的控制器 Spring MVC的表單標(biāo)簽庫 對Tiles 2 支持 對JSF 1.2支持 JAX-WS支持 其他 動態(tài)語言支持 增強(qiáng)的測試支持 JMX 支持 將Spring 應(yīng)用程序上下文部署為JCA adapter 計劃任務(wù) 對Java 5 (Tiger) 支持 移植到Spring 2.5 改變 支持的JDK版本 Spring 2.5的Jar打包 XML配置 Deprecated(淘汰)的類和方法 Apache OJB iBATIS Hibernate JDO UrlFilenameViewController 更新的樣例應(yīng)用 改進(jìn)的文檔 核心技術(shù) IoC(控制反轉(zhuǎn))容器 簡介 基本原理 - 容器和bean 容器 配置元數(shù)據(jù) 實(shí)例化容器 XML配置元數(shù)據(jù)的結(jié)構(gòu) 多種bean bean的命名 bean的別名 實(shí)例化bean 用構(gòu)造器來實(shí)例化 使用靜態(tài)工廠方法實(shí)例化 使用實(shí)例工廠方法實(shí)例化 使用容器 依賴 注入依賴 構(gòu)造器注入 構(gòu)造器參數(shù)解析 構(gòu)造器參數(shù)類型匹配 構(gòu)造參數(shù)索引 Setter注入 一些例子 依賴配置詳解 直接變量(基本類型、Strings類型等。) idref元素 引用其它的bean(協(xié)作者) 內(nèi)部bean 集合 集合的合并 強(qiáng)類型集合(僅適用于Java5+) Nulls XML配置文件的簡寫及其他 XML-based configuration metadata shortcuts 使用p名稱空間配置屬性 組合屬性名稱 使用depends-on 延遲初始化bean 自動裝配(autowire)協(xié)作者 將bean排除在自動裝配之外 依賴檢查 方法注入 Lookup方法注入 自定義方法的替代方案 Bean的作用域 Singleton作用域 Prototype作用域 Singleton beans和prototype-bean的依賴 其他作用域 初始化web配置 Request作用域 Session作用域 global session作用域 作用域bean與依賴 選擇創(chuàng)建代理的類型 自定義作用域 創(chuàng)建自定義作用域 使用自定義作用域 定制bean特性 生命周期回調(diào) 初始化回調(diào) 析構(gòu)回調(diào) 缺省的初始化和析構(gòu)方法 組合生命周期機(jī)制 在非web應(yīng)用中優(yōu)雅地關(guān)閉Spring IoC容器 了解自己 BeanFactoryAware BeanNameAware bean定義的繼承 容器擴(kuò)展點(diǎn) 用BeanPostProcessor定制bean 使用BeanPostProcessor的Hello World示例 RequiredAnnotationBeanPostProcessor示例 用BeanFactoryPostProcessor定制配置元數(shù)據(jù) PropertyPlaceholderConfigurer示例 PropertyOverrideConfigurer示例 使用FactoryBean定制實(shí)例化邏輯 The ApplicationContext BeanFactory 還是 ApplicationContext? 利用MessageSource實(shí)現(xiàn)國際化 事件 底層資源的訪問 ApplicationContext在WEB應(yīng)用中的實(shí)例化 粘合代碼和可怕的singleton 以J2EE RAR文件的形式部署Spring ApplicationContext 基于注解(Annotation-based)的配置 @Autowired 基于注解的自動連接微調(diào) CustomAutowireConfigurer @Resource @PostConstruct 與 @PreDestroy 對受管組件的Classpath掃描 @Component和更多典型化注解 自動檢測組件 使用過濾器自定義掃描 自動檢測組件的命名 為自動檢測的組件提供一個作用域 用注解提供限定符元數(shù)據(jù) 注冊一個LoadTimeWeaver 資源 簡介 Resource接口 內(nèi)置 Resource 實(shí)現(xiàn) UrlResource ClassPathResource FileSystemResource ServletContextResource InputStreamResource ByteArrayResource ResourceLoader接口 ResourceLoaderAware 接口 把Resource作為屬性來配置 Application context 和Resource 路徑 構(gòu)造application context 創(chuàng)建 ClassPathXmlApplicationContext 實(shí)例 - 簡介 Application context構(gòu)造器中資源路徑的通配符 Ant風(fēng)格的pattern 潛在的可移植性 classpath*: 前綴 其他關(guān)于通配符的說明 FileSystemResource 說明 校驗(yàn),數(shù)據(jù)綁定,BeanWrapper,與屬性編輯器 簡介 使用Spring的Validator接口進(jìn)行校驗(yàn) 從錯誤代碼到錯誤信息 Bean處理和BeanWrapper 設(shè)置和獲取屬性值以及嵌套屬性 內(nèi)建的PropertyEditor實(shí)現(xiàn) 注冊用戶自定義的PropertyEditor 使用PropertyEditorRegistrars 使用Spring進(jìn)行面向切面編程(AOP) 簡介 AOP概念 Spring AOP的功能和目標(biāo) AOP代理 @AspectJ支持 啟用@AspectJ支持 聲明一個切面 聲明一個切入點(diǎn)(pointcut) 切入點(diǎn)指示符(PCD)的支持 組合切入點(diǎn)表達(dá)式 共享通用切入點(diǎn)定義 示例 聲明通知 前置通知 后置通知(After returning advice) 異常通知(After throwing advice) 最終通知(After (finally) advice) 環(huán)繞通知 通知參數(shù)(Advice parameters) 訪問當(dāng)前的連接點(diǎn) 傳遞參數(shù)給通知 確定參數(shù)名 處理參數(shù) 通知順序 引入(Introduction) 切面實(shí)例化模型 例子 基于Schema的AOP支持 聲明一個切面 聲明一個切入點(diǎn) 聲明通知 前置通知 后置通知 異常通知 最終通知 環(huán)繞通知 通知參數(shù) 通知順序 引入 切面實(shí)例化模型 Advisor 例子 AOP聲明風(fēng)格的選擇 Spring AOP還是完全用AspectJ? Spring AOP中使用@AspectJ還是XML? 混合切面類型 代理機(jī)制 理解AOP代理 以編程方式創(chuàng)建@AspectJ代理 在Spring應(yīng)用中使用AspectJ 在Spring中使用AspectJ進(jìn)行domain object的依賴注入 @Configurable對象的單元測試 Working with multiple application contexts Spring中其他的AspectJ切面 使用Spring IoC來配置AspectJ的切面 在Spring應(yīng)用中使用AspectJ加載時織入(LTW) 第一個例子 切面 'META-INF/aop.xml' 相關(guān)類庫(JARS) Spring配置 特定環(huán)境的配置 通用Java應(yīng)用 Tomcat WebLogic 更多資源 Spring AOP APIs 簡介 Spring中的切入點(diǎn)API 概念 切入點(diǎn)運(yùn)算 AspectJ切入點(diǎn)表達(dá)式 便利的切入點(diǎn)實(shí)現(xiàn) 靜態(tài)切入點(diǎn) 正則表達(dá)式切入點(diǎn) 屬性驅(qū)動的切入點(diǎn) 動態(tài)切入點(diǎn) 控制流切入點(diǎn) 切入點(diǎn)的超類 自定義切入點(diǎn) Spring的通知API 通知的生命周期 Spring里的通知類型 攔截環(huán)繞通知 前置通知 異常通知 后置通知 引入通知 Spring里的Advisor API 使用ProxyFactoryBean創(chuàng)建AOP代理 基礎(chǔ) JavaBean屬性 基于JDK和CGLIB的代理 對接口進(jìn)行代理 對類進(jìn)行代理 使用“全局”通知器 簡化代理定義 使用ProxyFactory通過編程創(chuàng)建AOP代理 操作被通知對象 使用“自動代理(autoproxy)”功能 自動代理bean定義 BeanNameAutoProxyCreator DefaultAdvisorAutoProxyCreator AbstractAdvisorAutoProxyCreator 使用元數(shù)據(jù)驅(qū)動的自動代理 使用TargetSource 熱交換目標(biāo)源 池化目標(biāo)源 原型目標(biāo)源 ThreadLocal目標(biāo)源 定義新的Advice類型 更多資源 測試 簡介 單元測試 Mock對象 JNDI Servlet API Portlet API 單元測試支持類 通用工具類 Spring MVC 集成測試 概覽 使用哪個支持框架 通用目標(biāo) 上下文管理及緩存 測試fixtures依賴注入 事務(wù)管理 集成測試支持類 JDBC測試支持 常用注解 JUnit 3.8遺留支持 上下文管理及緩存 測試fixture依賴注入 字段級別(Field Level)注入 事務(wù)管理 JUnit 3.8 遺留支持類 Java 5+ 專有支持 使用注解的事務(wù)相關(guān)測試 JPA支持類 Spring TestContext Framework 主要的抽象 上下文管理和緩存 測試fixture的依賴注入 事務(wù)管理 TestContext支持類 JUnit 3.8支持類 JUnit 4.4支持類 定制JUnit 4.4運(yùn)行器 TestNG支持類 TestContext框架注解支持 PetClinic示例 更多資源 中間層數(shù)據(jù)訪問 事務(wù)管理 簡介 動機(jī) 關(guān)鍵抽象 使用資源同步的事務(wù) 高層次方案 低層次方案 TransactionAwareDataSourceProxy 聲明式事務(wù)管理 理解Spring的聲明式事務(wù)管理實(shí)現(xiàn) 第一個例子 回滾 為不同的bean配置不同的事務(wù)語義 <tx:advice/> 有關(guān)的設(shè)置 使用 @Transactional @Transactional 有關(guān)的設(shè)置 事務(wù)傳播 required RequiresNew Nested 通知事務(wù)操作 結(jié)合AspectJ使用 @Transactional 編程式事務(wù)管理 使用TransactionTemplate 指定事務(wù)設(shè)置 使用PlatformTransactionManager 選擇編程式事務(wù)管理還是聲明式事務(wù)管理 與特定應(yīng)用服務(wù)器集成 IBM WebSphere BEA WebLogic Oracle OC4J 常見問題的解決方法 對一個特定的 DataSource 使用了錯誤的事務(wù)管理器 更多的資源 DAO支持 簡介 一致的異常層次 一致的DAO支持抽象類 使用JDBC進(jìn)行數(shù)據(jù)訪問 簡介 選擇一種工作模式 Spring JDBC包結(jié)構(gòu) 利用JDBC核心類控制JDBC的基本操作和錯誤處理 JdbcTemplate類 一些示例 查詢(SELECT) 更新(INSERT/UPDATE/DELETE) 其他操作 JdbcTemplate 的最佳實(shí)踐 NamedParameterJdbcTemplate類 SimpleJdbcTemplate類 DataSource接口 SQLExceptionTranslator接口 執(zhí)行SQL語句 執(zhí)行查詢 更新數(shù)據(jù)庫 獲取自動生成的主鍵 控制數(shù)據(jù)庫連接 DataSourceUtils類 SmartDataSource接口 AbstractDataSource類 SingleConnectionDataSource類 DriverManagerDataSource類 TransactionAwareDataSourceProxy類 DataSourceTransactionManager類 NativeJdbcExtractor JDBC批量操作 使用JdbcTemplate進(jìn)行批量操作 使用SimpleJdbcTemplate進(jìn)行批量操作 通過使用SimpleJdbc類簡化JDBC操作 使用SimpleJdbcInsert插入數(shù)據(jù) 使用SimpleJdbcInsert來獲取自動生成的主鍵 指定SimpleJdbcInsert所使用的字段 使用SqlParameterSource提供參數(shù)值 使用SimpleJdbcCall調(diào)用存儲過程 聲明SimpleJdbcCall使用的參數(shù) 如何定義SqlParameters 使用SimpleJdbcCall調(diào)用內(nèi)置函數(shù) 使用SimpleJdbcCall返回的ResultSet/REF Cursor 用Java對象來表達(dá)JDBC操作 SqlQuery類 MappingSqlQuery類 SqlUpdate類 StoredProcedure類 SqlFunction類 參數(shù)和數(shù)據(jù)處理的基本原則 為參數(shù)設(shè)置SQL類型信息 處理BLOB 和 CLOB對象 在IN語句中傳入一組參數(shù)值 處理復(fù)雜類型的存儲過程調(diào)用 使用ORM工具進(jìn)行數(shù)據(jù)訪問 簡介 Hibernate 資源管理 在Spring容器中創(chuàng)建 SessionFactory The HibernateTemplate 不使用回調(diào)的基于Spring的DAO實(shí)現(xiàn) 基于Hibernate3的原生API實(shí)現(xiàn)DAO 編程式的事務(wù)劃分 聲明式的事務(wù)劃分 事務(wù)管理策略 容器資源 vs 本地資源 在應(yīng)用服務(wù)器中使用Hibernate的注意事項 JDO 建立PersistenceManagerFactory JdoTemplate和JdoDaoSupport 基于原生的JDO API實(shí)現(xiàn)DAO 事務(wù)管理 JdoDialect Oracle TopLink SessionFactory 抽象層 TopLinkTemplate and TopLinkDaoSupport 基于原生的TopLink API的DAO實(shí)現(xiàn) 事務(wù)管理 iBATIS SQL Maps 創(chuàng)建SqlMapClient 使用 SqlMapClientTemplate 和 SqlMapClientDaoSupport 基于原生的iBATIS API的DAO實(shí)現(xiàn) JPA 在Spring環(huán)境中建立JPA LocalEntityManagerFactoryBean 從JNDI中獲取 EntityManagerFactory LocalContainerEntityManagerFactoryBean Tomcat(5.0以上)加載時的織入配置 使用VM代理的全局加載時織入 上下文范圍內(nèi)的加載時織入配置 處理多持久化單元 JpaTemplate 和 JpaDaoSupport 基于原生的JPA實(shí)現(xiàn)DAO 異常轉(zhuǎn)化 事務(wù)管理 JpaDialect The Web Web MVC framework Web框架 概述 與其他MVC實(shí)現(xiàn)框架的集成 Spring Web MVC框架的特點(diǎn) DispatcherServlet 控制器 AbstractController 和 WebContentGenerator 其它的簡單控制器 MultiActionController 命令控制器 處理器映射(handler mapping) BeanNameUrlHandlerMapping SimpleUrlHandlerMapping 攔截器(HandlerInterceptor) 視圖與視圖解析 視圖解析器(ViewResolver) 視圖解析鏈 重定向(Rediret)到另一個視圖 RedirectView redirect:前綴 forward:前綴 本地化解析器 AcceptHeaderLocaleResolver CookieLocaleResolver SessionLocaleResolver LocaleChangeInterceptor 使用主題 簡介 如何定義主題 主題解析器 Spring對分段文件上傳(multipart file upload)的支持 介紹 使用MultipartResolver 在表單中處理分段文件上傳 使用Spring的表單標(biāo)簽庫 配置 form標(biāo)簽 input標(biāo)簽 checkbox標(biāo)簽 checkboxes標(biāo)簽 radiobutton標(biāo)簽 radiobuttons標(biāo)簽 password標(biāo)簽 select標(biāo)簽 option標(biāo)簽 options標(biāo)簽 textarea標(biāo)簽 hidden標(biāo)簽 errors標(biāo)簽 處理異常 慣例優(yōu)先原則(convention over configuration) 對控制器的支持:ControllerClassNameHandlerMapping 對模型的支持:ModelMap(ModelAndView) 對視圖的支持:RequestToViewNameTranslator 基于注解的控制器配置 建立dispatcher實(shí)現(xiàn)注解支持 使用@Controller定義一個控制器 使用@RequestMapping映射請求 使用@RequestParam綁定請求參數(shù)到方法參數(shù) 使用@ModelAttribute提供一個從模型到數(shù)據(jù)的鏈接 使用@SessionAttributes指定存儲在會話中的屬性 自定義WebDataBinder初始化 使用@InitBinder自定義數(shù)據(jù)綁定 配置一個定制的WebBindingInitializer 更多資源 集成視圖技術(shù) 簡介 JSP和JSTL 視圖解析器 'Plain-old' JSPs versus JSTL 'Plain-old' JSP與JSTL 幫助簡化開發(fā)的額外的標(biāo)簽 Tiles 需要的資源 如何集成Tiles UrlBasedViewResolver類 ResourceBundleViewResolver類 SimpleSpringPreparerFactory 和 SpringBeanPreparerFactory Velocity和FreeMarker 需要的資源 Context 配置 創(chuàng)建模板 高級配置 velocity.properties FreeMarker 綁定支持和表單處理 用于綁定的宏 簡單綁定 表單輸入生成宏 輸入域 選擇輸入域 重載HTML轉(zhuǎn)碼行為并使你的標(biāo)簽符合XHTML XSLT 寫在段首 Bean 定義 標(biāo)準(zhǔn)MVC控制器代碼 把模型數(shù)據(jù)轉(zhuǎn)化為XML 定義視圖屬性 文檔轉(zhuǎn)換 小結(jié) 文檔視圖(PDF/Excel) 簡介 配置和安裝 文檔視圖定義 Controller 代碼 Excel視圖子類 PDF視圖子類 JasperReports 依賴的資源 配置 配置ViewResolver 配置View 關(guān)于報表文件 使用 JasperReportsMultiFormatView 構(gòu)造ModelAndView 使用子報表 配置子報表文件 配置子報表數(shù)據(jù)源 配置Exporter的參數(shù) 集成其它Web框架 簡介 通用配置 JavaServer Faces DelegatingVariableResolver FacesContextUtils Struts ContextLoaderPlugin DelegatingRequestProcessor DelegatingActionProxy ActionSupport Classes Tapestry 注入 Spring 托管的 beans 將 Spring Beans 注入到 Tapestry 頁面中 組件定義文件 添加抽象訪問方法 將 Spring Beans 注入到 Tapestry 頁面中 - Tapestry 4.0+ 風(fēng)格 WebWork 更多資源 Portlet MVC框架 介紹 控制器 - MVC中的C 視圖 - MVC中的V Web作用范圍的Bean DispatcherPortlet ViewRendererServlet 控制器 AbstractController 和 PortletContentGenerator 其它簡單的控制器 Command控制器 PortletWrappingController 處理器映射 PortletModeHandlerMapping ParameterHandlerMapping PortletModeParameterHandlerMapping 增加 HandlerInterceptors HandlerInterceptorAdapter ParameterMappingInterceptor 視圖和它們的解析 Multipart文件上傳支持 使用 PortletMultipartResolver 處理表單里的文件上傳 異常處理 Portlet應(yīng)用的部署 整合 使用Spring進(jìn)行遠(yuǎn)程訪問與Web服務(wù) 簡介 使用RMI暴露服務(wù) 使用RmiServiceExporter暴露服務(wù) 在客戶端鏈接服務(wù) 使用Hessian或者Burlap通過HTTP遠(yuǎn)程調(diào)用服務(wù) 為Hessian和co.配置DispatcherServlet 使用HessianServiceExporter暴露你的bean 在客戶端連接服務(wù) 使用Burlap 對通過Hessian或Burlap暴露的服務(wù)使用HTTP Basic認(rèn)證 使用HTTP調(diào)用器暴露服務(wù) Exposing the service object 在客戶端連接服務(wù) Web Services 使用JAX-RPC暴露基于servlet的web服務(wù) 使用JAX-RPC訪問web服務(wù) 注冊JAX-RPC Bean映射 注冊自己的JAX-RPC 處理器 使用JAX-WS暴露基于servlet的web服務(wù) 使用JAX-WS暴露單獨(dú)web服務(wù) 使用Spring支持的JAX-WS RI來暴露服務(wù) 使用JAX-WS訪問web服務(wù) 使用XFire來暴露Web服務(wù) JMS 服務(wù)端配置 客戶端配置 對遠(yuǎn)程接口不提供自動探測實(shí)現(xiàn) 在選擇這些技術(shù)時的一些考慮 Enterprise Java Beans (EJB) 集成 簡介 訪問EJB 概念 訪問本地的無狀態(tài)Session Bean(SLSB) 訪問遠(yuǎn)程SLSB Accessing EJB 2.x SLSBs versus EJB 3 SLSBs 使用Spring提供的輔助類實(shí)現(xiàn)EJB組件 EJB 2.x base classes EJB 3 注入攔截 JMS (Java Message Service) 簡介 使用Spring JMS JmsTemplate 連接工廠 目的地管理 消息偵聽容器 SimpleMessageListenerContainer DefaultMessageListenerContainer ServerSessionMessageListenerContainer 事務(wù)管理 發(fā)送消息 使用消息轉(zhuǎn)換器 SessionCallback 和 ProducerCallback 接收消息 同步接收 異步接收 - 消息驅(qū)動的POJO SessionAwareMessageListener接口 MessageListenerAdapter 事務(wù)中的消息處理 JCA消息端點(diǎn)的支持 JMS命名空間支持 JMX 介紹 將Bean暴露為JMX 創(chuàng)建MBeanServer 重用原有的MBeanServer 延遲初始化的MBean MBean的自動注冊 控制注冊行為 控制Bean的管理接口 MBeanInfoAssembler接口 使用源碼級元數(shù)據(jù) 使用JDK 5.0的注解 源代碼級的元數(shù)據(jù)類型 AutodetectCapableMBeanInfoAssembler接口 用Java接口定義管理接口 使用MethodNameBasedMBeanInfoAssembler 控制Bean的ObjectName 從Properties讀取Properties 使用MetadataNamingStrategy <context:mbean-export/>元素 JSR-160連接器 服務(wù)器端連接器 客戶端連接器 基于Burlap/Hessian/SOAP的JMX 通過代理訪問MBean 通知 為通知注冊監(jiān)聽器 發(fā)布通知 更多資源 JCA CCI 簡介 配置CCI 連接器配置 在Spring中配置ConnectionFactory 配置CCI連接 使用一個 CCI 單連接 使用Spring的 CCI訪問支持 記錄轉(zhuǎn)換 CciTemplate類 DAO支持 自動輸出記錄生成 總結(jié) 直接使用一個CCI Connection接口和Interaction接口 CciTemplate 使用示例 建模CCI訪問為操作對象 MappingRecordOperation MappingCommAreaOperation 自動生成輸出記錄 總結(jié) MappingRecordOperation 使用示例 MappingCommAreaOperation 使用示例 事務(wù) Spring郵件抽象層 簡介 使用Spring郵件抽象 MailSender 和 SimpleMailMessage 的基本用法 使用 JavaMailSender 和 MimeMessagePreparator 使用MimeMessageHelper 發(fā)送附件和嵌入式資源(inline resources) 附件 內(nèi)嵌資源 使用模板來創(chuàng)建郵件內(nèi)容 一個基于Velocity的示例 Spring中的定時調(diào)度(Scheduling)和線程池(Thread Pooling) 簡介 使用OpenSymphony Quartz 調(diào)度器 使用JobDetailBean 使用 MethodInvokingJobDetailFactoryBean 使用triggers和SchedulerFactoryBean來包裝任務(wù) 使用JDK Timer支持類 創(chuàng)建定制的timers 使用 MethodInvokingTimerTaskFactoryBean類 最后:使用TimerFactoryBean來設(shè)置任務(wù) SpringTaskExecutor抽象 TaskExecutor接口 TaskExecutor類型 使用TaskExecutor 動態(tài)語言支持 介紹 第一個示例 定義動態(tài)語言支持的bean 公共概念 <lang:language/> 元素 Refreshable bean 內(nèi)置動態(tài)語言源文件 理解dynamic-language-backed bean上下文中的構(gòu)造器注入 JRuby beans Groovy beans 通過回調(diào)定制Groovy對象 BeanShell beans 場景 Spring MVC控制器的腳本化 Validator的腳本化 Bits and bobs AOP - 通知腳本化bean 作用域 更多的資源 注解和源代碼級的元數(shù)據(jù)支持 簡介 Spring的元數(shù)據(jù)支持 注解 @Required Spring中的其它@Annotations Jakarta Commons Attributes集成 元數(shù)據(jù)和Spring AOP自動代理 基本原理 聲明式事務(wù)管理 示例程序 演示案例 介紹 使用動態(tài)語言實(shí)現(xiàn)的Spring MVC控制器 構(gòu)建與部署 使用SimpleJdbcTemplate和@Repository實(shí)現(xiàn)DAO 域?qū)ο?/a> Data Access Object 構(gòu)建 XML Schema-based configuration Introduction XML Schema-based configuration Referencing the schemas The util schema <util:constant/> Setting a bean property or constructor arg from a field value <util:property-path/> Using <util:property-path/> to set a bean property or constructor-argument <util:properties/> <util:list/> <util:map/> <util:set/> The jee schema <jee:jndi-lookup/> (simple) <jee:jndi-lookup/> (with single JNDI environment setting) <jee:jndi-lookup/> (with multiple JNDI environment settings) <jee:jndi-lookup/> (complex) <jee:local-slsb/> (simple) <jee:local-slsb/> (complex) <jee:remote-slsb/> The lang schema The jms schema The tx (transaction) schema The aop schema The context schema <property-placeholder/> <annotation-config/> <component-scan/> <load-time-weaver/> <spring-configured/> <mbean-export/> The tool schema The beans schema Setting up your IDE Setting up Eclipse Setting up IntelliJ IDEA Integration issues XML parsing errors in the Resin v.3 application server Extensible XML authoring Introduction Authoring the schema Coding a NamespaceHandler Coding a BeanDefinitionParser Registering the handler and the schema 'META-INF/spring.handlers' 'META-INF/spring.schemas' Using a custom extension in your Spring XML configuration Meatier examples Nesting custom tags within custom tags Custom attributes on 'normal' elements Further Resources spring-beans-2.0.dtd spring.tld Introduction The bind tag The escapeBody tag The hasBindErrors tag The htmlEscape tag The message tag The nestedPath tag The theme tag The transform tag spring-form.tld Introduction The checkbox tag The checkboxes tag The errors tag The form tag The hidden tag The input tag The label tag The option tag The options tag The password tag The radiobutton tag The radiobuttons tag The select tag The textarea tag Spring 2.5開發(fā)手冊中文化項目 聲明 致謝 參與人員 項目歷程
personnages

9.5.?聲明式事務(wù)管理

大多數(shù)Spring用戶選擇聲明式事務(wù)管理。這是對應(yīng)用代碼影響最小的選擇,因此也最符合 非侵入式 輕量級容器的理念。

Spring的聲明式事務(wù)管理是通過Spring AOP實(shí)現(xiàn)的,因?yàn)槭聞?wù)方面的代碼與Spring綁定并以一種樣板式風(fēng)格使用, 不過盡管如此,你一般并不需要理解AOP概念就可以有效地使用Spirng的聲明式事務(wù)管理。

從考慮EJB CMT和Spring聲明式事務(wù)管理的相似以及不同之處出發(fā)是很有益的。它們的基本方法是相似的: 都可以指定事務(wù)管理到單獨(dú)的方法;如果需要可以在事務(wù)上下文調(diào)用 setRollbackOnly() 方法。不同之處在于:

  • 不像EJB CMT綁定在JTA上,Spring聲明式事務(wù)管理可以在任何環(huán)境下使用。只需更改配置文件, 它就可以和JDBC、JDO、Hibernate或其他的事務(wù)機(jī)制一起工作。

  • Spring的聲明式事務(wù)管理可以被應(yīng)用到任何類(以及那個類的實(shí)例)上,不僅僅是像EJB那樣的特殊類。

  • Spring提供了聲明式的 回滾規(guī)則:EJB沒有對應(yīng)的特性,我們將在下面討論?;貪L可以聲明式的控制,不僅僅是編程式的。

  • Spring允許你通過AOP定制事務(wù)行為。例如,如果需要,你可以在事務(wù)回滾中插入定制的行為。 你也可以增加任意的通知,就象事務(wù)通知一樣。使用EJB CMT,除了使用setRollbackOnly(),你沒有辦法能夠影響容器的事務(wù)管理。

  • Spring不提供高端應(yīng)用服務(wù)器提供的跨越遠(yuǎn)程調(diào)用的事務(wù)上下文傳播。如果你需要這些特性,我們推薦你使用EJB。 然而,不要輕易使用這些特性。因?yàn)橥ǔN覀儾⒉幌M聞?wù)跨越遠(yuǎn)程調(diào)用。

回滾規(guī)則的概念比較重要:它使我們能夠指定什么樣的異常(和throwable)將導(dǎo)致自動回滾。 我們在配置文件中聲明式地指定,無須在Java代碼中。同時,我們?nèi)耘f可以通過調(diào)用 TransactionStatussetRollbackOnly() 方法編程式地回滾當(dāng)前事務(wù)。通常,我們定義一條規(guī)則, 聲明 MyApplicationException 必須總是導(dǎo)致事務(wù)回滾。 這種方式帶來了顯著的好處,它使你的業(yè)務(wù)對象不必依賴于事務(wù)設(shè)施。典型的例子是你不必在代碼中導(dǎo)入Spring API,事務(wù)等。

對EJB來說,默認(rèn)的行為是EJB容器在遇到 系統(tǒng)異常(通常指運(yùn)行時異常)時自動回滾當(dāng)前事務(wù)。 EJB CMT遇到 應(yīng)用異常(例如,除了 java.rmi.RemoteException 外別的checked exception)時并不會自動回滾。 默認(rèn)式Spring處理聲明式事務(wù)管理的規(guī)則遵守EJB習(xí)慣(只在遇到unchecked exceptions時自動回滾),但通常定制這條規(guī)則會更有用。

9.5.1.?理解Spring的聲明式事務(wù)管理實(shí)現(xiàn)

本節(jié)的目的是消除與使用聲明式事務(wù)管理有關(guān)的神秘性。簡單點(diǎn)兒總是好的,這份參考文檔只是告訴你給你的類加上@Transactional注解,在配置文件中添加('<tx:annotation-driven/>')行,然后期望你理解整個過程是怎么工作的。此節(jié)講述Spring的聲明式事務(wù)管理內(nèi)部的工作機(jī)制,以幫助你在面對事務(wù)相關(guān)的問題時不至于誤入迷途,回朔到上游平靜的水域。

在理解Spring的聲明式事務(wù)管理方面最重要的概念是:Spring的事務(wù)管理是通過AOP代理實(shí)現(xiàn)的。 其中的事務(wù)通知由元數(shù)據(jù)(目前基于XML或注解)驅(qū)動。 代理對象與事務(wù)元數(shù)據(jù)結(jié)合產(chǎn)生了一個AOP代理,它使用一個PlatformTransactionManager 實(shí)現(xiàn)品配合TransactionInterceptor,在方法調(diào)用前后實(shí)施事務(wù)。

注意

盡管使用Spring聲明式事務(wù)管理不需要AOP(尤其是Spring AOP)的知識,但了解這些是很有幫助的。你可以在 第?6?章 使用Spring進(jìn)行面向切面編程(AOP) 章找到關(guān)于Spring AOP的全部內(nèi)容。

概念上來說,在事務(wù)代理上調(diào)用方法的工作過程看起來像這樣:

9.5.2.?第一個例子

請看下面的接口和它的實(shí)現(xiàn)。這個例子的意圖是介紹概念,使用 FooBar 這樣的名字只是為了讓你關(guān)注于事務(wù)的用法,而不是領(lǐng)域模型。

// 我們想做成事務(wù)性的服務(wù)接口

package x.y.service;

public interface FooService {

  Foo getFoo(String fooName);

  Foo getFoo(String fooName, String barName);

  void insertFoo(Foo foo);

  void updateFoo(Foo foo);

}
// 上述接口的一個實(shí)現(xiàn)

package x.y.service;

public class DefaultFooService implements FooService {

  public Foo getFoo(String fooName) {
    throw new UnsupportedOperationException();
  }

  public Foo getFoo(String fooName, String barName) {
    throw new UnsupportedOperationException();
  }

  public void insertFoo(Foo foo) {
    throw new UnsupportedOperationException();
  }

  public void updateFoo(Foo foo) {
    throw new UnsupportedOperationException();
  }

}

(對該例的目的來說,上例中實(shí)現(xiàn)類(DefaultFooService)的每個方法在其方法體中拋出 UnsupportedOperationException 的做法是恰當(dāng)?shù)?,我們可以看到,事?wù)被創(chuàng)建出來, 響應(yīng) UnsupportedOperationException 的拋出,然后回滾。)

我們假定,FooService的前兩個方法(getFoo(String)getFoo(String, String))必須執(zhí)行在只讀事務(wù)上下文中,其他的方法(insertFoo(Foo)updateFoo(Foo))必須執(zhí)行在可讀寫事務(wù)上下文中。不要想著一次理解下面的配置,所有內(nèi)容都會在后面的章節(jié)詳細(xì)討論。

<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
  
  <!-- this is the service object that we want to make transactional -->
  <bean id="fooService" class="x.y.service.DefaultFooService"/>

  <!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
  <tx:advice id="txAdvice" transaction-manager="txManager">
  <!-- the transactional semantics... -->
  <tx:attributes>
    <!-- all methods starting with 'get' are read-only -->
    <tx:method name="get*" read-only="true"/>
    <!-- other methods use the default transaction settings (see below) -->
    <tx:method name="*"/>
  </tx:attributes>
  </tx:advice>
  
  <!-- ensure that the above transactional advice runs for any execution
    of an operation defined by the FooService interface -->
  <aop:config>
  <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
  </aop:config>
  
  <!-- don't forget the DataSource -->
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
  <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
  <property name="username" value="scott"/>
  <property name="password" value="tiger"/>
  </bean>

  <!-- similarly, don't forget the PlatformTransactionManager -->
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
  </bean>
  
  <!-- other <bean/> definitions here -->

</beans>

我們來分析一下上面的配置。我們要把一個服務(wù)對象('fooService' bean)做成事務(wù)性的。 我們想施加的事務(wù)語義封裝在<tx:advice/>定義中。<tx:advice/>把所有以 'get' 開頭的方法看做執(zhí)行在只讀事務(wù)上下文中, 其余的方法執(zhí)行在默認(rèn)語義的事務(wù)上下文中”。 其中的 'transaction-manager' 屬性被設(shè)置為一個指向 PlatformTransactionManager bean的名字(這里指 'txManager'), 該bean將會真正管理事務(wù)。

提示

事實(shí)上,如果 PlatformTransactionManager bean的名字是 'transactionManager' 的話,你的事務(wù)通知(<tx:advice/>)中的 'transaction-manager' 屬性可以忽略。否則你則需要像上例那樣明確指定。

配置中最后一段是 <aop:config/> 的定義, 它確保由 'txAdvice' bean定義的事務(wù)通知在應(yīng)用中合適的點(diǎn)被執(zhí)行。 首先我們定義了 一個切面,它匹配 FooService 接口定義的所有操作, 我們把該切面叫做 'fooServiceOperation'。然后我們用一個通知器(advisor)把這個切面與 'txAdvice' 綁定在一起, 表示當(dāng) 'fooServiceOperation' 執(zhí)行時,'txAdvice' 定義的通知邏輯將被執(zhí)行。

<aop:pointcut/> 元素定義是AspectJ的切面表示法,可參考Spring 2.0 第?6?章 使用Spring進(jìn)行面向切面編程(AOP) 章獲得更詳細(xì)的內(nèi)容。

一個普遍性的需求是讓整個服務(wù)層成為事務(wù)性的。滿足該需求的最好方式是讓切面表達(dá)式匹配服務(wù)層的所有操作方法。例如:

<aop:config>
  <aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/>
  </aop:config>

(這個例子中假定你所有的服務(wù)接口定義在 'x.y.service' 包中。你同樣可以參考 第?6?章 使用Spring進(jìn)行面向切面編程(AOP) 章獲得更詳細(xì)內(nèi)容。)

現(xiàn)在,既然我們已經(jīng)分析了整個配置,你可能會問了,“好吧,但是所有這些配置做了什么?”。

上面的配置將為'fooService' bean創(chuàng)建一個代理對象,這個代理對象被裝配了事務(wù)通知,所以當(dāng)它的相應(yīng)方法被調(diào)用時,一個事務(wù)將被啟動、掛起、被標(biāo)記為只讀,或者其它(根據(jù)該方法所配置的事務(wù)語義)。我們來看看下面的例子,測試一下上面的配置。

public final class Boot {

  public static void main(final String[] args) throws Exception {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml", Boot.class);
    FooService fooService = (FooService) ctx.getBean("fooService");
    fooService.insertFoo (new Foo());
  }
}

運(yùn)行上面程序的輸出結(jié)果看起來像這樣(注意為了清楚起見,Log4J的消息和從 DefaultFooServiceinsertFoo(..) 方法拋出的 UnsupportedOperationException 異常堆棧信息被省略了)。

				<!-- Spring容器開始啟動... -->
				
[AspectJInvocationContextExposingAdvisorAutoProxyCreator] - Creating implicit proxy
        for bean 'fooService' with 0 common interceptors and 1 specific interceptors
    <!-- the DefaultFooService is actually proxied -->
    
[JdkDynamicAopProxy] - Creating JDK dynamic proxy for [x.y.service.DefaultFooService]

    <!-- ... the insertFoo(..) method is now being invoked on the proxy -->
    

[TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo
    <!-- the transactional advice kicks in here... -->
    
[DataSourceTransactionManager] - Creating new transaction with name [x.y.service.FooService.insertFoo]
[DataSourceTransactionManager] - Acquired Connection
        [org.apache.commons.dbcp.PoolableConnection@a53de4] for JDBC transaction

    <!-- the insertFoo(..) method from DefaultFooService throws an exception... -->
    
[RuleBasedTransactionAttribute] - Applying rules to determine whether transaction should
        rollback on java.lang.UnsupportedOperationException
[TransactionInterceptor] - Invoking rollback for transaction on x.y.service.FooService.insertFoo
        due to throwable [java.lang.UnsupportedOperationException]

   <!-- and the transaction is rolled back (by default, RuntimeException instances cause rollback) -->
   
[DataSourceTransactionManager] - Rolling back JDBC transaction on Connection
        [org.apache.commons.dbcp.PoolableConnection@a53de4]
[DataSourceTransactionManager] - Releasing JDBC Connection after transaction
[DataSourceUtils] - Returning JDBC Connection to DataSource

Exception in thread "main" java.lang.UnsupportedOperationException
	at x.y.service.DefaultFooService.insertFoo(DefaultFooService.java:14)
   <!-- AOP infrastructure stack trace elements removed for clarity -->
   
	at $Proxy0.insertFoo(Unknown Source)
	at Boot.main(Boot.java:11)

9.5.3.?回滾

在前面的章節(jié)里,概述了如何在你的應(yīng)用中用聲明的風(fēng)格為類(特別是服務(wù)層的類)指定事務(wù)配置。 這一章將描述如何使用一個簡單的聲明式配置來控制事務(wù)的回滾。

我們推薦做法是在Spring框架的事務(wù)架構(gòu)里指出當(dāng)context的事務(wù)里的代碼拋出 Exception 時事務(wù)進(jìn)行回滾。Spring框架的事務(wù)基礎(chǔ)架構(gòu)代碼將從調(diào)用的堆棧里捕獲到任何未處理的 Exception,并將標(biāo)識事務(wù)將回滾。

然而,請注意Spring框架的事務(wù)基礎(chǔ)架構(gòu)代碼將默認(rèn)地 在拋出運(yùn)行時和unchecked exceptions時才標(biāo)識事務(wù)回滾。 也就是說,當(dāng)拋出一個 RuntimeException 或其子類例的實(shí)例時。(Errors 也一樣 - 默認(rèn)地 - 標(biāo)識事務(wù)回滾。)從事務(wù)方法中拋出的Checked exceptions將 被標(biāo)識進(jìn)行事務(wù)回滾。

可以配置哪些 Exception類型將被標(biāo)識進(jìn)行事務(wù)回滾。 下面的XML配置片斷里示范了如何配置一個用于回滾的checked、應(yīng)用程序特定的 Exception 類型。

<tx:advice id="txAdvice" transaction-manager="txManager">
  <tx:attributes>
  <tx:method name="get*" read-only="true" rollback-for="NoProductInStockException"/>
  <tx:method name="*"/>
  </tx:attributes>
</tx:advice>

有時候你想在異常拋出的時候回滾事務(wù),就可以使用“不回滾規(guī)則”。 在下面的例子中,我們告訴Spring 框架即使遇到?jīng)]有經(jīng)過處理的InstrumentNotFoundException異常,也不要回滾事務(wù)。

<tx:advice id="txAdvice">
  <tx:attributes>
  <tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
  <tx:method name="*"/>
  </tx:attributes>
</tx:advice>

當(dāng)Spring框架捕獲到一個異常后會檢查配置回滾規(guī)則來決定是不是要回滾事務(wù),這時候會遵循最匹配的規(guī)則。 所以在下面這種配置中,除了InstrumentNotFoundException這種類型的異常不會導(dǎo)致事務(wù)回滾以外,其他任何類型的異常都會。

<tx:advice id="txAdvice">
  <tx:attributes>
  <tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
  </tx:attributes>
</tx:advice>

第二種方法是通過 編程式 方式來指定回滾事務(wù)。 雖然寫法非常的簡單,但是這個方法是高侵入性的,并且使你的代碼與Spring框架的事務(wù)架構(gòu)高度耦合。 下面的代碼片斷里示范了Spring框架管理事務(wù)的編程式回滾:

public void resolvePosition() {
  try {
    // some business logic...
  } catch (NoProductInStockException ex) {
    // trigger rollback programmatically
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  }
}

強(qiáng)烈推薦你盡可能地使用聲明式事務(wù)回滾方法。 編程式方法的回滾對你來說是可見,如果你需要它你就可以使用,但是使用它就直接違反了在你的應(yīng)用中使用一個純基于POJO的模型。

9.5.4.?為不同的bean配置不同的事務(wù)語義

現(xiàn)在讓我們考慮一下這樣的場景,假設(shè)你有許多服務(wù)對象,你想為他們分別設(shè)置 完全不同 的事務(wù)語義。 在Spring中,你可以通過分別定義特定的 <aop:advisor/> 元素, 讓每個advisor采用不同的 'pointcut''advice-ref' 屬性,來達(dá)到目的。

讓我們假定你所有的服務(wù)層類定義在以 'x.y.service' 為根的包內(nèi)。 為了讓service包(或子包)下所有名字以 'Service' 結(jié)尾的類的對象擁有默認(rèn)的事務(wù)語義,你可以做如下的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

  <aop:config>

    <aop:pointcut id="serviceOperation"
          expression="execution(* x.y.service..*Service.*(..))"/>

    <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>

  </aop:config>

  <!-- these two beans will be transactional... -->
  <bean id="fooService" class="x.y.service.DefaultFooService"/>
  <bean id="barService" class="x.y.service.extras.SimpleBarService"/>

  <!-- ... and these two beans won't -->
  <bean id="anotherService" class="org.xyz.SomeService"/> <!-- (not in the right package) -->
  <bean id="barManager" class="x.y.service.SimpleBarManager"/> <!-- (doesn't end in 'Service') -->

  <tx:advice id="txAdvice">
    <tx:attributes>
      <tx:method name="get*" read-only="true"/>
      <tx:method name="*"/>
    </tx:attributes>
  </tx:advice>

  <!-- other transaction infrastructure beans such as a PlatformTransactionManager omitted... -->

</beans>

下面的配置示例演示了兩個擁有完全不同的事務(wù)配置的bean。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

  <aop:config>

    <aop:pointcut id="defaultServiceOperation"
          expression="execution(* x.y.service.*Service.*(..))"/>

    <aop:pointcut id="noTxServiceOperation"
          expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>

    <aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>

    <aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>

  </aop:config>

  <!-- this bean will be transactional (see the 'defaultServiceOperation' pointcut) -->
  <bean id="fooService" class="x.y.service.DefaultFooService"/>

  <!-- this bean will also be transactional, but with totally different transactional settings -->
  <bean id="anotherFooService" class="x.y.service.ddl.DefaultDdlManager"/>

  <tx:advice id="defaultTxAdvice">
    <tx:attributes>
      <tx:method name="get*" read-only="true"/>
      <tx:method name="*"/>
    </tx:attributes>
  </tx:advice>

  <tx:advice id="noTxAdvice">
    <tx:attributes>
      <tx:method name="*" propagation="NEVER"/>
    </tx:attributes>
  </tx:advice>

  <!-- other transaction infrastructure beans such as a PlatformTransactionManager omitted... -->

</beans>

9.5.5.?<tx:advice/> 有關(guān)的設(shè)置

這一節(jié)里將描述通過 <tx:advice/> 標(biāo)簽來指定不同的事務(wù)性設(shè)置。默認(rèn)的 <tx:advice/> 設(shè)置如下:

  • 事務(wù)傳播設(shè)置 是 REQUIRED

  • 隔離級別是DEFAULT

  • 事務(wù)是 讀/寫

  • 事務(wù)超時默認(rèn)是依賴于事務(wù)系統(tǒng)的,或者事務(wù)超時沒有被支持。

  • 任何 RuntimeException 將觸發(fā)事務(wù)回滾,但是任何 checked Exception 將不觸發(fā)事務(wù)回滾

這些默認(rèn)的設(shè)置當(dāng)然也是可以被改變的。 <tx:advice/><tx:attributes/> 標(biāo)簽里的 <tx:method/> 各種屬性設(shè)置總結(jié)如下:

表?9.1.?<tx:method/> 有關(guān)的設(shè)置

屬性 是否需要? 默認(rèn)值 描述
name ?

與事務(wù)屬性關(guān)聯(lián)的方法名。通配符(*)可以用來指定一批關(guān)聯(lián)到相同的事務(wù)屬性的方法。 如:'get*'、'handle*''on*Event'等等。

propagation REQUIRED 事務(wù)傳播行為
isolation DEFAULT 事務(wù)隔離級別
timeout -1 事務(wù)超時的時間(以秒為單位)
read-only false 事務(wù)是否只讀?
rollback-for ?

將被觸發(fā)進(jìn)行回滾的 Exception(s);以逗號分開。 如:'com.foo.MyBusinessException,ServletException'

no-rollback-for ?

被觸發(fā)進(jìn)行回滾的 Exception(s);以逗號分開。 如:'com.foo.MyBusinessException,ServletException'


在寫代碼的時候,不可能對事務(wù)的名字有個很清晰的認(rèn)識,這里的名字是指會在事務(wù)監(jiān)視器(比如WebLogic的事務(wù)管理器)或者日志輸出中顯示的名字, 對于聲明式的事務(wù)設(shè)置,事務(wù)名字總是包含完整包名的類名加上"."和方法名,比如 'com.foo.BusinessService.handlePayment'.

9.5.6.?使用 @Transactional

注意

@Transactional 注解及其支持類所提供的功能最低要求使用Java 5(Tiger)。

除了基于XML文件的聲明式事務(wù)配置外,你也可以采用基于注解式的事務(wù)配置方法。直接在Java源代碼中聲明事務(wù)語義的做法讓事務(wù)聲明和將受其影響的代碼距離更近了,而且一般來說不會有不恰當(dāng)?shù)鸟詈系娘L(fēng)險,因?yàn)?,使用事?wù)性的代碼幾乎總是被部署在事務(wù)環(huán)境中。

下面的例子很好地演示了 @Transactional 注解的易用性,隨后解釋其中的細(xì)節(jié)。先看看其中的類定義:

// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {

  Foo getFoo(String fooName);

  Foo getFoo(String fooName, String barName);

  void insertFoo(Foo foo);

  void updateFoo(Foo foo);
}

當(dāng)上述的POJO定義在Spring IoC容器里時,上述bean實(shí)例僅僅通過 行xml配置就可以使它具有事務(wù)性的。如下:

<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
  
  <!-- this is the service object that we want to make transactional -->
  <bean id="fooService" class="x.y.service.DefaultFooService"/>

  <!-- enable the configuration of transactional behavior based on annotations -->
  <tx:annotation-driven transaction-manager="txManager"/>

  <!-- a PlatformTransactionManager is still required -->
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <!-- (this dependency is defined somewhere else) -->
  <property name="dataSource" ref="dataSource"/>
  </bean>
  
  <!-- other <bean/> definitions here -->

</beans>

提示

實(shí)際上,如果你用 'transactionManager' 來定義 PlatformTransactionManager bean的名字的話,你就可以忽略 <tx:annotation-driven/> 標(biāo)簽里的 'transaction-manager' 屬性。 如果 PlatformTransactionManager bean你要通過其它名稱來注入的話,你必須用 'transaction-manager' 屬性來指定它,如上所示。

@Transactional 注解可以被應(yīng)用于接口定義和接口方法、類定義和類的 public 方法上。 然而,請注意只是使用 @Transactional 注解并不會啟用事務(wù)行為, 它僅僅 是一種元數(shù)據(jù),能夠被可以識別 @Transactional 注解和上述的配置適當(dāng)?shù)木哂惺聞?wù)行為的beans所使用。上面的例子中,其實(shí)正是 <tx:annotation-driven/>元素的出現(xiàn) 開啟 了事務(wù)行為。

Spring團(tuán)隊的建議是你只在具體的類上使用 @Transactional 注解, 而不要注解在接口上。你當(dāng)然可以在接口(或接口方法)上使用 @Transactional 注解, 但是這只有在你使用基于接口的代理時它才會生效。因?yàn)樽⒔馐?不能繼承 的, 這就意味著如果你正在使用基于類的代理時,事務(wù)的設(shè)置將不能被基于類的代理所識別,而且對象也不會被事務(wù)代理所包裝 (這是很糟糕的)。 因此,請接受Spring團(tuán)隊的建議,在具體的類(包括該類的方法)上使用 @Transactional 注解。

注意:在代理模式下(默認(rèn)的情況),只有從代理傳過來的‘外部’方法調(diào)用才會被攔截。 這就意味著‘自我調(diào)用’是不會觸發(fā)事務(wù)的,比如說,一個在目標(biāo)對象中調(diào)用目標(biāo)對象其他方法的方法是不會觸發(fā)一個事務(wù)的,即使這個方法被標(biāo)記為 @Transactional!

如果你期望‘自我調(diào)用’被事務(wù)覆蓋到,可以考慮使用AspectJ 模式(如下所示)。在這種情況下,一開始就沒有任何代理的存在; 為了把@Transactional的方法變成運(yùn)行時的行為,目標(biāo)類會被‘編織’起來(比如修改它的字節(jié)碼)。

表?9.2.?<tx:annotation-driven/> 設(shè)置

屬性 默認(rèn)值 描述
transaction-manager transactionManager

使用的事務(wù)管理器的名字。只有像在上面的例子那樣,事務(wù)管理器不是 transactionManager的情況下才需要。

mode proxy

默認(rèn)的模式“proxy”會用Spring的AOP框架來代理注解過的bean(就像在前面討論過的那樣, 下面代理的語義只對通過代理傳遞過來的方法調(diào)用起效)。 另一種可行的模式"aspectj"會使用Spring的AspectJ事務(wù)切面來編織類(通過修改目標(biāo)對象的字節(jié)碼應(yīng)用到任何方法調(diào)用上)。 AspectJ織入需要在classpath中有spring-aspects.jar這個文件,并且啟用裝載時織入 (或者編譯時織入)。 (關(guān)于如何設(shè)置裝載時編織的詳情請參見 第?6.8.4.5?節(jié) “Spring配置” )

proxy-target-class false

只對代理模式有效。決定為那些使用了@Transactional注解的類創(chuàng)建何種事務(wù)代理。 如果 "proxy-target-class" 屬性被設(shè)為 "true", 那么基于類的代理就會被創(chuàng)建。如果 "proxy-target-class"屬性被設(shè)為"false" 或者沒設(shè),那么基于接口的標(biāo)準(zhǔn)JDK代理就會被創(chuàng)建。(關(guān)于不同代理類型的解釋請參見 第?6.6?節(jié) “代理機(jī)制” )

order Ordered.LOWEST_PRECEDENCE

定義事務(wù)通知的順序會作用到使用@Transactional注解的bean上。 更多的關(guān)于AOP通知順序的定義可以在章節(jié)(參見 第?6.2.4.7?節(jié) “通知順序”)。 請注意如果不指定任何順序?qū)褯Q定權(quán)交給AOP子系統(tǒng)。


注意

<tx:annotation-driven/>元素上的"proxy-target-class" 屬性 控制了有什么類型的事務(wù)性代理會為使用@Transactional 來注解的類創(chuàng)建代理。 如果"proxy-target-class" 屬性被設(shè)為"true",那么基于類的代理就會被創(chuàng)建。 如果"proxy-target-class" 屬性被設(shè)為"false" 或者沒設(shè),那么會創(chuàng)建基于接口的標(biāo)準(zhǔn)JDK代理。(關(guān)于不同代理類型的解釋請參見 第?6.6?節(jié) “代理機(jī)制”)

在多數(shù)情形下,方法的事務(wù)設(shè)置將被優(yōu)先執(zhí)行。在下列情況下,例如: DefaultFooService 類在類的級別上被注解為只讀事務(wù),但是,這個類中的 updateFoo(Foo) 方法的 @Transactional 注解的事務(wù)設(shè)置將優(yōu)先于類級別注解的事務(wù)設(shè)置。

@Transactional(readOnly = true)
public class DefaultFooService implements FooService {

  public Foo getFoo(String fooName) {
    // do something
  }

    // these settings have precedence for this method
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void updateFoo(Foo foo) {
        // do something
        
    }
}

9.5.6.1.?@Transactional 有關(guān)的設(shè)置

@Transactional 注解是用來指定接口、類或方法必須擁有事務(wù)語義的元數(shù)據(jù)。 如:“當(dāng)一個方法開始調(diào)用時就開啟一個新的只讀事務(wù),并停止掉任何現(xiàn)存的事務(wù)”。 默認(rèn)的 @Transactional 設(shè)置如下:

  • 事務(wù)傳播設(shè)置是 PROPAGATION_REQUIRED

  • 事務(wù)隔離級別是 ISOLATION_DEFAULT

  • 事務(wù)是 讀/寫

  • 事務(wù)超時默認(rèn)是依賴于事務(wù)系統(tǒng)的,或者事務(wù)超時沒有被支持。

  • 任何 RuntimeException 將觸發(fā)事務(wù)回滾,但是任何 checked Exception 將不觸發(fā)事務(wù)回滾

這些默認(rèn)的設(shè)置當(dāng)然也是可以被改變的。 @Transactional 注解的各種屬性設(shè)置總結(jié)如下:

表?9.3.?@Transactional 注解的屬性

屬性 類型 描述
propagation 枚舉型:Propagation 可選的傳播性設(shè)置
isolation 枚舉型:Isolation 可選的隔離性級別(默認(rèn)值:ISOLATION_DEFAULT
readOnly 布爾型 讀寫型事務(wù) vs. 只讀型事務(wù)
timeout int型(以秒為單位) 事務(wù)超時
rollbackFor 一組 Class 類的實(shí)例,必須是Throwable 的子類 一組異常類,遇到時 必須 進(jìn)行回滾。默認(rèn)情況下checked exceptions不進(jìn)行回滾,僅unchecked exceptions(即RuntimeException的子類)才進(jìn)行事務(wù)回滾。
rollbackForClassname 一組 Class 類的名字,必須是Throwable的子類 一組異常類名,遇到時 必須 進(jìn)行回滾
noRollbackFor 一組 Class 類的實(shí)例,必須是Throwable 的子類 一組異常類,遇到時 必須不 回滾。
noRollbackForClassname 一組 Class 類的名字,必須是Throwable 的子類 一組異常類,遇到時 必須不 回滾


在寫代碼的時候,不可能對事務(wù)的名字有個很清晰的認(rèn)識,這里的名字是指會在事務(wù)監(jiān)視器(比如WebLogic的事務(wù)管理器)或者日志輸出中顯示的名字, 對于聲明式的事務(wù)設(shè)置,事務(wù)名字總是全限定名+"."+事務(wù)通知的類的方法名。比如BusinessService類的handlePayment(..)方法啟動了一個事務(wù),事務(wù)的名稱是:

com.foo.BusinessService.handlePayment

9.5.7.?事務(wù)傳播

請注意這部分的Spring參考文檔不是 事務(wù)傳播的介紹, 而是詳細(xì)介紹了在Spring中與事務(wù)傳播相關(guān)的一些語義。

在由Spring管理的事務(wù)中,請記住 物理邏輯 事務(wù)存在的差異, 以及傳播設(shè)置是如何影響到這些差異的。

9.5.7.1.?required

PROPAGATION_REQUIRED

當(dāng)事務(wù)傳播被設(shè)置PROPAGATION_REQUIRED的時候, 會為每一個被應(yīng)用到的方法創(chuàng)建一個邏輯事務(wù)作用域。 每一個這樣的邏輯事務(wù)作用域都可以自主地決定rollback-only狀態(tài),當(dāng)這樣的邏輯事務(wù)作用域被外部的一個邏輯事務(wù)作用域所包含的時候, 他們在邏輯上是獨(dú)立的。當(dāng)然了,對于正常的 PROPAGATION_REQUIRED設(shè)置來說,他會被映射到相同的物理事務(wù)上。 所以一個標(biāo)記有rollback-only的內(nèi)部邏輯事務(wù)作用域的確會影響到外部的邏輯事務(wù)作用域(就像你所預(yù)料的那樣)。

然而,當(dāng)內(nèi)部的事務(wù)作用域標(biāo)記為rollback-only,同時外部的事務(wù)作用域并沒有決定要回滾, 這樣的回滾是意料不到的(靜悄悄地由內(nèi)部事務(wù)作用域觸發(fā)的): 一個對應(yīng)的UnexpectedRollbackException 異常會在這個時候被拋出。這是 可以預(yù)料到的行為, 只有這樣,這個事務(wù)的調(diào)用者才不會被誤導(dǎo),在事務(wù)沒有提交的情況下誤以為事務(wù)已經(jīng)提交。所以如果內(nèi)部的事務(wù)(外部的調(diào)用者并不知情)標(biāo)記該事務(wù)為 rollback-only,而外部的調(diào)用者卻依舊在不知情的情況下提交后,它需要收到一個 UnexpectedRollbackException 異常來清楚的了解事務(wù)并沒有提交而是發(fā)生了回滾。

9.5.7.2.?RequiresNew

PROPAGATION_REQUIRES_NEW

PROPAGATION_REQUIRES_NEW,與之前相反,為每一個相關(guān)的事務(wù)作用域使用了一個完全 獨(dú)立的事務(wù)。在這種情況下,物理事務(wù)也將是不同的,因此外部事務(wù)可以不受內(nèi)部事務(wù)回滾狀態(tài)的影響?yīng)毩⑻峤换蛘呋貪L。

9.5.7.3.?Nested

PROPAGATION_NESTED 是一個完全不同的設(shè)置。它使用了一個單獨(dú)的物理事務(wù), 這個事務(wù)擁有多個可以回滾的保存點(diǎn)。這樣部分回滾允許內(nèi)部事務(wù)在它的作用域內(nèi)觸發(fā)一個回滾, 并且外部事務(wù)能夠不受影響的繼續(xù)。 這通常是對應(yīng)于JDBC的保存點(diǎn),所以只會在 JDBC 資源事務(wù)管理上起效 (具體請參見 Spring的DataSourceTransactionManager).

9.5.8.?通知事務(wù)操作

考慮一下這樣的情況,如果你希望 同時執(zhí)行事務(wù)性通知(advice)一些基本的剖析(profiling)通知。 那么,在<tx:annotation-driven/>環(huán)境中該怎么做?

我們調(diào)用 updateFoo(Foo) 方法時希望這樣:

  • 配置的剖析切面(profiling aspect)開始啟動,

  • 然后進(jìn)入事務(wù)通知(根據(jù)配置創(chuàng)建一個新事務(wù)或加入一個已經(jīng)存在的事務(wù)),

  • 然后執(zhí)行原始對象的方法,

  • 然后事務(wù)提交(我們假定這里一切正常),

  • 最后剖析切面報告整個事務(wù)方法執(zhí)行過程花了多少時間。

注意

這章不會專門講述AOP的所有細(xì)節(jié)(除了應(yīng)用于事務(wù)方面的之外)。 請參考 第?6?章 使用Spring進(jìn)行面向切面編程(AOP) 章節(jié)以獲得對各種AOP配置及其一般概念的詳細(xì)敘述。

這里有一份簡單的剖析切面(profiling aspect)的代碼。 (請注意,通知的順序是由 Ordered 接口來控制的。 要想了解更多細(xì)節(jié),請參考 第?6.2.4.7?節(jié) “通知順序” 節(jié)。)

package x.y;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
import org.springframework.core.Ordered;

public class SimpleProfiler implements Ordered {

  private int order;

  // allows us to control the ordering of advice
  public int getOrder() {
    return this.order;
  }

  public void setOrder(int order) {
    this.order = order;
  }

  // this method is the around advice
  public Object profile(ProceedingJoinPoint call) throws Throwable {
    Object returnValue;
    StopWatch clock = new StopWatch(getClass().getName());
    try {
      clock.start(call.toShortString());
      returnValue = call.proceed();
    } finally {
      clock.stop();
      System.out.println(clock.prettyPrint());
    }
    return returnValue;
  }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xsi:schemaLocation="
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

  <bean id="fooService" class="x.y.service.DefaultFooService"/>

  <!-- this is the aspect -->
  <bean id="profiler" class="x.y.SimpleProfiler">
    <!-- execute before the transactional advice (hence the lower order number) -->
    <property name="order" value="1"/>
  </bean>

  <tx:annotation-driven transaction-manager="txManager" order="200"/>

  <aop:config>
    <!-- this advice will execute around the transactional advice -->
    <aop:aspect id="profilingAspect" ref="profiler">
      <aop:pointcut id="serviceMethodWithReturnValue"
              expression="execution(!void x.y..*Service.*(..))"/>
      <aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>
    </aop:aspect>
  </aop:config>

  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
    <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
    <property name="username" value="scott"/>
    <property name="password" value="tiger"/>
  </bean>

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

</beans>

上面配置的結(jié)果將獲得到一個擁有剖析和事務(wù)方面的 按那樣的順序 應(yīng)用于它上面的 'fooService' bean。 許多附加的方面的配置將一起達(dá)到這樣的效果。

最后,下面的一些示例演示了使用純XML聲明的方法來達(dá)到上面一樣的設(shè)置效果。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xsi:schemaLocation="
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

  <bean id="fooService" class="x.y.service.DefaultFooService"/>

  <!-- the profiling advice -->
  <bean id="profiler" class="x.y.SimpleProfiler">
    <!-- execute before the transactional advice (hence the lower order number) -->
    <property name="order" value="1"/>
  </bean>

  <aop:config>

    <aop:pointcut id="entryPointMethod" expression="execution(* x.y..*Service.*(..))"/>

    <!-- will execute after the profiling advice (c.f. the order attribute) -->
    <aop:advisor
        advice-ref="txAdvice"
        pointcut-ref="entryPointMethod"
        order="2"/> <!-- order value is higher than the profiling aspect -->

    <aop:aspect id="profilingAspect" ref="profiler">
      <aop:pointcut id="serviceMethodWithReturnValue"
              expression="execution(!void x.y..*Service.*(..))"/>
      <aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>
    </aop:aspect>

  </aop:config>

  <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
      <tx:method name="get*" read-only="true"/>
      <tx:method name="*"/>
    </tx:attributes>
  </tx:advice>

  <!-- other <bean/> definitions such as a DataSource and a PlatformTransactionManager here -->

</beans>

上面配置的結(jié)果是創(chuàng)建了一個 'fooService' bean,剖析方面和事務(wù)方面被 依照順序 施加其上。如果我們希望剖析通知在目標(biāo)方法執(zhí)行之前 后于 事務(wù)通知執(zhí)行,而且在目標(biāo)方法執(zhí)行之后 先于 事務(wù)通知,我們可以簡單地交換兩個通知bean的order值。

如果配置中包含更多的方面,它們將以同樣的方式受到影響。

9.5.9.?結(jié)合AspectJ使用 @Transactional

通過AspectJ切面,你也可以在Spring容器之外使用Spring框架的 @Transactional 功能。要使用這項功能你必須先給相應(yīng)的類和方法加上 @Transactional注解,然后把 spring-aspects.jar 文件中定義的 org.springframework.transaction.aspectj.AnnotationTransactionAspect 切面連接進(jìn)(織入)你的應(yīng)用。同樣,該切面必須配置一個事務(wù)管理器。你當(dāng)然可以通過Spring框架容器來處理注入,但因?yàn)槲覀冞@里關(guān)注于在Spring容器之外運(yùn)行應(yīng)用,我們將向你展示如何通過手動書寫代碼來完成。

注意

在我們繼續(xù)之前,你可能需要好好讀一下前面的第?9.5.6?節(jié) “使用 @Transactional” 和 第?6?章 使用Spring進(jìn)行面向切面編程(AOP) 兩章。

// construct an appropriate transaction manager 
DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource());

// configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager); 

注意

使用此切面(aspect),你必須在 實(shí)現(xiàn) 類(和/或類里的方法)、而 不是 類的任何所實(shí)現(xiàn)的接口上面進(jìn)行注解。AspectJ遵循Java的接口上的注解 不被繼承 的規(guī)則。

定義在類上的 @Transactional 注解指定了類中所有方法執(zhí)行時的默認(rèn)事務(wù)語義。

定義在類的方法上的 @Transactional 注解將覆蓋掉類上注解的所指定的默認(rèn)事務(wù)語義(如過存在的話)。 所有的方法都可以注解,不管它的可見度是什么樣的。

要把 AnnotationTransactionAspect 織入你的應(yīng)用,你或者基于AspectJ構(gòu)建你的應(yīng)用(參考 AspectJ Development Guide),或者采取“載入時織入”(load-time weaving),參考 第?6.8.4?節(jié) “在Spring應(yīng)用中使用AspectJ加載時織入(LTW)” 獲得關(guān)于使用AspectJ進(jìn)行“載入時織入”的討論。

Article précédent: Article suivant: