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

?? ??? ??
前言 簡(jiǎn)介 概覽 使用場(chǎng)景 Spring 2.0和 2.5的新特性 簡(jiǎn)介 控制反轉(zhuǎn)(IoC)容器 新的bean作用域 更簡(jiǎn)單的XML配置 可擴(kuò)展的XML編寫 Annotation(注解)驅(qū)動(dòng)配置 在classpath中自動(dòng)搜索組件 面向切面編程(AOP) 更加簡(jiǎn)單的AOP XML配置 對(duì)@AspectJ 切面的支持 對(duì)bean命名pointcut( bean name pointcut element)的支持 對(duì)AspectJ裝載時(shí)織入(AspectJ load-time weaving)的支持 中間層 在XML里更為簡(jiǎn)單的聲明性事務(wù)配置 對(duì)Websphere 事務(wù)管理的完整支持 JPA 異步的JMS JDBC Web層 Spring MVC合理的默認(rèn)值 Portlet 框架 基于Annotation的控制器 Spring MVC的表單標(biāo)簽庫(kù) 對(duì)Tiles 2 支持 對(duì)JSF 1.2支持 JAX-WS支持 其他 動(dòng)態(tài)語(yǔ)言支持 增強(qiáng)的測(cè)試支持 JMX 支持 將Spring 應(yīng)用程序上下文部署為JCA adapter 計(jì)劃任務(wù) 對(duì)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))容器 簡(jiǎn)介 基本原理 - 容器和bean 容器 配置元數(shù)據(jù) 實(shí)例化容器 XML配置元數(shù)據(jù)的結(jié)構(gòu) 多種bean bean的命名 bean的別名 實(shí)例化bean 用構(gòu)造器來(lái)實(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配置文件的簡(jiǎn)寫及其他 XML-based configuration metadata shortcuts 使用p名稱空間配置屬性 組合屬性名稱 使用depends-on 延遲初始化bean 自動(dòng)裝配(autowire)協(xié)作者 將bean排除在自動(dòng)裝配之外 依賴檢查 方法注入 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)國(guó)際化 事件 底層資源的訪問(wèn) ApplicationContext在WEB應(yīng)用中的實(shí)例化 粘合代碼和可怕的singleton 以J2EE RAR文件的形式部署Spring ApplicationContext 基于注解(Annotation-based)的配置 @Autowired 基于注解的自動(dòng)連接微調(diào) CustomAutowireConfigurer @Resource @PostConstruct 與 @PreDestroy 對(duì)受管組件的Classpath掃描 @Component和更多典型化注解 自動(dòng)檢測(cè)組件 使用過(guò)濾器自定義掃描 自動(dòng)檢測(cè)組件的命名 為自動(dòng)檢測(cè)的組件提供一個(gè)作用域 用注解提供限定符元數(shù)據(jù) 注冊(cè)一個(gè)LoadTimeWeaver 資源 簡(jiǎn)介 Resource接口 內(nèi)置 Resource 實(shí)現(xiàn) UrlResource ClassPathResource FileSystemResource ServletContextResource InputStreamResource ByteArrayResource ResourceLoader接口 ResourceLoaderAware 接口 把Resource作為屬性來(lái)配置 Application context 和Resource 路徑 構(gòu)造application context 創(chuàng)建 ClassPathXmlApplicationContext 實(shí)例 - 簡(jiǎn)介 Application context構(gòu)造器中資源路徑的通配符 Ant風(fēng)格的pattern 潛在的可移植性 classpath*: 前綴 其他關(guān)于通配符的說(shuō)明 FileSystemResource 說(shuō)明 校驗(yàn),數(shù)據(jù)綁定,BeanWrapper,與屬性編輯器 簡(jiǎn)介 使用Spring的Validator接口進(jìn)行校驗(yàn) 從錯(cuò)誤代碼到錯(cuò)誤信息 Bean處理和BeanWrapper 設(shè)置和獲取屬性值以及嵌套屬性 內(nèi)建的PropertyEditor實(shí)現(xiàn) 注冊(cè)用戶自定義的PropertyEditor 使用PropertyEditorRegistrars 使用Spring進(jìn)行面向切面編程(AOP) 簡(jiǎn)介 AOP概念 Spring AOP的功能和目標(biāo) AOP代理 @AspectJ支持 啟用@AspectJ支持 聲明一個(gè)切面 聲明一個(gè)切入點(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) 訪問(wèn)當(dāng)前的連接點(diǎn) 傳遞參數(shù)給通知 確定參數(shù)名 處理參數(shù) 通知順序 引入(Introduction) 切面實(shí)例化模型 例子 基于Schema的AOP支持 聲明一個(gè)切面 聲明一個(gè)切入點(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對(duì)象的單元測(cè)試 Working with multiple application contexts Spring中其他的AspectJ切面 使用Spring IoC來(lái)配置AspectJ的切面 在Spring應(yīng)用中使用AspectJ加載時(shí)織入(LTW) 第一個(gè)例子 切面 'META-INF/aop.xml' 相關(guān)類庫(kù)(JARS) Spring配置 特定環(huán)境的配置 通用Java應(yīng)用 Tomcat WebLogic 更多資源 Spring AOP APIs 簡(jiǎn)介 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ū)動(dòng)的切入點(diǎn) 動(dòng)態(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的代理 對(duì)接口進(jìn)行代理 對(duì)類進(jìn)行代理 使用“全局”通知器 簡(jiǎn)化代理定義 使用ProxyFactory通過(guò)編程創(chuàng)建AOP代理 操作被通知對(duì)象 使用“自動(dòng)代理(autoproxy)”功能 自動(dòng)代理bean定義 BeanNameAutoProxyCreator DefaultAdvisorAutoProxyCreator AbstractAdvisorAutoProxyCreator 使用元數(shù)據(jù)驅(qū)動(dòng)的自動(dòng)代理 使用TargetSource 熱交換目標(biāo)源 池化目標(biāo)源 原型目標(biāo)源 ThreadLocal目標(biāo)源 定義新的Advice類型 更多資源 測(cè)試 簡(jiǎn)介 單元測(cè)試 Mock對(duì)象 JNDI Servlet API Portlet API 單元測(cè)試支持類 通用工具類 Spring MVC 集成測(cè)試 概覽 使用哪個(gè)支持框架 通用目標(biāo) 上下文管理及緩存 測(cè)試fixtures依賴注入 事務(wù)管理 集成測(cè)試支持類 JDBC測(cè)試支持 常用注解 JUnit 3.8遺留支持 上下文管理及緩存 測(cè)試fixture依賴注入 字段級(jí)別(Field Level)注入 事務(wù)管理 JUnit 3.8 遺留支持類 Java 5+ 專有支持 使用注解的事務(wù)相關(guān)測(cè)試 JPA支持類 Spring TestContext Framework 主要的抽象 上下文管理和緩存 測(cè)試fixture的依賴注入 事務(wù)管理 TestContext支持類 JUnit 3.8支持類 JUnit 4.4支持類 定制JUnit 4.4運(yùn)行器 TestNG支持類 TestContext框架注解支持 PetClinic示例 更多資源 中間層數(shù)據(jù)訪問(wèn) 事務(wù)管理 簡(jiǎn)介 動(dòng)機(jī) 關(guān)鍵抽象 使用資源同步的事務(wù) 高層次方案 低層次方案 TransactionAwareDataSourceProxy 聲明式事務(wù)管理 理解Spring的聲明式事務(wù)管理實(shí)現(xiàn) 第一個(gè)例子 回滾 為不同的bean配置不同的事務(wù)語(yǔ)義 <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 常見(jiàn)問(wèn)題的解決方法 對(duì)一個(gè)特定的 DataSource 使用了錯(cuò)誤的事務(wù)管理器 更多的資源 DAO支持 簡(jiǎn)介 一致的異常層次 一致的DAO支持抽象類 使用JDBC進(jìn)行數(shù)據(jù)訪問(wèn) 簡(jiǎn)介 選擇一種工作模式 Spring JDBC包結(jié)構(gòu) 利用JDBC核心類控制JDBC的基本操作和錯(cuò)誤處理 JdbcTemplate類 一些示例 查詢(SELECT) 更新(INSERT/UPDATE/DELETE) 其他操作 JdbcTemplate 的最佳實(shí)踐 NamedParameterJdbcTemplate類 SimpleJdbcTemplate類 DataSource接口 SQLExceptionTranslator接口 執(zhí)行SQL語(yǔ)句 執(zhí)行查詢 更新數(shù)據(jù)庫(kù) 獲取自動(dòng)生成的主鍵 控制數(shù)據(jù)庫(kù)連接 DataSourceUtils類 SmartDataSource接口 AbstractDataSource類 SingleConnectionDataSource類 DriverManagerDataSource類 TransactionAwareDataSourceProxy類 DataSourceTransactionManager類 NativeJdbcExtractor JDBC批量操作 使用JdbcTemplate進(jìn)行批量操作 使用SimpleJdbcTemplate進(jìn)行批量操作 通過(guò)使用SimpleJdbc類簡(jiǎn)化JDBC操作 使用SimpleJdbcInsert插入數(shù)據(jù) 使用SimpleJdbcInsert來(lái)獲取自動(dòng)生成的主鍵 指定SimpleJdbcInsert所使用的字段 使用SqlParameterSource提供參數(shù)值 使用SimpleJdbcCall調(diào)用存儲(chǔ)過(guò)程 聲明SimpleJdbcCall使用的參數(shù) 如何定義SqlParameters 使用SimpleJdbcCall調(diào)用內(nèi)置函數(shù) 使用SimpleJdbcCall返回的ResultSet/REF Cursor 用Java對(duì)象來(lái)表達(dá)JDBC操作 SqlQuery類 MappingSqlQuery類 SqlUpdate類 StoredProcedure類 SqlFunction類 參數(shù)和數(shù)據(jù)處理的基本原則 為參數(shù)設(shè)置SQL類型信息 處理BLOB 和 CLOB對(duì)象 在IN語(yǔ)句中傳入一組參數(shù)值 處理復(fù)雜類型的存儲(chǔ)過(guò)程調(diào)用 使用ORM工具進(jìn)行數(shù)據(jù)訪問(wèn) 簡(jiǎn)介 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的注意事項(xiàng) 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以上)加載時(shí)的織入配置 使用VM代理的全局加載時(shí)織入 上下文范圍內(nèi)的加載時(shí)織入配置 處理多持久化單元 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 其它的簡(jiǎn)單控制器 MultiActionController 命令控制器 處理器映射(handler mapping) BeanNameUrlHandlerMapping SimpleUrlHandlerMapping 攔截器(HandlerInterceptor) 視圖與視圖解析 視圖解析器(ViewResolver) 視圖解析鏈 重定向(Rediret)到另一個(gè)視圖 RedirectView redirect:前綴 forward:前綴 本地化解析器 AcceptHeaderLocaleResolver CookieLocaleResolver SessionLocaleResolver LocaleChangeInterceptor 使用主題 簡(jiǎn)介 如何定義主題 主題解析器 Spring對(duì)分段文件上傳(multipart file upload)的支持 介紹 使用MultipartResolver 在表單中處理分段文件上傳 使用Spring的表單標(biāo)簽庫(kù) 配置 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) 對(duì)控制器的支持:ControllerClassNameHandlerMapping 對(duì)模型的支持:ModelMap(ModelAndView) 對(duì)視圖的支持:RequestToViewNameTranslator 基于注解的控制器配置 建立dispatcher實(shí)現(xiàn)注解支持 使用@Controller定義一個(gè)控制器 使用@RequestMapping映射請(qǐng)求 使用@RequestParam綁定請(qǐng)求參數(shù)到方法參數(shù) 使用@ModelAttribute提供一個(gè)從模型到數(shù)據(jù)的鏈接 使用@SessionAttributes指定存儲(chǔ)在會(huì)話中的屬性 自定義WebDataBinder初始化 使用@InitBinder自定義數(shù)據(jù)綁定 配置一個(gè)定制的WebBindingInitializer 更多資源 集成視圖技術(shù) 簡(jiǎn)介 JSP和JSTL 視圖解析器 'Plain-old' JSPs versus JSTL 'Plain-old' JSP與JSTL 幫助簡(jiǎn)化開(kāi)發(fā)的額外的標(biāo)簽 Tiles 需要的資源 如何集成Tiles UrlBasedViewResolver類 ResourceBundleViewResolver類 SimpleSpringPreparerFactory 和 SpringBeanPreparerFactory Velocity和FreeMarker 需要的資源 Context 配置 創(chuàng)建模板 高級(jí)配置 velocity.properties FreeMarker 綁定支持和表單處理 用于綁定的宏 簡(jiǎn)單綁定 表單輸入生成宏 輸入域 選擇輸入域 重載HTML轉(zhuǎn)碼行為并使你的標(biāo)簽符合XHTML XSLT 寫在段首 Bean 定義 標(biāo)準(zhǔn)MVC控制器代碼 把模型數(shù)據(jù)轉(zhuǎn)化為XML 定義視圖屬性 文檔轉(zhuǎn)換 小結(jié) 文檔視圖(PDF/Excel) 簡(jiǎn)介 配置和安裝 文檔視圖定義 Controller 代碼 Excel視圖子類 PDF視圖子類 JasperReports 依賴的資源 配置 配置ViewResolver 配置View 關(guān)于報(bào)表文件 使用 JasperReportsMultiFormatView 構(gòu)造ModelAndView 使用子報(bào)表 配置子報(bào)表文件 配置子報(bào)表數(shù)據(jù)源 配置Exporter的參數(shù) 集成其它Web框架 簡(jiǎn)介 通用配置 JavaServer Faces DelegatingVariableResolver FacesContextUtils Struts ContextLoaderPlugin DelegatingRequestProcessor DelegatingActionProxy ActionSupport Classes Tapestry 注入 Spring 托管的 beans 將 Spring Beans 注入到 Tapestry 頁(yè)面中 組件定義文件 添加抽象訪問(wèn)方法 將 Spring Beans 注入到 Tapestry 頁(yè)面中 - Tapestry 4.0+ 風(fēng)格 WebWork 更多資源 Portlet MVC框架 介紹 控制器 - MVC中的C 視圖 - MVC中的V Web作用范圍的Bean DispatcherPortlet ViewRendererServlet 控制器 AbstractController 和 PortletContentGenerator 其它簡(jiǎn)單的控制器 Command控制器 PortletWrappingController 處理器映射 PortletModeHandlerMapping ParameterHandlerMapping PortletModeParameterHandlerMapping 增加 HandlerInterceptors HandlerInterceptorAdapter ParameterMappingInterceptor 視圖和它們的解析 Multipart文件上傳支持 使用 PortletMultipartResolver 處理表單里的文件上傳 異常處理 Portlet應(yīng)用的部署 整合 使用Spring進(jìn)行遠(yuǎn)程訪問(wèn)與Web服務(wù) 簡(jiǎn)介 使用RMI暴露服務(wù) 使用RmiServiceExporter暴露服務(wù) 在客戶端鏈接服務(wù) 使用Hessian或者Burlap通過(guò)HTTP遠(yuǎn)程調(diào)用服務(wù) 為Hessian和co.配置DispatcherServlet 使用HessianServiceExporter暴露你的bean 在客戶端連接服務(wù) 使用Burlap 對(duì)通過(guò)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訪問(wèn)web服務(wù) 注冊(cè)JAX-RPC Bean映射 注冊(cè)自己的JAX-RPC 處理器 使用JAX-WS暴露基于servlet的web服務(wù) 使用JAX-WS暴露單獨(dú)web服務(wù) 使用Spring支持的JAX-WS RI來(lái)暴露服務(wù) 使用JAX-WS訪問(wèn)web服務(wù) 使用XFire來(lái)暴露Web服務(wù) JMS 服務(wù)端配置 客戶端配置 對(duì)遠(yuǎn)程接口不提供自動(dòng)探測(cè)實(shí)現(xiàn) 在選擇這些技術(shù)時(shí)的一些考慮 Enterprise Java Beans (EJB) 集成 簡(jiǎn)介 訪問(wèn)EJB 概念 訪問(wèn)本地的無(wú)狀態(tài)Session Bean(SLSB) 訪問(wèn)遠(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) 簡(jiǎn)介 使用Spring JMS JmsTemplate 連接工廠 目的地管理 消息偵聽(tīng)容器 SimpleMessageListenerContainer DefaultMessageListenerContainer ServerSessionMessageListenerContainer 事務(wù)管理 發(fā)送消息 使用消息轉(zhuǎn)換器 SessionCallback 和 ProducerCallback 接收消息 同步接收 異步接收 - 消息驅(qū)動(dòng)的POJO SessionAwareMessageListener接口 MessageListenerAdapter 事務(wù)中的消息處理 JCA消息端點(diǎn)的支持 JMS命名空間支持 JMX 介紹 將Bean暴露為JMX 創(chuàng)建MBeanServer 重用原有的MBeanServer 延遲初始化的MBean MBean的自動(dòng)注冊(cè) 控制注冊(cè)行為 控制Bean的管理接口 MBeanInfoAssembler接口 使用源碼級(jí)元數(shù)據(jù) 使用JDK 5.0的注解 源代碼級(jí)的元數(shù)據(jù)類型 AutodetectCapableMBeanInfoAssembler接口 用Java接口定義管理接口 使用MethodNameBasedMBeanInfoAssembler 控制Bean的ObjectName 從Properties讀取Properties 使用MetadataNamingStrategy <context:mbean-export/>元素 JSR-160連接器 服務(wù)器端連接器 客戶端連接器 基于Burlap/Hessian/SOAP的JMX 通過(guò)代理訪問(wèn)MBean 通知 為通知注冊(cè)監(jiān)聽(tīng)器 發(fā)布通知 更多資源 JCA CCI 簡(jiǎn)介 配置CCI 連接器配置 在Spring中配置ConnectionFactory 配置CCI連接 使用一個(gè) CCI 單連接 使用Spring的 CCI訪問(wèn)支持 記錄轉(zhuǎn)換 CciTemplate類 DAO支持 自動(dòng)輸出記錄生成 總結(jié) 直接使用一個(gè)CCI Connection接口和Interaction接口 CciTemplate 使用示例 建模CCI訪問(wèn)為操作對(duì)象 MappingRecordOperation MappingCommAreaOperation 自動(dòng)生成輸出記錄 總結(jié) MappingRecordOperation 使用示例 MappingCommAreaOperation 使用示例 事務(wù) Spring郵件抽象層 簡(jiǎn)介 使用Spring郵件抽象 MailSender 和 SimpleMailMessage 的基本用法 使用 JavaMailSender 和 MimeMessagePreparator 使用MimeMessageHelper 發(fā)送附件和嵌入式資源(inline resources) 附件 內(nèi)嵌資源 使用模板來(lái)創(chuàng)建郵件內(nèi)容 一個(gè)基于Velocity的示例 Spring中的定時(shí)調(diào)度(Scheduling)和線程池(Thread Pooling) 簡(jiǎn)介 使用OpenSymphony Quartz 調(diào)度器 使用JobDetailBean 使用 MethodInvokingJobDetailFactoryBean 使用triggers和SchedulerFactoryBean來(lái)包裝任務(wù) 使用JDK Timer支持類 創(chuàng)建定制的timers 使用 MethodInvokingTimerTaskFactoryBean類 最后:使用TimerFactoryBean來(lái)設(shè)置任務(wù) SpringTaskExecutor抽象 TaskExecutor接口 TaskExecutor類型 使用TaskExecutor 動(dòng)態(tài)語(yǔ)言支持 介紹 第一個(gè)示例 定義動(dòng)態(tài)語(yǔ)言支持的bean 公共概念 <lang:language/> 元素 Refreshable bean 內(nèi)置動(dòng)態(tài)語(yǔ)言源文件 理解dynamic-language-backed bean上下文中的構(gòu)造器注入 JRuby beans Groovy beans 通過(guò)回調(diào)定制Groovy對(duì)象 BeanShell beans 場(chǎng)景 Spring MVC控制器的腳本化 Validator的腳本化 Bits and bobs AOP - 通知腳本化bean 作用域 更多的資源 注解和源代碼級(jí)的元數(shù)據(jù)支持 簡(jiǎn)介 Spring的元數(shù)據(jù)支持 注解 @Required Spring中的其它@Annotations Jakarta Commons Attributes集成 元數(shù)據(jù)和Spring AOP自動(dòng)代理 基本原理 聲明式事務(wù)管理 示例程序 演示案例 介紹 使用動(dòng)態(tài)語(yǔ)言實(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開(kāi)發(fā)手冊(cè)中文化項(xiàng)目 聲明 致謝 參與人員 項(xiàng)目歷程
??

6.3.?基于Schema的AOP支持

  

如果你無(wú)法使用Java 5,或者你比較喜歡使用XML格式,Spring2.0也提供了使用新的"aop"命名空間來(lái)定義一個(gè)切面。 和使用@AspectJ風(fēng)格完全一樣,切入點(diǎn)表達(dá)式和通知類型同樣得到了支持,因此在這一節(jié)中我們將著重介紹新的 語(yǔ)法并回顧前一節(jié)(第?6.2?節(jié) “@AspectJ支持”)對(duì)編寫一個(gè)切入點(diǎn)表達(dá)式和綁定通知參數(shù)的討論。

  

使用本章所介紹的aop命名空間標(biāo)簽,你需要引入附錄?A, XML Schema-based configuration 中提及的spring-aop schema。 參見(jiàn)第?A.2.7?節(jié) “The aop schema”了解如何在aop命名空間中引入標(biāo)簽。

  

在Spring的配置文件中,所有的切面和通知都必須定義在<aop:config>元素內(nèi)部。 (一個(gè)application context可以包含多個(gè) <aop:config>)。 一個(gè)<aop:config>可以包含pointcut,advisor和aspect元素 (注意這三個(gè)元素必須按照這個(gè)順序進(jìn)行聲明)。

警告

<aop:config>風(fēng)格的配置使得Spring auto-proxying機(jī)制的使用變得很笨重。如果你已經(jīng)通過(guò) BeanNameAutoProxyCreator或類似的東西顯式使用auto-proxying,它可能會(huì)導(dǎo)致問(wèn)題 (例如通知沒(méi)有被織入)。 推薦的使用模式是僅僅使用<aop:config>風(fēng)格, 或者僅僅使用AutoProxyCreator風(fēng)格。

6.3.1.?聲明一個(gè)切面

   

有了schema的支持,切面就和常規(guī)的Java對(duì)象一樣被定義成application context中的一個(gè)bean。   對(duì)象的字段和方法提供了狀態(tài)和行為信息,XML文件則提供了切入點(diǎn)和通知信息。

 

切面使用<aop:aspect>來(lái)聲明,backing bean(支持bean)通過(guò) ref 屬性來(lái)引用:

<aop:config>
  <aop:aspect id="myAspect" ref="aBean">
    ...
  </aop:aspect>
</aop:config>

<bean id="aBean" class="...">
  ...
</bean>

切面的支持bean(上例中的"aBean")可以象其他Spring bean一樣被容器管理配置以及依賴注入。

6.3.2.?聲明一個(gè)切入點(diǎn)

   

一個(gè)命名切入點(diǎn)可以在<aop:config>元素中定義,這樣多個(gè)切面和通知就可以共享該切入點(diǎn)。

 

一個(gè)描述service層中所有service執(zhí)行的切入點(diǎn)可以定義如下:

<aop:config>

  <aop:pointcut id="businessService" 
        expression="execution(* com.xyz.myapp.service.*.*(..))"/>

</aop:config>
   

注意切入點(diǎn)表達(dá)式本身使用了與第?6.2?節(jié) “@AspectJ支持”中描述的相同的AspectJ切入點(diǎn)表達(dá)式語(yǔ)言。   如果你在Java 5環(huán)境下使用基于schema的聲明風(fēng)格,可參考切入點(diǎn)表達(dá)式類型(@Aspects)中定義的命名切入點(diǎn),   不過(guò)這個(gè)特性在JDK1.4及以下版本中是不可用的(因?yàn)橐蕾囉贘ava 5中的AspectJ反射API)。所以在JDK 1.5中,   上面的切入點(diǎn)的另外一種定義形式如下:  

<aop:config>

  <aop:pointcut id="businessService" 
        expression="com.xyz.myapp.SystemArchitecture.businessService()"/>

</aop:config>

假定你有一個(gè)在第?6.2.3.3?節(jié) “共享通用切入點(diǎn)定義”中 描述的SystemArchitecture切面。

在切面里面聲明一個(gè)切入點(diǎn)和聲明一個(gè)頂級(jí)的切入點(diǎn)非常類似:

<aop:config>

  <aop:aspect id="myAspect" ref="aBean">

    <aop:pointcut id="businessService" 
          expression="execution(* com.xyz.myapp.service.*.*(..))"/>
          
    ...
    
  </aop:aspect>

</aop:config>

幾乎和@AspectJ切面中的一樣,使用基于schema定義風(fēng)格聲明的切入點(diǎn)可以收集(collect) 連接點(diǎn)上下文。例如,下面的切入點(diǎn)收集'this'對(duì)象作為連接點(diǎn)上下文并傳遞它給通知:

<aop:config>

  <aop:aspect id="myAspect" ref="aBean">

    <aop:pointcut id="businessService" 
          expression="execution(* com.xyz.myapp.service.*.*(..)) &amp;&amp; this(service)"/>
    <aop:before pointcut-ref="businessService" method="monitor"/>
    ...
    
  </aop:aspect>

</aop:config>
   

通過(guò)包含匹配名字的參數(shù),通知被聲明來(lái)接收收集的連接點(diǎn)上下文:

public void monitor(Object service) {
    ...
}
   

當(dāng)需要連接子表達(dá)式的時(shí)候,'&&'在XML中用起來(lái)非常不方便,所以關(guān)鍵字'and', 'or' 和 'not'可以分別用來(lái)代替'&&', '||' 和 '!'。例如,上面切入點(diǎn)更好的寫法如下:

<aop:config>

  <aop:aspect id="myAspect" ref="aBean">

    <aop:pointcut id="businessService" 
          expression="execution(* com.xyz.myapp.service.*.*(..)) and this(service)"/>
    <aop:before pointcut-ref="businessService" method="monitor"/>
    ...
    
  </aop:aspect>

</aop:config>

注意這種方式定義的切入點(diǎn)通過(guò)XML id來(lái)查找,并且不能定義切入點(diǎn)參數(shù)。在基于schema的定義風(fēng)格中 命名切入點(diǎn)支持較之@AspectJ風(fēng)格受到了很多的限制。

6.3.3.?聲明通知

 

和@AspectJ風(fēng)格一樣,基于schema的風(fēng)格也支持5種通知類型并且兩者具有同樣的語(yǔ)義。

6.3.3.1.?前置通知

    

前置通知在匹配方法執(zhí)行前運(yùn)行。在<aop:aspect>中使用<aop:before> 元素來(lái)聲明它。

<aop:aspect id="beforeExample" ref="aBean">

    <aop:before 
      pointcut-ref="dataAccessOperation" 
      method="doAccessCheck"/>
          
    ...
    
</aop:aspect>
    

這里dataAccessOperation是一個(gè)頂級(jí)(<aop:config>)切入點(diǎn)的id。     而要定義內(nèi)置切入點(diǎn),需將pointcut-ref屬性替換為pointcut屬性:

<aop:aspect id="beforeExample" ref="aBean">

    <aop:before 
      pointcut="execution(* com.xyz.myapp.dao.*.*(..))" 
      method="doAccessCheck"/>
          
    ...
    
</aop:aspect>
    

正如我們?cè)贎AspectJ風(fēng)格章節(jié)中討論過(guò)的,使用命名切入點(diǎn)能夠明顯的提高代碼的可讀性。

Method屬性標(biāo)識(shí)了提供通知主體的方法(doAccessCheck)。 這個(gè)方法必須定義在包含通知的切面元素所引用的bean中。在一個(gè)數(shù)據(jù)訪問(wèn)操作執(zhí)行之前 (一個(gè)方法執(zhí)行由切入點(diǎn)表達(dá)式所匹配的連接點(diǎn)),切面中的"doAccessCheck"會(huì)被調(diào)用。

6.3.3.2.?后置通知

后置通知在匹配的方法完全執(zhí)行后運(yùn)行。和前置通知一樣,可以在<aop:aspect> 里面聲明它。例如:

<aop:aspect id="afterReturningExample" ref="aBean">

    <aop:after-returning 
      pointcut-ref="dataAccessOperation" 
      method="doAccessCheck"/>
          
    ...
    
</aop:aspect>

和@AspectJ風(fēng)格一樣,通知主體可以得到返回值。使用returning屬性來(lái)指定傳遞返回值的參數(shù)名:

<aop:aspect id="afterReturningExample" ref="aBean">

    <aop:after-returning 
      pointcut-ref="dataAccessOperation"
      returning="retVal" 
      method="doAccessCheck"/>
          
    ...
    
</aop:aspect>

doAccessCheck方法必須聲明一個(gè)名字叫 retVal 的參數(shù)。 參數(shù)的類型依照@AfterReturning所描述的方法強(qiáng)制匹配。例如,方法簽名可以這樣聲明:

public void doAccessCheck(Object retVal) {...

6.3.3.3.?異常通知

異常通知在匹配方法拋出異常退出時(shí)執(zhí)行。在<aop:aspect>中使用 after-throwing元素來(lái)聲明:

<aop:aspect id="afterThrowingExample" ref="aBean">

    <aop:after-throwing
      pointcut-ref="dataAccessOperation" 
      method="doRecoveryActions"/>
          
    ...
    
</aop:aspect>

和@AspectJ風(fēng)格一樣,通知主體可以得到拋出的異常。使用throwing屬性來(lái)指定傳遞異常的參數(shù)名:

<aop:aspect id="afterThrowingExample" ref="aBean">

    <aop:after-throwing 
      pointcut-ref="dataAccessOperation"
      throwing="dataAccessEx" 
      method="doRecoveryActions"/>
          
    ...
    
</aop:aspect>

doRecoveryActions方法必須聲明一個(gè)名字為dataAccessEx的參數(shù)。 參數(shù)的類型依照@AfterThrowing所描述的方法強(qiáng)制匹配。例如:方法簽名可以如下這般聲明:

public void doRecoveryActions(DataAccessException dataAccessEx) {...

6.3.3.4.?最終通知

最終通知無(wú)論如何都會(huì)在匹配方法退出后執(zhí)行。使用after元素來(lái)聲明它:

<aop:aspect id="afterFinallyExample" ref="aBean">

    <aop:after
      pointcut-ref="dataAccessOperation" 
      method="doReleaseLock"/>
          
    ...
    
</aop:aspect>

6.3.3.5.?環(huán)繞通知

環(huán)繞通知是最后一種通知類型。環(huán)繞通知在匹配方法運(yùn)行期的“周圍”執(zhí)行。 它有機(jī)會(huì)在目標(biāo)方法的前面和后面執(zhí)行,并決定什么時(shí)候運(yùn)行,怎么運(yùn)行,甚至是否運(yùn)行。 環(huán)繞通知經(jīng)常在需要在一個(gè)方法執(zhí)行前后共享狀態(tài)信息,并且是在線程安全的情況下使用 (啟動(dòng)和停止一個(gè)計(jì)時(shí)器就是一個(gè)例子)。注意選擇能滿足你需求的最簡(jiǎn)單的通知類型; 如果簡(jiǎn)單的前置通知能做的事情就絕對(duì)不要使用環(huán)繞通知。

Around通知使用aop:around元素來(lái)聲明。通知方法的第一個(gè)參數(shù)的類型必須是 ProceedingJoinPoint類型。在通知的主體中,調(diào)用 ProceedingJoinPointproceed()方法來(lái)執(zhí)行真正的方法。 proceed方法也可能會(huì)被調(diào)用并且傳入一個(gè)Object[]對(duì)象 - 該數(shù)組將作為方法執(zhí)行時(shí)候的參數(shù)。參見(jiàn)第?6.2.4.5?節(jié) “環(huán)繞通知”中調(diào)用具有 Object[]的proceed方法。

<aop:aspect id="aroundExample" ref="aBean">

    <aop:around
      pointcut-ref="businessService" 
      method="doBasicProfiling"/>
          
    ...
    
</aop:aspect>

doBasicProfiling通知的實(shí)現(xiàn)和@AspectJ中的例子完全一樣(當(dāng)然要去掉注解):

public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
    // start stopwatch
    Object retVal = pjp.proceed();
    // stop stopwatch
    return retVal;
}

6.3.3.6.?通知參數(shù)

Schema-based聲明風(fēng)格和@AspectJ一樣,支持多種類型的通知:通過(guò)通知方法參數(shù)名字來(lái)匹配切入點(diǎn)參數(shù)。 參見(jiàn)第?6.2.4.6?節(jié) “通知參數(shù)(Advice parameters)”獲取詳細(xì)信息。如果你希望顯式指定通知方法的參數(shù)名 (而不是依靠先前提及的偵測(cè)策略),可以通過(guò)通知元素的arg-names屬性來(lái)實(shí)現(xiàn),它的處理和 在第?6.2.4.6.3?節(jié) “確定參數(shù)名”中所描述的對(duì)通知注解中"argNames"屬性的處理方式一樣。 示例如下:

<aop:before
  pointcut="com.xyz.lib.Pointcuts.anyPublicMethod() and @annotation(auditable)"
  method="audit"
  arg-names="auditable"/>

arg-names屬性接受由逗號(hào)分割的參數(shù)名列表。

下面是個(gè)稍微復(fù)雜的基于XSD的例子,它展示了關(guān)聯(lián)了多個(gè)強(qiáng)類型參數(shù)的環(huán)繞通知的使用。

package x.y.service;

public interface FooService {

   Foo getFoo(String fooName, int age);
}

public class DefaultFooService implements FooService {

   public Foo getFoo(String name, int age) {
      return new Foo(name, age);
   }
}

接下來(lái)看切面。注意profile(..)方法接受多個(gè)強(qiáng)類型參數(shù), 首先連接點(diǎn)在方法調(diào)用時(shí)執(zhí)行,這個(gè)參數(shù)指明profile(..)會(huì)被用作 環(huán)繞通知:

package x.y;

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

public class SimpleProfiler {

   public Object profile(ProceedingJoinPoint call, String name, int age) throws Throwable {
      StopWatch clock = new StopWatch(
            "Profiling for '" + name + "' and '" + age + "'");
      try {
         clock.start(call.toShortString());
         return call.proceed();
      } finally {
         clock.stop();
         System.out.println(clock.prettyPrint());
      }
   }
}

最后這里是使得上面的通知針對(duì)一個(gè)特定連接點(diǎn)而執(zhí)行所必需的XML配置:

<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"
      xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

   <!-- this is the object that will be proxied by Spring's AOP infrastructure -->
   <bean id="fooService" class="x.y.service.DefaultFooService"/>

   <!-- this is the actual advice itself -->
   <bean id="profiler" class="x.y.SimpleProfiler"/>

   <aop:config>
      <aop:aspect ref="profiler">

         <aop:pointcut id="theExecutionOfSomeFooServiceMethod"
                    expression="execution(* x.y.service.FooService.getFoo(String,int))
                    and args(name, age)"/>

         <aop:around pointcut-ref="theExecutionOfSomeFooServiceMethod"
                  method="profile"/>

      </aop:aspect>
   </aop:config>

</beans>

如果我們有下面的驅(qū)動(dòng)腳本,我們將在標(biāo)準(zhǔn)輸出上得到如下的輸出:

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import x.y.service.FooService;

public final class Boot {

   public static void main(final String[] args) throws Exception {
      BeanFactory ctx = new ClassPathXmlApplicationContext("x/y/plain.xml");
      FooService foo = (FooService) ctx.getBean("fooService");
      foo.getFoo("Pengo", 12);
   }
}
StopWatch 'Profiling for 'Pengo' and '12'': running time (millis) = 0
-----------------------------------------
ms     %     Task name
-----------------------------------------
00000  ?  execution(getFoo)

6.3.3.7.?通知順序

當(dāng)同一個(gè)切入點(diǎn)(執(zhí)行方法)上有多個(gè)通知需要執(zhí)行時(shí),執(zhí)行順序的規(guī)則如 第?6.2.4.7?節(jié) “通知順序”所述。切面的優(yōu)先級(jí)通過(guò)給切面的支持bean增加 Order注解或者使切面的支持bean實(shí)現(xiàn) Ordered接口來(lái)決定。   

6.3.4.?引入

引入(在AspectJ中稱為inter-type聲明)允許一個(gè)切面聲明一個(gè)通知對(duì)象實(shí)現(xiàn)指定接口, 并且提供了一個(gè)接口實(shí)現(xiàn)類來(lái)代表這些對(duì)象。

引入的定義使用aop:aspect中的aop:declare-parents元素。 該元素用于聲明所匹配的類型有一個(gè)新的父類型(所以有了這個(gè)名字)。 例如,給定接口UsageTracked, 以及這個(gè)接口的一個(gè)實(shí)現(xiàn)類 DefaultUsageTracked, 下面的切面聲明所有實(shí)現(xiàn)service接口的類同時(shí)實(shí)現(xiàn) UsageTracked 接口。(比如為了通過(guò)JMX輸出統(tǒng)計(jì)信息)

<aop:aspect id="usageTrackerAspect" ref="usageTracking">

  <aop:declare-parents
      types-matching="com.xzy.myapp.service.*+"
      implement-interface="com.xyz.myapp.service.tracking.UsageTracked"
      default-impl="com.xyz.myapp.service.tracking.DefaultUsageTracked"/>
  
  <aop:before
    pointcut="com.xyz.myapp.SystemArchitecture.businessService()
              and this(usageTracked)"
    method="recordUsage"/>
  
</aop:aspect>

usageTracking bean的支持類可以包含下面的方法:

public void recordUsage(UsageTracked usageTracked) {
    usageTracked.incrementUseCount();
}

要實(shí)現(xiàn)的接口由implement-interface屬性來(lái)指定。  types-matching屬性的值是一個(gè)AspectJ類型模式:任何匹配類型的bean都會(huì)實(shí)現(xiàn)  UsageTracked 接口。注意在上面前置通知的例子中, serevice bean可以直接用作UsageTracked接口的實(shí)現(xiàn)。 如果以編程形式訪問(wèn)一個(gè)bean,你可以這樣來(lái)寫:

UsageTracked usageTracked = (UsageTracked) context.getBean("myService");

6.3.5.?切面實(shí)例化模型

采用Schema風(fēng)格來(lái)定義切面僅支持一種實(shí)例化模型就是singlton模型。其他的實(shí)例化模型或許以后的版本會(huì)支持。

6.3.6.?Advisor

"advisor"這個(gè)概念來(lái)自Spring1.2對(duì)AOP的支持,而在AspectJ中沒(méi)有等價(jià)的概念。 advisor就像一個(gè)小的自包含的切面,這個(gè)切面只有一個(gè)通知。切面自身通過(guò)一個(gè)bean表示, 并且必須實(shí)現(xiàn)一個(gè)在第?7.3.2?節(jié) “Spring里的通知類型”中描述的通知接口。 Advisor可以很好的利用AspectJ的切入點(diǎn)表達(dá)式。  

Spring 2.0通過(guò)<aop:advisor>元素來(lái)支持advisor概念。 你將會(huì)發(fā)現(xiàn)大多數(shù)情況下它會(huì)和transactional advice一起使用,在Spring 2.0中它有自己的命名空間。其格式如下:  

<aop:config>

  <aop:pointcut id="businessService"
        expression="execution(* com.xyz.myapp.service.*.*(..))"/>

  <aop:advisor 
      pointcut-ref="businessService"
      advice-ref="tx-advice"/>
      
</aop:config>

<tx:advice id="tx-advice">
  <tx:attributes>
    <tx:method name="*" propagation="REQUIRED"/>
  </tx:attributes>
</tx:advice>

和上面所使用的pointcut-ref屬性一樣,你還可以使用pointcut 屬性來(lái)定義一個(gè)內(nèi)聯(lián)的切入點(diǎn)表達(dá)式。

為了定義一個(gè)advisor的優(yōu)先級(jí)以便讓通知具有次序,使用order屬性來(lái)定義advisor中 Ordered的值 。

6.3.7.?例子

讓我們看看第?6.2.7?節(jié) “例子”中并發(fā)鎖失敗重試的例子, 當(dāng)使用schema重寫它時(shí)是什么樣子。

因?yàn)椴l(fā)的問(wèn)題,有時(shí)候business services可能會(huì)失?。ɡ?,死鎖失?。?。如果重試操作,下一次很可能就會(huì)成功。   對(duì)于business services來(lái)說(shuō),這種情況下重試是很正常的(Idempotent操作不需要用戶參與,否則會(huì)得出矛盾的結(jié)論)    我們可能需要透明的重試操作以避免客戶看到一個(gè)OptimisticLockingFailureException   異常。很明顯,在一個(gè)橫切多層的情況下,這是非常有必要的,因此通過(guò)切面來(lái)實(shí)現(xiàn)是很理想的。  

因?yàn)橄胍卦嚥僮?,我們需要使用環(huán)繞通知,這樣就可以多次調(diào)用proceed()方法。 下面是簡(jiǎn)單的切面實(shí)現(xiàn)(只是一個(gè)schema支持的普通Java 類):

public class ConcurrentOperationExecutor implements Ordered {
   
   private static final int DEFAULT_MAX_RETRIES = 2;

   private int maxRetries = DEFAULT_MAX_RETRIES;
   private int order = 1;

   public void setMaxRetries(int maxRetries) {
      this.maxRetries = maxRetries;
   }
   
   public int getOrder() {
      return this.order;
   }
   
   public void setOrder(int order) {
      this.order = order;
   }
   
   public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable { 
      int numAttempts = 0;
      PessimisticLockingFailureException lockFailureException;
      do {
         numAttempts++;
         try { 
            return pjp.proceed();
         }
         catch(PessimisticLockingFailureException ex) {
            lockFailureException = ex;
         }
      }
      while(numAttempts <= this.maxRetries);
      throw lockFailureException;
   }

}

請(qǐng)注意切面實(shí)現(xiàn)了Ordered接口,這樣我們就可以把切面的優(yōu)先級(jí)設(shè)定為 高于事務(wù)通知(我們每次重試的時(shí)候都想要在一個(gè)全新的事務(wù)中進(jìn)行)。 maxRetriesorder 屬性都可以在Spring中配置。 主要的動(dòng)作在doConcurrentOperation 這個(gè)環(huán)繞通知方法中發(fā)生。 我們首先會(huì)嘗試處理,如果得到一個(gè)OptimisticLockingFailureException 異常,我們僅僅重試直到耗盡所有預(yù)設(shè)的重試次數(shù)。

這個(gè)類跟我們?cè)贎AspectJ的例子中使用的是相同的,只是沒(méi)有使用注解。

 

對(duì)應(yīng)的Spring配置如下:

<aop:config>

  <aop:aspect id="concurrentOperationRetry" ref="concurrentOperationExecutor">

    <aop:pointcut id="idempotentOperation"
        expression="execution(* com.xyz.myapp.service.*.*(..))"/>
       
    <aop:around
       pointcut-ref="idempotentOperation"
       method="doConcurrentOperation"/>
  
  </aop:aspect>

</aop:config>

<bean id="concurrentOperationExecutor"
  class="com.xyz.myapp.service.impl.ConcurrentOperationExecutor">
     <property name="maxRetries" value="3"/>
     <property name="order" value="100"/>  
</bean>

請(qǐng)注意我們現(xiàn)在假設(shè)所有的bussiness services都是idempotent。如果不是這樣,我們可以改寫切面, 通過(guò)引入一個(gè)Idempotent注解,讓它只調(diào)用idempotent:

@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
  // marker annotation
}

并且對(duì)service操作的實(shí)現(xiàn)進(jìn)行注解。這時(shí)如果你只希望改變切面重試idempotent操作, 你只需要改寫切入點(diǎn)表達(dá)式,讓其只匹配@Idempotent操作:

  <aop:pointcut id="idempotentOperation"
        expression="execution(* com.xyz.myapp.service.*.*(..)) and
                    @annotation(com.xyz.myapp.service.Idempotent)"/>
?? ??: ?? ??: