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

directory search
前言 簡(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)簽庫 對(duì)Tiles 2 支持 對(duì)JSF 1.2支持 JAX-WS支持 其他 動(dòng)態(tài)語言支持 增強(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)造器來實(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ó)際化 事件 底層資源的訪問 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è)組件 使用過濾器自定義掃描 自動(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作為屬性來配置 Application context 和Resource 路徑 構(gòu)造application context 創(chuàng)建 ClassPathXmlApplicationContext 實(shí)例 - 簡(jiǎn)介 Application context構(gòu)造器中資源路徑的通配符 Ant風(fēng)格的pattern 潛在的可移植性 classpath*: 前綴 其他關(guān)于通配符的說明 FileSystemResource 說明 校驗(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) 訪問當(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來配置AspectJ的切面 在Spring應(yīng)用中使用AspectJ加載時(shí)織入(LTW) 第一個(gè)例子 切面 'META-INF/aop.xml' 相關(guān)類庫(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通過編程創(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ù)管理 簡(jiǎn)介 動(dòng)機(jī) 關(guān)鍵抽象 使用資源同步的事務(wù) 高層次方案 低層次方案 TransactionAwareDataSourceProxy 聲明式事務(wù)管理 理解Spring的聲明式事務(wù)管理實(shí)現(xiàn) 第一個(gè)例子 回滾 為不同的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 常見問題的解決方法 對(duì)一個(gè)特定的 DataSource 使用了錯(cuò)誤的事務(wù)管理器 更多的資源 DAO支持 簡(jiǎn)介 一致的異常層次 一致的DAO支持抽象類 使用JDBC進(jìn)行數(shù)據(jù)訪問 簡(jiǎn)介 選擇一種工作模式 Spring JDBC包結(jié)構(gòu) 利用JDBC核心類控制JDBC的基本操作和錯(cuò)誤處理 JdbcTemplate類 一些示例 查詢(SELECT) 更新(INSERT/UPDATE/DELETE) 其他操作 JdbcTemplate 的最佳實(shí)踐 NamedParameterJdbcTemplate類 SimpleJdbcTemplate類 DataSource接口 SQLExceptionTranslator接口 執(zhí)行SQL語句 執(zhí)行查詢 更新數(shù)據(jù)庫 獲取自動(dòng)生成的主鍵 控制數(shù)據(jù)庫連接 DataSourceUtils類 SmartDataSource接口 AbstractDataSource類 SingleConnectionDataSource類 DriverManagerDataSource類 TransactionAwareDataSourceProxy類 DataSourceTransactionManager類 NativeJdbcExtractor JDBC批量操作 使用JdbcTemplate進(jìn)行批量操作 使用SimpleJdbcTemplate進(jìn)行批量操作 通過使用SimpleJdbc類簡(jiǎn)化JDBC操作 使用SimpleJdbcInsert插入數(shù)據(jù) 使用SimpleJdbcInsert來獲取自動(dòng)生成的主鍵 指定SimpleJdbcInsert所使用的字段 使用SqlParameterSource提供參數(shù)值 使用SimpleJdbcCall調(diào)用存儲(chǔ)過程 聲明SimpleJdbcCall使用的參數(shù) 如何定義SqlParameters 使用SimpleJdbcCall調(diào)用內(nèi)置函數(shù) 使用SimpleJdbcCall返回的ResultSet/REF Cursor 用Java對(duì)象來表達(dá)JDBC操作 SqlQuery類 MappingSqlQuery類 SqlUpdate類 StoredProcedure類 SqlFunction類 參數(shù)和數(shù)據(jù)處理的基本原則 為參數(shù)設(shè)置SQL類型信息 處理BLOB 和 CLOB對(duì)象 在IN語句中傳入一組參數(shù)值 處理復(fù)雜類型的存儲(chǔ)過程調(diào)用 使用ORM工具進(jìn)行數(shù)據(jù)訪問 簡(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)簽庫 配置 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)化開發(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 頁面中 組件定義文件 添加抽象訪問方法 將 Spring Beans 注入到 Tapestry 頁面中 - 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)程訪問與Web服務(wù) 簡(jiǎn)介 使用RMI暴露服務(wù) 使用RmiServiceExporter暴露服務(wù) 在客戶端鏈接服務(wù) 使用Hessian或者Burlap通過HTTP遠(yuǎn)程調(diào)用服務(wù) 為Hessian和co.配置DispatcherServlet 使用HessianServiceExporter暴露你的bean 在客戶端連接服務(wù) 使用Burlap 對(duì)通過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ù) 注冊(cè)JAX-RPC Bean映射 注冊(cè)自己的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ù)端配置 客戶端配置 對(duì)遠(yuǎn)程接口不提供自動(dòng)探測(cè)實(shí)現(xiàn) 在選擇這些技術(shù)時(shí)的一些考慮 Enterprise Java Beans (EJB) 集成 簡(jiǎn)介 訪問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) 簡(jiǎn)介 使用Spring JMS JmsTemplate 連接工廠 目的地管理 消息偵聽容器 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 通過代理訪問MBean 通知 為通知注冊(cè)監(jiān)聽器 發(fā)布通知 更多資源 JCA CCI 簡(jiǎn)介 配置CCI 連接器配置 在Spring中配置ConnectionFactory 配置CCI連接 使用一個(gè) CCI 單連接 使用Spring的 CCI訪問支持 記錄轉(zhuǎn)換 CciTemplate類 DAO支持 自動(dòng)輸出記錄生成 總結(jié) 直接使用一個(gè)CCI Connection接口和Interaction接口 CciTemplate 使用示例 建模CCI訪問為操作對(duì)象 MappingRecordOperation MappingCommAreaOperation 自動(dòng)生成輸出記錄 總結(jié) MappingRecordOperation 使用示例 MappingCommAreaOperation 使用示例 事務(wù) Spring郵件抽象層 簡(jiǎn)介 使用Spring郵件抽象 MailSender 和 SimpleMailMessage 的基本用法 使用 JavaMailSender 和 MimeMessagePreparator 使用MimeMessageHelper 發(fā)送附件和嵌入式資源(inline resources) 附件 內(nèi)嵌資源 使用模板來創(chuàng)建郵件內(nèi)容 一個(gè)基于Velocity的示例 Spring中的定時(shí)調(diào)度(Scheduling)和線程池(Thread Pooling) 簡(jiǎn)介 使用OpenSymphony Quartz 調(diào)度器 使用JobDetailBean 使用 MethodInvokingJobDetailFactoryBean 使用triggers和SchedulerFactoryBean來包裝任務(wù) 使用JDK Timer支持類 創(chuàng)建定制的timers 使用 MethodInvokingTimerTaskFactoryBean類 最后:使用TimerFactoryBean來設(shè)置任務(wù) SpringTaskExecutor抽象 TaskExecutor接口 TaskExecutor類型 使用TaskExecutor 動(dòng)態(tài)語言支持 介紹 第一個(gè)示例 定義動(dòng)態(tài)語言支持的bean 公共概念 <lang:language/> 元素 Refreshable bean 內(nèi)置動(dòng)態(tài)語言源文件 理解dynamic-language-backed bean上下文中的構(gòu)造器注入 JRuby beans Groovy beans 通過回調(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)語言實(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ā)手冊(cè)中文化項(xiàng)目 聲明 致謝 參與人員 項(xiàng)目歷程
characters

6.8.?在Spring應(yīng)用中使用AspectJ

到目前為止本章討論的一直是純Spring AOP。在這一節(jié)里面我們將介紹如何使用AspectJ compiler/weaver 來代替Spring AOP或者作為它的補(bǔ)充,因?yàn)橛行r(shí)候Spring AOP單獨(dú)提供的功能也許并不能滿足你的需要。

Spring提供了一個(gè)小巧的AspectJ aspect library,你可以在程序發(fā)行版本中單獨(dú)使用 spring-aspects.jar文件,并將其加入到classpath下以使用其中的切面。 第?6.8.1?節(jié) “在Spring中使用AspectJ進(jìn)行domain object的依賴注入”和第?6.8.2?節(jié) “Spring中其他的AspectJ切面” 討論了該庫以及如何使用該庫。 第?6.8.3?節(jié) “使用Spring IoC來配置AspectJ的切面”討論了如何對(duì)通過AspectJ compiler織入的AspectJ切面進(jìn)行依賴注入。 最后第?6.8.4?節(jié) “在Spring應(yīng)用中使用AspectJ加載時(shí)織入(LTW)”介紹了使用AspectJ的Spring應(yīng)用程序如何進(jìn)行加載期織入(load-time weaving)。

6.8.1.?在Spring中使用AspectJ進(jìn)行domain object的依賴注入

Spring容器對(duì)application context中定義的bean進(jìn)行實(shí)例化和配置。同樣也可以通過bean factory 來為一個(gè)已經(jīng)存在且已經(jīng)定義為spring bean的對(duì)象應(yīng)用所包含的配置信息。 spring-aspects.jar中包含了一個(gè)annotation-driven的切面, 提供了能為任何對(duì)象進(jìn)行依賴注入的能力。這樣的支持旨在為 脫離容器管理而創(chuàng)建的對(duì)象進(jìn)行依賴注入。領(lǐng)域?qū)ο蠼?jīng)常處于這樣的情形: 它們可能是通過new操作符創(chuàng)建的對(duì)象,也可能是由ORM工具查詢數(shù)據(jù)庫所返回的結(jié)果。

@Configurable注解標(biāo)記了一個(gè)類可以通過Spring-driven方式來配置。 在最簡(jiǎn)單的情況下,我們只把它當(dāng)作標(biāo)記注解:

package com.xyz.myapp.domain;
                
                import org.springframework.beans.factory.annotation.Configurable;
                
                @Configurable
                public class Account {
                // ...
            }

當(dāng)只是簡(jiǎn)單地作為一個(gè)標(biāo)記接口來使用的時(shí)候,Spring將采用和該已注解的類型 (比如Account類)全名(com.xyz.myapp.domain.Account) 一致的bean原型定義來配置一個(gè)新實(shí)例。由于一個(gè)bean默認(rèn)的名字就是它的全名, 所以一個(gè)比較方便的辦法就是省略定義中的id屬性:

<bean class="com.xyz.myapp.domain.Account" scope="prototype">
                <property name="fundsTransferService" ref="fundsTransferService"/>
            </bean>

如果你希望明確的指定bean原型定義的名字,你可以在注解中直接定義:

package com.xyz.myapp.domain;
                
                import org.springframework.beans.factory.annotation.Configurable;
                
                @Configurable("account")
                public class Account {
                // ...
            }

Spring會(huì)查找名字為"account"的bean定義,并使用它作定義來配置一個(gè)新的 Account實(shí)例。

你也可以使用自動(dòng)裝配來避免手工指定原型定義的名字。只要設(shè)置@Configurable 注解中的autowire屬性就可以讓Spring進(jìn)行自動(dòng)裝配: 指定@Configurable(autowire=Autowire.BY_TYPE)或者 @Configurable(autowire=Autowire.BY_NAME可以讓自動(dòng)裝配分別按照類型或名字進(jìn)行。 作為另外一種選擇,在Spring2.5中最好是在域或方法級(jí)使用@Autowired@Resource為你的@Configurable beans指定 明確的、注解驅(qū)動(dòng)的依賴注入。(詳情請(qǐng)參看第?3.11?節(jié) “基于注解(Annotation-based)的配置”)

最后,你可以通過使用dependencyCheck 屬性,讓Spring對(duì)新創(chuàng)建和配置的對(duì)象的對(duì)象引用進(jìn)行 依賴檢查(例如:@Configurable(autowire=Autowire.BY_NAME,dependencyCheck=true))。 如果這個(gè)屬性設(shè)置為true,Spring會(huì)在配置結(jié)束后校驗(yàn)(除了primitives和collections類型) 所有的屬性是否都被設(shè)置。

僅僅使用注解并沒有做任何事情。但是spring-aspects.jar 中的AnnotationBeanConfigurerAspect會(huì)在注解存在時(shí)起作用。實(shí)質(zhì)上切面指明: “在初始化一個(gè)由@Configurable 注解的新對(duì)象時(shí), Spring按照注解中的屬性來配置這個(gè)新創(chuàng)建的對(duì)象”。這種情況下,initialization 指新初始化的(比如用new初始化)的對(duì)象以及能進(jìn)行反序列化的 Serializable對(duì)象(例如通過 readResolve()方法)。

注意

在上一段中一個(gè)關(guān)鍵的階段就是“inessence”。多數(shù)情況下,“ 當(dāng)從一個(gè)新對(duì)象初始化返回之后”的精確語義很不錯(cuò)...這種語境下, “初始化之后”的意思是依賴將在對(duì)象被構(gòu)造之后注入 - 這意味著在類的構(gòu)造器塊中依賴將不可用。如果你希望它能在構(gòu)造器代碼塊執(zhí)行 之前被注入,并從而在構(gòu)造器中使用它, 那么你需要在@Configurable接口聲明上做類似的定義:

@Configurable(preConstruction=true)

你可以在 AspectJ Programming Guide一書的附錄中 找到更多有關(guān)在AspectJ中各種切面類型的語義信息。

要實(shí)現(xiàn)上述的操作,已注解的類型必須由AspectJ weaver來織入 - 你可以使用一個(gè)構(gòu)建時(shí)的ant/maven任務(wù)來完成 (參見AspectJ Development Environment Guide)或者使用加載時(shí)織入(參見 第?6.8.4?節(jié) “在Spring應(yīng)用中使用AspectJ加載時(shí)織入(LTW)”)。 類AnnotationBeanConfigurerAspect本身也需要Spring來配置(獲得bean factory的引用,使用bean factory配置新的對(duì)象)。為此Spring的 context命名空間 定義了一個(gè)非常方便的標(biāo)簽。只要簡(jiǎn)單的在application context配置中包含下面的內(nèi)容。

<context:spring-configured/>

如果你使用DTD代替Schema,對(duì)應(yīng)的定義如下:

<bean 
                class="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"
            factory-method="aspectOf"/>

在切面配置完成之前創(chuàng)建的@Configurable 對(duì)象實(shí)例會(huì)導(dǎo)致在log中留下一個(gè)warning,并且任何對(duì)于該對(duì)象的配置都不會(huì)生效。 舉一個(gè)例子,一個(gè)Spring管理配置的bean在被Spring初始化的時(shí)候創(chuàng)建了一個(gè)domain object。 對(duì)于這樣的情況,你需要定義bean屬性中的"depends-on"屬性來手動(dòng)指定該bean依賴于configuration切面。

<bean id="myService"
                class="com.xzy.myapp.service.MyService"
                depends-on="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect">
                
                <!-- ... -->
                
            </bean>

6.8.1.1.?@Configurable對(duì)象的單元測(cè)試

提供@Configurable支持的一個(gè)目的就是使得domain object的單元測(cè)試 可以獨(dú)立進(jìn)行,不需要通過硬編碼查找各種倚賴關(guān)系。如果@Configurable 類型沒有通過AspectJ織入,則在單元測(cè)試過程中注解不會(huì)起到任何作用, 測(cè)試中你可以簡(jiǎn)單的為對(duì)象的mock或者stub屬性賦值,并且和正常情況一樣去使用該對(duì)象。 如果@Configurable類型通過AspectJ織入, 我們依然可以脫離容器進(jìn)行單元測(cè)試,不過每次創(chuàng)建一個(gè)新的@Configurable 對(duì)象時(shí)都會(huì)看到一個(gè)warning,標(biāo)示該對(duì)象沒有被Spring配置。

6.8.1.2.?Working with multiple application contexts

6.8.1.2.?Working with multiple application contexts

AnnotationBeanConfigurerAspect通過一個(gè)AspectJ singleton切面來實(shí)現(xiàn)對(duì) @Configurable的支持。一個(gè)singleton切面的作用域和一個(gè) 靜態(tài)變量的作用域是一樣的,那就是說,對(duì)于每一個(gè)classloader有一個(gè)切面來定義類型。 這就意味著如果你在一個(gè)classloader層次結(jié)構(gòu)中定義了多個(gè)application context的時(shí)候就需要考慮 在哪里定義<aop:spring-configured/> bean和在哪個(gè)classpath下 放置spring-aspects.jar。

考慮一下典型的Spring web項(xiàng)目,一般都是由一個(gè)父application context定義大部分business service和 所需要的其他資源,然后每一個(gè)servlet擁有一個(gè)子application context定義。所有這些context共存于 同一個(gè)classloader體系下,因此AnnotationBeanConfigurerAspect僅保持 一個(gè)對(duì)context的引用。在這樣的情況下,我們推薦在父application context中定義 <aop:spring-configured/> bean:這里所定義的service可能是 你希望注入domain object的。這樣做的結(jié)果是你不能為子application context中 使用@Configurable的domain object配置bean引用(可能你也根本就不希望那么做!)。

當(dāng)在一個(gè)容器中部署多個(gè)web-app的時(shí)候,請(qǐng)確保每一個(gè)web-application使用自己的classloader 來加載spring-aspects.jar中的類(例如將spring-aspects.jar放在WEB-INF/lib目錄下)。 如果spring-aspects.jar被放在了容器的classpath下(因此也被父classloader加載),則所有的 web application將共享一個(gè)aspect實(shí)例,這可能并不是你所想要的。

6.8.2.?Spring中其他的AspectJ切面

除了@Configurable切面, spring-aspects.jar包含了一個(gè)AspectJ切面可以用來為 那些使用了@Transactional注解的類型和方法驅(qū)動(dòng)Spring事務(wù)管理。 提供這個(gè)的主要目的是有些用戶希望脫離Spring容器使用Spring的事務(wù)管理。

解析@Transactional注解的切面是 AnnotationTransactionAspect。當(dāng)使用這個(gè)切面時(shí), 你必須注解這個(gè)實(shí)現(xiàn)類(和/或這個(gè)類中的方法),而不是 這個(gè)類實(shí)現(xiàn)的接口(如果有)。AspectJ允許在接口上注解的Java規(guī)則 不被繼承。

類之上的一個(gè)@Transactional注解為該類中任何 public操作的執(zhí)行指定了默認(rèn)的事務(wù)語義。

類內(nèi)部方法上的一個(gè)@Transactional注解會(huì)覆蓋類注解(如果存在) 所給定的默認(rèn)的事務(wù)語義。具有public、protected和default修飾符的方法都可以被注解。 直接注解protected和default方法是讓這個(gè)操作的執(zhí)行獲得事務(wù)劃分的唯一途徑。

對(duì)于AspectJ程序員,希望使用Spring管理配置和事務(wù)管理支持,不過他們不想(或者不能)使用注解, spring-aspects.jar也包含了一些抽象 切面供你繼承來提供你自己的切入點(diǎn)定義。參見AbstractBeanConfigurerAspectAbstractTransactionAspect的Javadoc獲取更多信息。 作為一個(gè)例子,下面的代碼片斷展示了如何編寫一個(gè)切面,然后通過和類全名匹配的bean原型定義來 配置domian object中定義的所有實(shí)例:

public aspect DomainObjectConfiguration extends AbstractBeanConfigurerAspect {
                
                public DomainObjectConfiguration() {
                setBeanWiringInfoResolver(new ClassNameBeanWiringInfoResolver());
                }
                
                // the creation of a new bean (any object in the domain model)
                protected pointcut beanCreation(Object beanInstance) :
                initialization(new(..)) &&
                SystemArchitecture.inDomainModel() && 
                this(beanInstance);
                
            }

6.8.3.?使用Spring IoC來配置AspectJ的切面

當(dāng)在Spring application中使用AspectJ的時(shí)候,很自然的會(huì)想到用Spring來管理這些切面。 AspectJ runtime自身負(fù)責(zé)切面的創(chuàng)建,這意味著通過Spring來管理AspectJ 創(chuàng)建切面依賴于切面所使用的AspectJ instantiation model(per-clause)。

大多數(shù)AspectJ切面都是singleton切面。管理這些切面非常容易, 和通常一樣創(chuàng)建一個(gè)bean定義引用該切面類型就可以了,并且在bean定義中包含 'factory-method="aspectOf"'這個(gè)屬性。 這確保Spring從AspectJ獲取切面實(shí)例而不是嘗試自己去創(chuàng)建該實(shí)例。示例如下:

<bean id="profiler" class="com.xyz.profiler.Profiler"
                factory-method="aspectOf">
                <property name="profilingStrategy" ref="jamonProfilingStrategy"/>
            </bean>

non-singleton切面的配置稍難一點(diǎn),然而它可以通過定義一個(gè)bean原型定義并且使用 spring-aspects.jar中的@Configurable支持, 當(dāng)切面實(shí)例由AspectJ runtime創(chuàng)建后進(jìn)行配置。

如果你希望一些@AspectJ切面使用AspectJ來織入(例如使用load-time織入domain object) 而另一些@AspectJ切面使用Spring AOP,并且這些切面都由Spring來管理,那你就需要告訴Spring AOP @AspectJ自動(dòng)代理支持那些切面需要被自動(dòng)代理。你可以通過在 <aop:aspectj-autoproxy>聲明中使用一個(gè)或多個(gè) <include/>元素。每個(gè)元素指定了一種命名格式, 只有bean命名至少符合其中一種情況下才會(huì)使用Spring AOP自動(dòng)代理配置:

<aop:aspectj-autoproxy>
                <aop:include name="thisBean"/>
                <aop:include name="thatBean"/>
            </aop:aspectj-autoproxy>

注意

不要被<aop:aspectj-autoproxy/>元素的名字所誤導(dǎo): 用它會(huì)導(dǎo)致Spring AOP 代理的創(chuàng)建。在這中只是使用@AspectJ 類型的切面聲明,但并不會(huì)涉及AspectJ運(yùn)行時(shí)。

6.8.4.?在Spring應(yīng)用中使用AspectJ加載時(shí)織入(LTW)

加載時(shí)織入(Load-time weaving(LTW))指的是在虛擬機(jī)載入字節(jié)碼文件時(shí)動(dòng)態(tài)織入AspectJ切面。 本 節(jié)關(guān)注于在Spring Framework中特的定context下配置和使用LTW:并沒有LTW的介紹。 關(guān)于LTW和僅使用AspectJ配置LTW的詳細(xì)信息(根本不涉及Spring),請(qǐng)查看 LTW section of the AspectJ Development Environment Guide。

Spring框架的值添加為AspectJ LTW在動(dòng)態(tài)織入過程中提供了更細(xì)粒度的控制。使用Java(5+)的代理 能使用一個(gè)叫‘Vanilla’的AspectJ LTW,這需要在啟動(dòng)JVM的時(shí)候?qū)⒛硞€(gè)VM參數(shù)設(shè)置為開。 這種JVM范圍的設(shè)置在一些情況下或許不錯(cuò),但通常情況下顯得有些粗顆粒。而用Spring的LTW能讓你在 per-ClassLoader的基礎(chǔ)上打開LTW, 這顯然更加細(xì)粒度并且對(duì)“單JVM多應(yīng)用”的環(huán)境更具意義(例如在一個(gè)典型應(yīng)用服務(wù)器環(huán)境中一樣)。

另外,在某些環(huán)境下,這能讓你使用LTW而 不對(duì)應(yīng)用服務(wù)器的啟動(dòng)腳本做任何改動(dòng),不然則需要添加 -javaagent:path/to/aspectjweaver.jar或者(以下將會(huì)提及的)-javaagent:path/to/spring-agent.jar。 開發(fā)人員只需簡(jiǎn)單修改應(yīng)用上下文的一個(gè)或幾個(gè)文件就能使用LTW,而不需依靠那些管理著部署配置 比如啟動(dòng)腳本的系統(tǒng)管理員。

經(jīng)過以上講解之后,先讓我們來過一遍一個(gè)使用Spring的AspectJ LTW的快速示例,接著是一個(gè) 有對(duì)元素詳細(xì)講解的示例。如果想要一個(gè)完整的示例,請(qǐng)參看Petclinic(寵物診所)的應(yīng)用實(shí)例。

6.8.4.1.?第一個(gè)例子

假設(shè)你是一個(gè)應(yīng)用開人員,被指派診斷一個(gè)系統(tǒng)的若干性能問題。與其拿出性能分析工具, 我們不如開啟一個(gè)簡(jiǎn)單的分析切面,使我們能很快地得到一些性能指標(biāo),這樣我們就能馬上 針對(duì)特定區(qū)域使用一些較細(xì)粒度的分析工具。

這就是一個(gè)分析切面。沒什么特別的,只是一個(gè)快餐式的基于時(shí)間的模擬分析器, 使用類@AspectJ風(fēng)格的切面聲明。

package foo;
                    
                    import org.aspectj.lang.ProceedingJoinPoint;
                    import org.aspectj.lang.annotation.Aspect;
                    import org.aspectj.lang.annotation.Around;
                    import org.aspectj.lang.annotation.Pointcut;
                    import org.springframework.util.StopWatch;
                    import org.springframework.core.annotation.Order;
                    
                    @Aspect
                    public class ProfilingAspect {
                    
                    @Around("methodsToBeProfiled()")
                    public Object profile(ProceedingJoinPoint pjp) throws Throwable {
                    StopWatch sw = new StopWatch(getClass().getSimpleName());
                    try {
                    sw.start(pjp.getSignature().getName());
                    return pjp.proceed();
                    } finally {
                    sw.stop();
                    System.out.println(sw.prettyPrint());
                    }
                    }
                    
                    @Pointcut("execution(public * foo..*.*(..))")
                    public void methodsToBeProfiled(){}
                    }
                

我們還需要?jiǎng)?chuàng)建一個(gè)“META-INF/aop.xml”文件,以告知AspectJ weaver 我們要把ProfilingAspect織入到類中。這個(gè)文件慣例,即在Java classpath中 出現(xiàn)一個(gè)文件稱作“META-INF/aop.xml”是標(biāo)準(zhǔn)的AspectJ。

<!DOCTYPE aspectj PUBLIC
                    "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
                    <aspectj>
                    
                    <weaver>
                    
                    <!-- only weave classes in our application-specific packages -->
                    <include within="foo.*"/>
                    
                    </weaver>
                    
                    <aspects>
                    
                    <!-- weave in just this aspect -->        
                    <aspect name="foo.ProfilingAspect"/>
                    
                    </aspects>
                    
                </aspectj>

現(xiàn)在來看Spring特定的配置部分。我們需要配置一個(gè)LoadTimeWeaver (稍后會(huì)有解釋,暫時(shí)不多深究)。當(dāng)將一個(gè)或多個(gè)“META-INF/aop.xml”文件中的切面 配置織入你的應(yīng)用程序的類中時(shí),這個(gè)加載時(shí)織入器是必須的。這樣的好處是不需要很多的配置, 正如下面你看到的一樣(還有另外一些參數(shù)供你指定,我們將在后面詳細(xì)介紹)。

<?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:context="http://www.springframework.org/schema/context"
                    xsi:schemaLocation="
                    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
                    
                    <!-- a service object; we will be profiling it's methods -->
                    <bean id="entitlementCalculationService"
                    class="foo.StubEntitlementCalculationService"/>
                    
                    <!-- this switches on the load-time weaving -->
                    <context:load-time-weaver/>
                    
                </beans>

現(xiàn)在萬事俱備 - 切面,META-INF/aop.xml文件,以及Spring的配置 - 讓我們創(chuàng)建一個(gè)帶有main(..)方法的簡(jiǎn)單驅(qū)動(dòng)類來演示LTW的作用吧。

package foo;
                    
                    import org.springframework.context.support.ClassPathXmlApplicationContext;
                    
                    public final class Main {
                    
                    public static void main(String[] args) {
                    
                    ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml", Main.class);
                    
                    EntitlementCalculationService entitlementCalculationService
                    = (EntitlementCalculationService) ctx.getBean("entitlementCalculationService");
                    
                    // the profiling aspect is 'woven' around this method execution
                    entitlementCalculationService.calculateEntitlement();
                    }
                }

最后還有一件事要做。此節(jié)之前的介紹說過可以有選擇性的基于Spring的 per-ClassLoader來啟動(dòng)LTW,而且的確如此。不過,對(duì)此例來說, 我們將使用Java代理(由Spring提供)來啟動(dòng)LTW。這個(gè)就是用以運(yùn)行上面Main 類的命令行語句:

java -javaagent:C:/projects/foo/lib/global/spring-agent.jar foo.Main

-javaagent是一個(gè)Java 5+標(biāo)記,用來指定和激活 使JVM上的程序運(yùn)行的代理。Spring框架裝載了一個(gè)InstrumentationSavingAgent 代理,在上面的例子中被作為了-javaagent參數(shù)的值打包在 spring-agent.jar中。

Main程序運(yùn)行的輸出如下所示。(我已經(jīng)在 calculateEntitlement()的實(shí)現(xiàn)中插入了Thread.sleep(..) 語句,以免讓模擬分析器獲取0毫秒 - 這里的01234毫秒并非是AOP引入的系統(tǒng)開銷。)

Calculating entitlement
                    
                    StopWatch 'ProfilingAspect': running time (millis) = 1234
                    ------ ----- ----------------------------
                    ms     %     Task name
                    ------ ----- ----------------------------
                01234  100%  calculateEntitlement

因?yàn)檫@個(gè)LTW使用成熟的AspectJ,我們并不局限于通知Spring beans的方法;接下來這個(gè)稍有變化的 Main程序?qū)⑸赏瑯拥慕Y(jié)果。

package foo;
                    
                    import org.springframework.context.support.ClassPathXmlApplicationContext;
                    
                    public final class Main {
                    
                    public static void main(String[] args) {
                    
                    new ClassPathXmlApplicationContext("beans.xml", Main.class);
                    
                    EntitlementCalculationService entitlementCalculationService =
                    new StubEntitlementCalculationService();
                    
                    // the profiling aspect will be 'woven' around this method execution
                    entitlementCalculationService.calculateEntitlement();
                    }
                }

注意以上程序我們只是引導(dǎo)了Spring容器,然后完全在Spring上下文之外創(chuàng)建了一個(gè) StubEntitlementCalculationService的實(shí)例...分析通知仍然得到織入。

上面的例子雖然簡(jiǎn)單了些,但Spring中基本的LTW支持都已介紹完了, 此節(jié)余下內(nèi)容將對(duì)使用這些配置和用法背后的理由作詳細(xì)解釋。

注意

ProfilingAspect在此例中雖然基本但是頗為有用。這是一個(gè)很好的開發(fā)時(shí)切面的例子,開發(fā)者可以在開發(fā)過程中使用它(廢話), 然后也能從已部署到UAT或者生產(chǎn)環(huán)境的應(yīng)用中輕易的脫離。

6.8.4.2.?切面

你在LTW中使用的切面必須是AspectJ切面。你可以使用AspectJ語言或者類@AspectJ風(fēng)格來編寫你的切面。 后一種方式當(dāng)然只能在Java 5+中使用,但它說明了你的切面可以同時(shí)對(duì)AspectJ和Spring AOP切面有效。 此外,編譯后的切面類需要被注冊(cè)到classpath下。

6.8.4.3.?'META-INF/aop.xml'

AspectJ LTW的基礎(chǔ)設(shè)施是用一個(gè)或多個(gè)位于Java classpath上的(可以是直接的文件形式, 也可以是更典型的jar包形式)META-INF/aop.xml文件配置起來的。

有關(guān)文件的結(jié)構(gòu)和內(nèi)容都在AspectJ的參考文檔中有詳細(xì)介紹,有興趣的讀者 請(qǐng)參考這些資源。(很慶幸這一節(jié)比較簡(jiǎn)短,但aop.xml文件 是100% AspectJ的 - 沒有任何使用Spring特定的信息或語義,因此我也沒有什么可貢獻(xiàn)的。 與其重寫這些已由AspectJ開發(fā)者提供的令人滿意的章節(jié),我不如領(lǐng)你到這里。)

6.8.4.4.?相關(guān)類庫(JARS)

你至少需要以下類庫來讓Spring框架支持AspectJ LTW:

  1. spring.jar(2.5或更高版本)

  2. aspectjrt.jar (1.5或更高版本)

  3. aspectjweaver.jar (1.5或更高版本)

如果你正在使用 由Spring提供的代理來激活檢測(cè)(instrumentation)功能,你會(huì)需要:

  1. spring-agent.jar

6.8.4.5.?Spring配置

Spring LTW功能的關(guān)鍵組件是LoadTimeWeaver接口 (在org.springframework.instrument.classloading包中), 以及Spring分發(fā)包中大量的實(shí)現(xiàn)。LoadTimeWeaver的實(shí)現(xiàn)負(fù)責(zé) 在運(yùn)行時(shí)把一個(gè)或多個(gè)java.lang.instrument.ClassFileTransformers類添加到 ClassLoader中,這能產(chǎn)生各種各樣有趣的應(yīng)用,LTW切面恰好便是其中之一。

提示

如果你對(duì)運(yùn)行時(shí)類文件變換的思想還不熟悉,推薦你在繼續(xù)之前閱讀 java.lang.instrument包的Javadoc API文檔。 這其實(shí)并不難-反而有些惱人-因?yàn)橛杏玫奈募⒉欢?..關(guān)鍵的接口和類都將會(huì)在此節(jié)呈現(xiàn)給你。

用XML為ApplicationContext配置一個(gè) LoadTimeWeaver簡(jiǎn)單得只需要添加一行。 (請(qǐng)注意幾乎肯定你需要使用ApplicationContext作為你的 Spring容器 - 一般來說只有BeanFactory是不夠的, 因?yàn)長(zhǎng)TW功能需要用到BeanFactoryPostProcessors。)

當(dāng)要使用Spring框架的LTW功能時(shí),你需要配置一個(gè)LoadTimeWeaver, 一般可以用<context:load-time-weaver/>元素來完成。 下面為一個(gè)有效的使用默認(rèn)設(shè)置的<context:load-time-weaver/>定義。

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

上面<context:load-time-weaver/> bean的定義會(huì)自動(dòng)為你定義和注冊(cè)若干 特定LTW的基礎(chǔ)設(shè)施beans,比如一個(gè)LoadTimeWeaver 和一個(gè)AspectJWeavingEnabler。請(qǐng)注意 <context:load-time-weaver/>是怎樣在context 命名空間下被定義的;還要注意被引用的XML Schema文件只在Spring 2.5或更高版本中才可用。

上面的配置為你定義并注冊(cè)了一個(gè)默認(rèn)的LoadTimeWeaver bean。 默認(rèn)的LoadTimeWeaver是一個(gè) DefaultContextLoadTimeWeaver類,它更傾向于去裝飾一個(gè)能自動(dòng)檢測(cè)的LoadTimeWeaver類:LoadTimeWeaver 的確切類型會(huì)根據(jù)你的運(yùn)行時(shí)環(huán)境“自動(dòng)檢測(cè)”出來(概述如下表)。

表?6.1.?DefaultContextLoadTimeWeaver LoadTimeWeaversDefaultContextLoadTimeWeaver類和LoadTimeWeavers接口

運(yùn)行時(shí)環(huán)境 LoadTimeWeaver的接口實(shí)現(xiàn)

BEA's Weblogic 10環(huán)境下

WebLogicLoadTimeWeaver

Oracle's OC4J環(huán)境下

OC4JLoadTimeWeaver

GlassFish環(huán)境下

GlassFishLoadTimeWeaver

以SpringInstrumentationSavingAgent

啟動(dòng)的JVM中

(java -javaagent:path/to/spring-agent.jar)

InstrumentationLoadTimeWeaver

不過,我們更希望這些類加載器能遵循共同的規(guī)范 (例如適用TomcatInstrumentableClassLoader和Resin)

ReflectiveLoadTimeWeaver


請(qǐng)注意當(dāng)使用DefaultContextLoadTimeWeaver時(shí)只有 LoadTimeWeavers實(shí)現(xiàn)類能進(jìn)行自動(dòng)檢測(cè): 當(dāng)然,你也可以通過指定將類的完全限定名作為<context:load-time-weaver/> 元素中weaver-class屬性的值 來指定究竟想使用哪個(gè)LoadTimeWeaver的實(shí)現(xiàn)。如下例:

<?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:context="http://www.springframework.org/schema/context"
                    xsi:schemaLocation="
                    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
                    
                    <context:load-time-weaver
                    weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
                    
                </beans>

<context:load-time-weaver/>元素上定義和注冊(cè)的 LoadTimeWeaver接口可以在Spring容器中以 loadTimeWeaver名字找到。 記住LoadTimeWeaver接口只是作為Spring LTW基礎(chǔ)設(shè)施的一個(gè)機(jī)制 用來添加一個(gè)或多個(gè)ClassFileTransformers的。 ClassFileTransformer類實(shí)際是利用 ClassPreProcessorAgentAdapter類(包含在 org.aspectj.weaver.loadtime中)來進(jìn)行LTW的。 有關(guān)ClassPreProcessorAgentAdapter的細(xì)節(jié)請(qǐng)參見 類級(jí)別的javadoc,織入實(shí)際怎樣生效的具體內(nèi)容已經(jīng)超出本節(jié)討論范圍。

讓我們來討論<context:load-time-weaver/>的最后一個(gè)屬性: aspectj-weaving。 這是一個(gè)簡(jiǎn)單的LTW開關(guān),就這么簡(jiǎn)單。 它可以接受如下所述的三種值,如果不顯示設(shè)置此屬性則其默認(rèn)值為autodetect

表?6.2.?aspectj-weaving屬性值

屬性值 注釋

on

AspectJ織入功能開啟,切面將會(huì)在加載時(shí)適當(dāng)時(shí)機(jī)被織入。

off

LTW功能關(guān)閉...不會(huì)在加載時(shí)織入切面。

autodetect

如果Spring LTW基礎(chǔ)設(shè)施能找到至少一個(gè)META-INF/aop.xml 文件,那么AspectJ織入將會(huì)開啟,否則關(guān)閉。此為默認(rèn)值。


6.8.4.6.?特定環(huán)境的配置

這最后一節(jié)包括所有你在諸如應(yīng)用服務(wù)器和web容器中使用Spring的LTW功能時(shí)需要的額外設(shè)置和配置。

6.8.4.6.1.?通用Java應(yīng)用

你可能在各種Java應(yīng)用中通過使用由Spring提供的檢測(cè)代理啟用Spring的LTW功能 (獨(dú)立應(yīng)用或者基于應(yīng)用服務(wù)器的應(yīng)用)。這樣的話,可以通過指定 -javaagent:path/to/spring-agent.jar選項(xiàng)來啟動(dòng)虛擬機(jī)。 請(qǐng)注意這需要修改虛擬機(jī)的啟動(dòng)腳本,但在某些應(yīng)用服務(wù)器環(huán)境下是禁止這么做的 (這取決于你的操作策略)。

6.8.4.6.2.?Tomcat

對(duì)于部署在Apache Tomcat 5.0或更高版本上的web應(yīng)用,Spring將一個(gè) TomcatInstrumentableClassLoader注冊(cè)成為web應(yīng)用的類加載器。 必須的Tomcat設(shè)置如下所示,你可以把它放在Tomcat WAR包根目錄下的核心文件 server.xml中或放到應(yīng)用特定的META-INF/context.xml文件中。 Spring的spring-tomcat-weaver.jar需要被包含到Tomcat 的common lib路徑下以確保設(shè)置生效。

<Context path="/myWebApp" docBase="/my/webApp/location">
                        <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
                        useSystemClassLoaderAsParent="false"/>
                        </Context>
                    

注意:當(dāng)使用LTW時(shí),我們一般推薦使用Tomcat 5.5.20或更高版本。 先前的版本對(duì)定制的ClassLoader設(shè)置會(huì)產(chǎn)生問題。

另外,請(qǐng)考慮使用在Tomcat啟動(dòng)腳本中(見上面)指定由Spring提供的通用虛擬機(jī)代理。 這樣才能使檢測(cè)功能在所有已部署的web應(yīng)用中可用,無論其上運(yùn)行的是哪種類加載器。

有關(guān)更多基于Tomcat織入設(shè)置的詳細(xì)討論,請(qǐng)參考討論各種不同Tomcat版本內(nèi)容的 第?12.6.1.3.1?節(jié) “Tomcat(5.0以上)加載時(shí)的織入配置”一節(jié)。雖然本節(jié)主要關(guān)注于 JPA persistence提供者的設(shè)置,但也談到了Tomcat各種特定設(shè)置適用于一般加載時(shí)織入的情況。

6.8.4.6.3.?WebLogic, OC4J, Resin, GlassFish

BEA WebLogic(版本10或更高),Oracle的JavaEE容器(OC4J 10.1.3.1或更高)以及 Resin(版本3.1或更高)提供具有本地檢測(cè)能力的類加載器。 Srping的原生LTW利用這些類加載器來激活A(yù)spectJ織入。你可以通過簡(jiǎn)單地激活之前提到的 context:load-time-weaver來啟動(dòng)LTW功能。具體來說,即你 需要通過修改啟動(dòng)腳本來添加 -javaagent:path/to/spring-agent.jar。

GlassFish同樣也提供了檢測(cè)能力的類加載器,不過只能在它的EAR環(huán)境下使用。 對(duì)于GlassFish的web應(yīng)用,可以使用跟上面tomcat相同的設(shè)置。

Previous article: Next article: