亚洲国产日韩欧美一区二区三区,精品亚洲国产成人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)造器來實(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)類庫(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通過編程創(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ù)語(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 常見問題的解決方法 對(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語(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)行批量操作 通過使用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語(yǔ)句中傳入一組參數(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)簽庫(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)化開發(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è)面中 組件定義文件 添加抽象訪問方法 將 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)程訪問與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)語(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 通過回調(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開發(fā)手冊(cè)中文化項(xiàng)目 聲明 致謝 參與人員 項(xiàng)目歷程
テキスト

3.3.?依賴

典型的企業(yè)應(yīng)用不會(huì)只由單一的對(duì)象(或Spring的術(shù)語(yǔ)bean)組成。毫無疑問,即使最簡(jiǎn)單的系統(tǒng)也需要多個(gè)對(duì)象共同來展示給用戶一個(gè)整體的應(yīng)用。接下來的的內(nèi)容除了闡述如何單獨(dú)定義一系列bean外,還將描述如何讓這些bean對(duì)象一起協(xié)同工作來實(shí)現(xiàn)一個(gè)完整的真實(shí)應(yīng)用。

3.3.1.?注入依賴

依賴注入(DI)背后的基本原理是對(duì)象之間的依賴關(guān)系(即一起工作的其它對(duì)象)只會(huì)通過以下幾種方式來實(shí)現(xiàn):構(gòu)造器的參數(shù)、工廠方法的參數(shù),或給由構(gòu)造函數(shù)或者工廠方法創(chuàng)建的對(duì)象設(shè)置屬性。因此,容器的工作就是創(chuàng)建bean時(shí)注入那些依賴關(guān)系。相對(duì)于由bean自己來控制其實(shí)例化、直接在構(gòu)造器中指定依賴關(guān)系或者類似服務(wù)定位器(Service Locator)模式這3種自主控制依賴關(guān)系注入的方法來說,控制從根本上發(fā)生了倒轉(zhuǎn),這也正是控制反轉(zhuǎn)(Inversion of Control, IoC) 名字的由來。

應(yīng)用DI原則后,代碼將更加清晰。而且當(dāng)bean自己不再擔(dān)心對(duì)象之間的依賴關(guān)系(甚至不知道依賴的定義指定地方和依賴的實(shí)際類)之后,實(shí)現(xiàn)更高層次的松耦合將易如反掌。DI主要有兩種注入方式,即Setter注入和構(gòu)造器注入

3.3.1.1.?構(gòu)造器注入

基于構(gòu)造器的DI通過調(diào)用帶參數(shù)的構(gòu)造器來實(shí)現(xiàn),每個(gè)參數(shù)代表著一個(gè)依賴。此外,還可通過給stattic工廠方法傳參數(shù)來構(gòu)造bean。接下來的介紹將認(rèn)為給構(gòu)造器傳參與給靜態(tài)工廠方法傳參是類似的。下面展示了只能使用構(gòu)造器參數(shù)來注入依賴關(guān)系的例子。請(qǐng)注意,這個(gè)類并沒有什么特別之處。

public class SimpleMovieLister {

    // the SimpleMovieLister has a dependency on a MovieFinder
    private MovieFinder movieFinder;

    // a constructor so that the Spring container can 'inject' a MovieFinder
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    
    // business logic that actually 'uses' the injected MovieFinder is omitted...
}
3.3.1.1.1.?構(gòu)造器參數(shù)解析

構(gòu)造器參數(shù)解析根據(jù)參數(shù)類型進(jìn)行匹配,如果bean的構(gòu)造器參數(shù)類型定義非常明確,那么在bean被實(shí)例化的時(shí)候,bean定義中構(gòu)造器參數(shù)的定義順序就是這些參數(shù)的順序,依次進(jìn)行匹配,比如下面的代碼

package x.y;

public class Foo {

    public Foo(Bar bar, Baz baz) {
        // ...
    }
}

上述例子中由于構(gòu)造參數(shù)非常明確(這里我們假定 BarBaz之間不存在繼承關(guān)系)。因此下面的配置即使沒有明確指定構(gòu)造參數(shù)順序(和類型),也會(huì)工作的很好。

<beans>
    <bean name="foo" class="x.y.Foo">
        <constructor-arg>
            <bean class="x.y.Bar"/>
        </constructor-arg>
        <constructor-arg>
            <bean class="x.y.Baz"/>
        </constructor-arg>
    </bean>
</beans>

我們?cè)賮砜戳硪粋€(gè)bean,該bean的構(gòu)造參數(shù)類型已知,匹配也沒有問題(跟前面的例子一樣)。但是當(dāng)使用簡(jiǎn)單類型時(shí),比如<value>true<value>,Spring將無法知道該值的類型。不借助其他幫助,他將無法僅僅根據(jù)參數(shù)類型進(jìn)行匹配,比如下面的這個(gè)例子:

package examples;

public class ExampleBean {

    // No. of years to the calculate the Ultimate Answer
    private int years;

    // The Answer to Life, the Universe, and Everything
    private String ultimateAnswer;

    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }
}
3.3.1.1.1.1.?構(gòu)造器參數(shù)類型匹配

針對(duì)上面的場(chǎng)景可以通過使用'type'屬性來顯式指定那些簡(jiǎn)單類型的構(gòu)造參數(shù)的類型,比如:

<bean id="exampleBean" class="examples.ExampleBean">
  <constructor-arg type="int" value="7500000"/>
  <constructor-arg type="java.lang.String" value="42"/>
</bean>
3.3.1.1.1.2.?構(gòu)造參數(shù)索引

我們還可以通過index屬性來顯式指定構(gòu)造參數(shù)的索引,比如下面的例子:

<bean id="exampleBean" class="examples.ExampleBean">
  <constructor-arg index="0" value="7500000"/>
  <constructor-arg index="1" value="42"/>
</bean>

通過使用索引屬性不但可以解決多個(gè)簡(jiǎn)單屬性的混淆問題,還可以解決有可能有相同類型的2個(gè)構(gòu)造參數(shù)的混淆問題了,注意index是從0開始。

3.3.1.2.?Setter注入

通過調(diào)用無參構(gòu)造器或無參static工廠方法實(shí)例化bean之后,調(diào)用該bean的setter方法,即可實(shí)現(xiàn)基于setter的DI。

下面的例子將展示只使用setter注入依賴。注意,這個(gè)類并沒有什么特別之處,它就是普通的Java類。

public class SimpleMovieLister {

    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;

    // a setter method so that the Spring container can 'inject' a MovieFinder
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually 'uses' the injected MovieFinder is omitted...
}

BeanFactory對(duì)于它所管理的bean提供兩種注入依賴方式(實(shí)際上它也支持同時(shí)使用構(gòu)造器注入和Setter方式注入依賴)。需要注入的依賴將保存在BeanDefinition中,它能根據(jù)指定的PropertyEditor實(shí)現(xiàn)將屬性從一種格式轉(zhuǎn)換成另外一種格式。然而,大部份的Spring用戶并不需要直接以編程的方式處理這些類,而是采用XML的方式來進(jìn)行定義,在內(nèi)部這些定義將被轉(zhuǎn)換成相應(yīng)類的實(shí)例,并最終得到一個(gè)Spring IoC容器實(shí)例。

處理bean依賴關(guān)系通常按以下步驟進(jìn)行:

  1. 根據(jù)定義bean的配置(文件)創(chuàng)建并初始化BeanFactory實(shí)例(大部份的Spring用戶使用支持XML格式配置文件的BeanFactoryApplicationContext實(shí)現(xiàn))。

  2. 每個(gè)bean的依賴將以屬性、構(gòu)造器參數(shù)、或靜態(tài)工廠方法參數(shù)的形式出現(xiàn)。當(dāng)這些bean被實(shí)際創(chuàng)建時(shí),這些依賴也將會(huì)提供給該bean。

  3. 每個(gè)屬性或構(gòu)造器參數(shù)既可以是一個(gè)實(shí)際的值,也可以是對(duì)該容器中另一個(gè)bean的引用。

  4. 每個(gè)指定的屬性或構(gòu)造器參數(shù)值必須能夠被轉(zhuǎn)換成特定的格式或構(gòu)造參數(shù)所需的類型。默認(rèn)情況下,Spring會(huì)以String類型提供值轉(zhuǎn)換成各種內(nèi)置類型,比如int、long、String、boolean等。

Spring會(huì)在容器被創(chuàng)建時(shí)驗(yàn)證容器中每個(gè)bean的配置,包括驗(yàn)證那些bean所引用的屬性是否指向一個(gè)有效的bean(即被引用的bean也在容器中被定義)。然而,在bean被實(shí)際創(chuàng)建之前,bean的屬性并不會(huì)被設(shè)置。對(duì)于那些singleton類型和被設(shè)置為提前實(shí)例化的bean(比如ApplicationContext中的singleton bean)而言,bean實(shí)例將與容器同時(shí)被創(chuàng)建。而另外一些bean則會(huì)在需要的時(shí)候被創(chuàng)建,伴隨著bean被實(shí)際創(chuàng)建,作為該bean的依賴bean以及依賴bean的依賴bean(依此類推)也將被創(chuàng)建和分配。

通常情況下,你可以信賴Spring,它會(huì)在容器加載時(shí)發(fā)現(xiàn)配置錯(cuò)誤(比如對(duì)無效bean的引用以及循環(huán)依賴)。Spring會(huì)在bean創(chuàng)建時(shí)才去設(shè)置屬性和依賴關(guān)系(只在需要時(shí)創(chuàng)建所依賴的其他對(duì)象)。這意味著即使Spring容器被正確加載,當(dāng)獲取一個(gè)bean實(shí)例時(shí),如果在創(chuàng)建bean或者設(shè)置依賴時(shí)出現(xiàn)問題,仍然會(huì)拋出一個(gè)異常。因缺少或設(shè)置了一個(gè)無效屬性而導(dǎo)致拋出一個(gè)異常的情況的確是存在的。因?yàn)橐恍┡渲脝栴}而導(dǎo)致潛在的可見性被延遲,所以在默認(rèn)情況下,ApplicationContext實(shí)現(xiàn)中的bean采用提前實(shí)例化的singleton模式。在實(shí)際需要之前創(chuàng)建這些bean將帶來時(shí)間與內(nèi)存的開銷。而這樣做的好處就是ApplicationContext被加載的時(shí)候可以盡早的發(fā)現(xiàn)一些配置的問題。不過用戶也可以根據(jù)需要采用延遲實(shí)例化來替代默認(rèn)的singleton模式。

如果撇開循環(huán)依賴不談,當(dāng)協(xié)作bean被注入到依賴bean時(shí),協(xié)作bean必須在依賴bean之前完全配置好。例如bean A對(duì)bean B存在依賴關(guān)系,那么Spring IoC容器在調(diào)用bean A的setter方法之前,bean B必須被完全配置,這里所謂完全配置的意思就是bean將被實(shí)例化(如果不是采用提前實(shí)例化的singleton模式),相關(guān)的依賴也將被設(shè)置好,而且所有相關(guān)的lifecycle方法(如IntializingBean的init方法以及callback方法)也將被調(diào)用。

3.3.1.3.?一些例子

首先是一個(gè)用XML格式定義的Setter DI例子。相關(guān)的XML配置如下:

<bean id="exampleBean" class="examples.ExampleBean">

  <!-- setter injection using the nested <ref/> element -->
  <property name="beanOne"><ref bean="anotherExampleBean"/></property>

  <!-- setter injection using the neater 'ref' attribute -->
  <property name="beanTwo" ref="yetAnotherBean"/>
  <property name="integerProperty" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {

    private AnotherBean beanOne;
    private YetAnotherBean beanTwo;
    private int i;

    public void setBeanOne(AnotherBean beanOne) {
        this.beanOne = beanOne;
    }

    public void setBeanTwo(YetAnotherBean beanTwo) {
        this.beanTwo = beanTwo;
    }

    public void setIntegerProperty(int i) {
        this.i = i;
    }    
}

正如你所看到的,bean類中的setter方法與xml文件中配置的屬性是一一對(duì)應(yīng)的。接著是構(gòu)造器注入的例子:

<bean id="exampleBean" class="examples.ExampleBean">

  <!-- constructor injection using the nested <ref/> element -->
  <constructor-arg>
    <ref bean="anotherExampleBean"/>
  </constructor-arg>
  
  <!-- constructor injection using the neater 'ref' attribute -->
  <constructor-arg ref="yetAnotherBean"/>
  
  <constructor-arg type="int" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {

    private AnotherBean beanOne;
    private YetAnotherBean beanTwo;
    private int i;
    
    public ExampleBean(
        AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
        this.beanOne = anotherBean;
        this.beanTwo = yetAnotherBean;
        this.i = i;
    }
}

如你所見,在xml bean定義中指定的構(gòu)造器參數(shù)將被用來作為傳遞給類ExampleBean構(gòu)造器的參數(shù)。

現(xiàn)在來研究一個(gè)替代構(gòu)造器的方法,采用static工廠方法返回對(duì)象實(shí)例:

<bean id="exampleBean" class="examples.ExampleBean"
      factory-method="createInstance">
  <constructor-arg ref="anotherExampleBean"/>
  <constructor-arg ref="yetAnotherBean"/>
  <constructor-arg value="1"/> 
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {

    // a private constructor
    private ExampleBean(...) {
      ...
    }
    
    // a static factory method; the arguments to this method can be
    // considered the dependencies of the bean that is returned,
    // regardless of how those arguments are actually used.
    public static ExampleBean createInstance (
            AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {

        ExampleBean eb = new ExampleBean (...);
        // some other operations...
        return eb;
    }
}

請(qǐng)注意,傳給static工廠方法的參數(shù)由constructor-arg元素提供,這與使用構(gòu)造器注入時(shí)完全一樣。而且,重要的是,工廠方法所返回的實(shí)例的類型并不一定要與包含static工廠方法的類類型一致。盡管在此例子中它的確是這樣。非靜態(tài)的實(shí)例工廠方法與此相同(除了使用factory-bean屬性替代class屬性外),因而不在此細(xì)述。

3.3.2.?依賴配置詳解

正如前面章節(jié)所提到的,bean的屬性及構(gòu)造器參數(shù)既可以引用容器中的其他bean,也可以是內(nèi)聯(lián)(inline)bean。在spring的XML配置中使用<property/><constructor-arg/>元素定義。

3.3.2.1.?直接變量(基本類型、Strings類型等。)

<value/>元素通過人可以理解的字符串來指定屬性或構(gòu)造器參數(shù)的值。正如前面所提到的,JavaBean PropertyEditor將用于把字符串從java.lang.String類型轉(zhuǎn)化為實(shí)際的屬性或參數(shù)類型。

<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  
  <!-- results in a setDriverClassName(String) call -->
  <property name="driverClassName">
    <value>com.mysql.jdbc.Driver</value>
  </property>
  <property name="url">
    <value>jdbc:mysql://localhost:3306/mydb</value>
  </property>
  <property name="username">
    <value>root</value>
  </property>
  <property name="password">
    <value>masterkaoli</value>
  </property>
</bean>

<property/><constructor-arg/> 元素中也可以使用'value' 屬性,這樣會(huì)使我們的配置更簡(jiǎn)潔,比如下面的配置:

<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  
  <!-- results in a setDriverClassName(String) call -->
  <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
  <property name="username" value="root"/>
  <property name="password" value="masterkaoli"/>
</bean>

Spring團(tuán)隊(duì)更傾向采用屬性方式(使用<value/>元素)來定義value值。當(dāng)然我們也可以按照下面這種方式配置一個(gè)java.util.Properties實(shí)例:

<bean id="mappings" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            
   <!-- typed as a java.util.Properties -->
   <property name="properties">
      <value>
         jdbc.driver.className=com.mysql.jdbc.Driver
         jdbc.url=jdbc:mysql://localhost:3306/mydb
      </value>
   </property>
</bean>

看到什么了嗎?如果采用上面的配置,Spring容器將使用JavaBean PropertyEditor<value/>元素中的文本轉(zhuǎn)換為一個(gè)java.util.Properties實(shí)例。由于這種做法的簡(jiǎn)單,因此Spring團(tuán)隊(duì)在很多地方也會(huì)采用內(nèi)嵌的<value/>元素來代替value屬性。

3.3.2.1.1.?idref元素

idref元素用來將容器內(nèi)其它bean的id傳給<constructor-arg/><property/>元素,同時(shí)提供錯(cuò)誤驗(yàn)證功能。

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

<bean id="theClientBean" class="...">
    <property name="targetName">
        <idref bean="theTargetBean" />
    </property>
</bean>

上述bean定義片段完全地等同于(在運(yùn)行時(shí))以下的片段:

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

<bean id="client" class="...">
    <property name="targetName" value="theTargetBean" />
</bean>

第一種形式比第二種更可取的主要原因是,使用idref標(biāo)記允許容器在部署時(shí) 驗(yàn)證所被引用的bean是否存在。而第二種方式中,傳給client bean的targetName屬性值并沒有被驗(yàn)證。任何的輸入錯(cuò)誤僅在client bean實(shí)際實(shí)例化時(shí)才會(huì)被發(fā)現(xiàn)(可能伴隨著致命的錯(cuò)誤)。如果client bean 是prototype類型的bean,則此輸入錯(cuò)誤(及由此導(dǎo)致的異常)可能在容器部署很久以后才會(huì)被發(fā)現(xiàn)。

此外,如果被引用的bean在同一XML文件內(nèi),且bean名字就是bean id,那么可以使用local屬性,此屬性允許XML解析器在解析XML文件時(shí)對(duì)引用的bean進(jìn)行驗(yàn)證。

<property name="targetName">
   <!-- a bean with an id of 'theTargetBean' must exist; otherwise an XML exception will be thrown -->
   <idref local="theTargetBean"/>
</property>

上面的例子中,與在ProxyFactoryBean bean定義中使用<idref/>元素指定AOP interceptor的相同之處在于:如果使用<idref/>元素指定攔截器名字,可以避免因一時(shí)疏忽導(dǎo)致的攔截器ID拼寫錯(cuò)誤。

3.3.2.2.?引用其它的bean(協(xié)作者)

<constructor-arg/><property/>元素內(nèi)部還可以使用ref元素。該元素用來將bean中指定屬性的值設(shè)置為對(duì)容器中的另外一個(gè)bean的引用。如前所述,該引用bean將被作為依賴注入,而且在注入之前會(huì)被初始化(如果是singleton bean則已被容器初始化)。盡管都是對(duì)另外一個(gè)對(duì)象的引用,但是通過id/name指向另外一個(gè)對(duì)象卻有三種不同的形式,不同的形式將決定如何處理作用域及驗(yàn)證。

第一種形式也是最常見的形式是通過使用<ref/>標(biāo)記指定bean屬性的目標(biāo)bean,通過該標(biāo)簽可以引用同一容器或父容器內(nèi)的任何bean(無論是否在同一XML文件中)。XML 'bean'元素的值既可以是指定bean的id值也可以是其name值。

<ref bean="someBean"/>

第二種形式是使用ref的local屬性指定目標(biāo)bean,它可以利用XML解析器來驗(yàn)證所引用的bean是否存在同一文件中。local屬性值必須是目標(biāo)bean的id屬性值。如果在同一配置文件中沒有找到引用的bean,XML解析器將拋出一個(gè)例外。如果目標(biāo)bean是在同一文件內(nèi),使用local方式就是最好的選擇(為了盡早地發(fā)現(xiàn)錯(cuò)誤)。

<ref local="someBean"/>

第三種方式是通過使用ref的parent屬性來引用當(dāng)前容器的父容器中的bean。parent屬性值既可以是目標(biāo)bean的id值,也可以是name屬性值。而且目標(biāo)bean必須在當(dāng)前容器的父容器中。使用parent屬性的主要用途是為了用某個(gè)與父容器中的bean同名的代理來包裝父容器中的一個(gè)bean(例如,子上下文中的一個(gè)bean定義覆蓋了他的父bean)。

<!-- in the parent context -->
<bean id="accountService" class="com.foo.SimpleAccountService">
    <!-- insert dependencies as required as here -->
</bean>
<!-- in the child (descendant) context -->
<bean id="accountService"  <-- notice that the name of this bean is the same as the name of the 'parent' bean
      class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="target">
          <ref parent="accountService"/>  <-- notice how we refer to the parent bean
      </property>
    <!-- insert other configuration and dependencies as required as here -->
</bean>

3.3.2.3.?內(nèi)部bean

所謂的內(nèi)部bean(inner bean)是指在一個(gè)bean的<property/><constructor-arg/>元素中使用<bean/>元素定義的bean。內(nèi)部bean定義不需要有id或name屬性,即使指定id 或 name屬性值也將會(huì)被容器忽略。

<bean id="outer" class="...">
  <!-- instead of using a reference to a target bean, simply define the target bean inline -->
  <property name="target">
    <bean class="com.example.Person"> <!-- this is the inner bean -->
      <property name="name" value="Fiona Apple"/>
      <property name="age" value="25"/>
    </bean>
  </property>
</bean>

注意:內(nèi)部bean中的scope標(biāo)記及idname屬性將被忽略。內(nèi)部bean總是匿名的且它們總是prototype模式的。同時(shí)將內(nèi)部bean注入到包含該內(nèi)部bean之外的bean是可能的。

3.3.2.4.?集合

通過<list/>、<set/>、<map/><props/>元素可以定義和設(shè)置與Java Collection類型對(duì)應(yīng)List、Set、MapProperties的值。

<bean id="moreComplexObject" class="example.ComplexObject">
  <!-- results in a setAdminEmails(java.util.Properties) call -->
  <property name="adminEmails">
    <props>
        <prop key="administrator">administrator@example.org</prop>
        <prop key="support">support@example.org</prop>
        <prop key="development">development@example.org</prop>
    </props>
  </property>
  <!-- results in a setSomeList(java.util.List) call -->
  <property name="someList">
    <list>
        <value>a list element followed by a reference</value>
        <ref bean="myDataSource" />
    </list>
  </property>
  <!-- results in a setSomeMap(java.util.Map) call -->
  <property name="someMap">
    <map>
        <entry>
            <key>
                <value>an entry</value>
            </key>
            <value>just some string</value>
        </entry>
        <entry>
            <key>
                <value>a ref</value>
            </key>
            <ref bean="myDataSource" />
        </entry>
    </map>
  </property>
  <!-- results in a setSomeSet(java.util.Set) call -->
  <property name="someSet">
    <set>
        <value>just some string</value>
        <ref bean="myDataSource" />
    </set>
  </property>
</bean>

注意:map的key或value值,或set的value值還可以是以下元素:

bean | ref | idref | list | set | map | props | value | null
3.3.2.4.1.?集合的合并

從2.0開始,Spring IoC容器將支持集合的合并。這樣我們可以定義parent-style和child-style的<list/><map/><set/><props/>元素,子集合的值從其父集合繼承和覆蓋而來;也就是說,父子集合元素合并后的值就是子集合中的最終結(jié)果,而且子集合中的元素值將覆蓋父集全中對(duì)應(yīng)的值。

請(qǐng)注意,關(guān)于合并的這部分利用了parent-child bean機(jī)制。此內(nèi)容將在后面介紹,不熟悉父子bean的讀者可參見第?3.6?節(jié) “bean定義的繼承”。

Find below an example of the collection merging feature:

下面的例子展示了集合合并特性:

<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
    <property name="adminEmails">
        <props>
            <prop key="administrator">administrator@example.com</prop>
            <prop key="support">support@example.com</prop>
        </props>
    </property>
</bean>
<bean id="child" parent="parent">
    <property name="adminEmails">
        <!-- the merge is specified on the *child* collection definition -->
        <props merge="true">
            <prop key="sales">sales@example.com</prop>
            <prop key="support">support@example.co.uk</prop>
        </props>
    </property>
</bean>
<beans>

在上面的例子中,childbean的adminEmails屬性的<props/>元素上使用了merge=true屬性。當(dāng)child bean被容器實(shí)際解析及實(shí)例化時(shí),其 adminEmails將與父集合的adminEmails屬性進(jìn)行合并。

administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk

注意到這里子bean的Properties集合將從父<props/>繼承所有屬性元素。同時(shí)子bean的support值將覆蓋父集合的相應(yīng)值。

對(duì)于<list/>、<map/><set/>集合類型的合并處理都基本類似,在某個(gè)方面<list/>元素比較特殊,這涉及到List集合本身的語(yǔ)義學(xué),就拿維護(hù)一個(gè)有序集合中的值來說,父bean的列表內(nèi)容將排在子bean列表內(nèi)容的前面。對(duì)于Map、SetProperties集合類型沒有順序的概念,因此作為相關(guān)的Map、SetProperties實(shí)現(xiàn)基礎(chǔ)的集合類型在容器內(nèi)部沒有排序的語(yǔ)義。

最后需要指出的一點(diǎn)就是,合并功能僅在Spring 2.0(及隨后的版本中)可用。不同的集合類型是不能合并(如maplist是不能合并的),否則將會(huì)拋出相應(yīng)的Exception。merge屬性必須在繼承的子bean中定義,而在父bean的集合屬性上指定的merge屬性將被忽略。

3.3.2.4.2.?強(qiáng)類型集合(僅適用于Java5+)

你若有幸在使用Java5 或Java 6,那么你可以使用強(qiáng)類型集合(支持泛型)。比如,聲明一個(gè)只能包含String類型元素的Collection。假若使用Spring來給bean注入強(qiáng)類型的Collection,那就可以利用Spring的類型轉(zhuǎn)換能,當(dāng)向強(qiáng)類型Collection中添加元素前,這些元素將被轉(zhuǎn)換。

public class Foo {
                
    private Map<String, Float> accounts;
    
    public void setAccounts(Map<String, Float> accounts) {
        this.accounts = accounts;
    }
}
<beans>
    <bean id="foo" class="x.y.Foo">
        <property name="accounts">
            <map>
                <entry key="one" value="9.99"/>
                <entry key="two" value="2.75"/>
                <entry key="six" value="3.99"/>
            </map>
        </property>
    </bean>
</beans>

foobean的accounts屬性被注入之前,通過反射,利用強(qiáng)類型Map<String, Float>的泛型信息,Spring的底層類型轉(zhuǎn)換機(jī)制將會(huì)把各種value元素值轉(zhuǎn)換為Float類型,因此字符串9.99、2.753.99就會(huì)被轉(zhuǎn)換為實(shí)際的Float類型。

3.3.2.5.?Nulls

<null/>用于處理null值。Spring會(huì)把屬性的空參數(shù)當(dāng)作空字符串處理。以下的xml片斷將email屬性設(shè)為空字符串

<bean class="ExampleBean">
  <property name="email"><value/></property>
</bean>

這等同于Java代碼: exampleBean.setEmail("")。 而null值則可以使用<null>元素可用來表示。例如:

<bean class="ExampleBean">
  <property name="email"><null/></property>
</bean>

上述的配置等同于Java代碼:exampleBean.setEmail(null)。

3.3.2.6.?XML配置文件的簡(jiǎn)寫及其他

配置元數(shù)據(jù)冗長(zhǎng)不是什么好事情,因此我們將通過下面的方式來對(duì)配置進(jìn)行“減肥”,第一種做法就是通過使用<property/>來定義值和對(duì)其他bean的引用,另一個(gè)做法就是采用不同的屬性定義格式。

3.3.2.6.1.?XML-based configuration metadata shortcuts

<property/>、<constructor-arg/><entry/>元素都支持value屬性(attribute),它可以用來替代內(nèi)嵌的<value/>元素。因而,以下的代碼:

<property name="myProperty">
  <value>hello</value>
</property>
<constructor-arg>
  <value>hello</value>
</constructor-arg>
<entry key="myKey">
  <value>hello</value>
</entry>

等同于:

<property name="myProperty" value="hello"/>
<constructor-arg value="hello"/>
<entry key="myKey" value="hello"/>

The <property/> and <constructor-arg/> elements support a similar shortcut 'ref' attribute which may be used instead of a full nested <ref/> element. Therefore, the following:

<property/><constructor-arg/>支持類似ref的簡(jiǎn)寫屬性,它可用來替代整個(gè)內(nèi)嵌的<ref/>元素。因而,以下的代碼:

<property name="myProperty">
  <ref bean="myBean">
</property>
<constructor-arg>
  <ref bean="myBean">
</constructor-arg>

等同于:

<property name="myProperty" ref="myBean"/>
<constructor-arg ref="myBean"/>

注意,盡管存在等同于<ref bean="xxx"> 元素的簡(jiǎn)寫形式,但并沒有<ref local="xxx">的簡(jiǎn)寫形式,為了對(duì)當(dāng)前xml中bean的引用,你只能使用完整的形式。

最后,map中entry元素的簡(jiǎn)寫形式為key/key-refvalue /value-ref屬性,因而,以下的代碼:

<entry>
  <key>
    <ref bean="myKeyBean" />
  </key>
  <ref bean="myValueBean" />
</entry>

等同于:

<entry key-ref="myKeyBean" value-ref="myValueBean"/>

再次強(qiáng)調(diào),只有<ref bean="xxx">元素的簡(jiǎn)寫形式,沒有<ref local="xxx">的簡(jiǎn)寫形式。

3.3.2.6.2.?使用p名稱空間配置屬性

給XML配置文件"減肥"的另一個(gè)選擇就是使用p名稱空間,從 2.0開始,Spring支持使用名稱空間的可擴(kuò)展配置格式。這些名稱空間都是基于一種XML Schema定義。事實(shí)上,我們所看到的所有bean的配置格式都是基于一個(gè) XML Schema文檔。

特定的名稱空間并不需要定義在一個(gè)XSD文件中,它只在Spring內(nèi)核中存在。我們所說的p名稱空間就是這樣,它不需要一個(gè)schema定義,與我們前面采用<property/>元素定義bean的屬性不同的是,當(dāng)我們采用了p名稱空間,我們就可以在bean元素中使用屬性(attribute)來描述bean的property值。

下面的兩段XML配置文件中都是用來定義同一個(gè)bean:一個(gè)采用的是標(biāo)準(zhǔn)的XML格式,一個(gè)是采用p名稱空間。

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    
    <bean name="classic" class="com.example.ExampleBean">
        <property name="email" value="foo@bar.com/>
    </bean>
    
    <bean name="p-namespace" class="com.example.ExampleBean"
          p:email="foo@bar.com"/>
</beans>

從上面的bean定義中,我們采用p名稱空間的方式包含了一個(gè)叫email的屬性,而Spring會(huì)知道我們的bean包含了一個(gè)屬性(property)定義。我們前面說了,p名稱空間是不需要schema定義的,因此屬性(attribute)的名字就是你bean的property的名字。

This next example includes two more bean definitions that both have a reference to another bean:

下面的例子包含了兩個(gè)bean定義,它們都引用了另一個(gè)bean

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    
    <bean name="john-classic" class="com.example.Person">
        <property name="name" value="John Doe"/>
        <property name="spouse" ref="jane"/>
    </bean>

    <bean name="john-modern" 
        class="com.example.Person"
        p:name="John Doe"
        p:spouse-ref="jane"/>

    <bean name="jane" class="com.example.Person">
        <property name="name" value="Jane Doe"/>
    </bean>
</beans>

As you can see, this example doesn't only include a property value using the p-namespace, but also uses a special format to declare property references. Whereas the first bean definition uses <property name="spouse" ref="jane"/> to create a reference from bean john to bean jane, the second bean definition uses p:spouse-ref="jane" as an attribute to do the exact same thing. In this case 'spouse' is the property name whereas the '-ref' part indicates that this is not a straight value but rather a reference to another bean.

上面的例子不僅使用p名稱空間包含了一個(gè)屬性(property)值,而且使用了一個(gè)特殊的格式聲明了一個(gè)屬性引用。在第一個(gè)bean定義中使用了<property name="spouse" ref="jane"/>來建立beanjohn到beanjane的引用,而第二個(gè)bean定義則采用p:spouse-ref="jane"屬性(attribute)的方式達(dá)到了同樣的目的。在這個(gè)例子中,"spouse"是屬性(property)名,而"-ref“則用來說明該屬性不是一個(gè)具體的值而是對(duì)另外一個(gè)bean的引用。

注意

需要注意的是,p名稱空間沒有標(biāo)準(zhǔn)的XML格式定義靈活,比如說,bean的屬性名是以Ref結(jié)尾的,那么采用p名稱空間定義就會(huì)導(dǎo)致沖突,而采用標(biāo)準(zhǔn)的XML格式定義則不會(huì)出現(xiàn)這種問題。這里我們提醒大家在項(xiàng)目中還是仔細(xì)權(quán)衡來決定到底采用那種方式,同時(shí)也可以在團(tuán)隊(duì)成員都理解不同的定義方式的基礎(chǔ)上,在項(xiàng)目中根據(jù)需要同時(shí)選擇三種定義方式。

3.3.2.7.?組合屬性名稱

當(dāng)設(shè)置bean的組合屬性時(shí),除了最后一個(gè)屬性外,只要其他屬性值不為null,組合或嵌套屬性名是完全合法的。例如,下面bean的定義:

<bean id="foo" class="foo.Bar">
  <property name="fred.bob.sammy" value="123" />
</bean>

foo bean有個(gè)fred屬性,此屬性有個(gè)bob屬性,而bob屬性又有個(gè)sammy屬性,最后把sammy屬性設(shè)置為123。為了讓此定義能工作, foofred屬性及fredbob屬性在bean被構(gòu)造后都必須非空,否則將拋出NullPointerException異常。

3.3.3.?使用depends-on

多數(shù)情況下,一個(gè)bean對(duì)另一個(gè)bean的依賴最簡(jiǎn)單的做法就是將一個(gè)bean設(shè)置為另外一個(gè)bean的屬性。在xml配置文件中最常見的就是使用 <ref/>元素。在少數(shù)情況下,有時(shí)候bean之間的依賴關(guān)系并不是那么的直接(例如,當(dāng)類中的靜態(tài)塊的初始化被時(shí),如數(shù)據(jù)庫(kù)驅(qū)動(dòng)的注冊(cè))。depends-on屬性可以用于當(dāng)前bean初始化之前顯式地強(qiáng)制一個(gè)或多個(gè)bean被初始化。下面的例子中使用了depends-on屬性來指定一個(gè)bean的依賴。

<bean id="beanOne" class="ExampleBean" depends-on="manager"/>

<bean id="manager" class="ManagerBean" />

若需要表達(dá)對(duì)多個(gè)bean的依賴,可以在'depends-on'中將指定的多個(gè)bean名字用分隔符進(jìn)行分隔,分隔符可以是逗號(hào)、空格及分號(hào)等。下面的例子中使用了'depends-on'來表達(dá)對(duì)多個(gè)bean的依賴。

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
  <property name="manager" ref="manager" />
</bean>

<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />

注意

depends-on”屬性不僅用來指定初始化時(shí)的依賴,同時(shí)也用來指定相應(yīng)的銷毀時(shí)的依賴(該依賴只針對(duì)singletonbean)。depends-on屬性中指定的依賴bean會(huì)在相關(guān)bean銷毀之前被銷毀,從而可以讓用戶控制銷毀順序。

3.3.4.?延遲初始化bean

ApplicationContext實(shí)現(xiàn)的默認(rèn)行為就是在啟動(dòng)時(shí)將所有singleton bean提前進(jìn)行實(shí)例化。提前實(shí)例化意味著作為初始化過程的一部分,ApplicationContext實(shí)例會(huì)創(chuàng)建并配置所有的singleton bean。通常情況下這是件好事,因?yàn)檫@樣在配置中的任何錯(cuò)誤就會(huì)即刻被發(fā)現(xiàn)(否則的話可能要花幾個(gè)小時(shí)甚至幾天)。

有時(shí)候這種默認(rèn)處理可能并不是你想要的。如果你不想讓一個(gè)singleton bean在ApplicationContext初始化時(shí)被提前實(shí)例化,那么可以將bean設(shè)置為延遲實(shí)例化。一個(gè)延遲初始化bean將告訴IoC 容器是在啟動(dòng)時(shí)還是在第一次被用到時(shí)實(shí)例化。

在XML配置文件中,延遲初始化將通過<bean/>元素中的lazy-init屬性來進(jìn)行控制。例如:

<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>

<bean name="not.lazy" class="com.foo.AnotherBean"/>

當(dāng)ApplicationContext實(shí)現(xiàn)加載上述配置時(shí),設(shè)置為lazy的bean將不會(huì)ApplicationContext啟動(dòng)時(shí)提前被實(shí)例化,而not.lazy卻會(huì)被提前實(shí)例化。

需要說明的是,如果一個(gè)bean被設(shè)置為延遲初始化,而另一個(gè)非延遲初始化的singleton bean依賴于它,那么當(dāng)ApplicationContext提前實(shí)例化singleton bean時(shí),它必須也確保所有上述singleton 依賴bean也被預(yù)先初始化,當(dāng)然也包括設(shè)置為延遲實(shí)例化的bean。因此,如果Ioc容器在啟動(dòng)的時(shí)候創(chuàng)建了那些設(shè)置為延遲實(shí)例化的bean的實(shí)例,你也不要覺得奇怪,因?yàn)槟切┭舆t初始化的bean可能在配置的某個(gè)地方被注入到了一個(gè)非延遲初始化singleton bean里面。

在容器層次上通過在<beans/>元素上使用'default-lazy-init'屬性來控制延遲初始化也是可能的。如下面的配置:

<beans default-lazy-init="true">
    <!-- no beans will be pre-instantiated... -->
</beans>

3.3.5.?自動(dòng)裝配(autowire)協(xié)作者

Spring IoC容器可以自動(dòng)裝配(autowire)相互協(xié)作bean之間的關(guān)聯(lián)關(guān)系。因此,如果可能的話,可以自動(dòng)讓Spring通過檢查BeanFactory中的內(nèi)容,來替我們指定bean的協(xié)作者(其他被依賴的bean)。autowire一共有五種類型。由于autowire可以針對(duì)單個(gè)bean進(jìn)行設(shè)置,因此可以讓有些bean使用autowire,有些bean不采用。autowire的方便之處在減少或者消除屬性或構(gòu)造器參數(shù)的設(shè)置,這樣可以給我們的配置文件減減肥![2] 在xml配置文件中,可以在<bean/>元素中使用autowire屬性指定:

表?3.2.?Autowiring modes

模式 說明
no ?
byName

根據(jù)屬性名自動(dòng)裝配。此選項(xiàng)將檢查容器并根據(jù)名字查找與屬性完全一致的bean,并將其與屬性自動(dòng)裝配。例如,在bean定義中將autowire設(shè)置為by name,而該bean包含master屬性(同時(shí)提供setMaster(..)方法),Spring就會(huì)查找名為master的bean定義,并用它來裝配給master屬性。

byType

如果容器中存在一個(gè)與指定屬性類型相同的bean,那么將與該屬性自動(dòng)裝配。如果存在多個(gè)該類型的bean,那么將會(huì)拋出異常,并指出不能使用byType方式進(jìn)行自動(dòng)裝配。若沒有找到相匹配的bean,則什么事都不發(fā)生,屬性也不會(huì)被設(shè)置。如果你不希望這樣,那么可以通過設(shè)置dependency-check="objects"讓Spring拋出異常。

constructor

byType的方式類似,不同之處在于它應(yīng)用于構(gòu)造器參數(shù)。如果在容器中沒有找到與構(gòu)造器參數(shù)類型一致的bean,那么將會(huì)拋出異常。

autodetect

通過bean類的自省機(jī)制(introspection)來決定是使用constructor還是byType方式進(jìn)行自動(dòng)裝配。如果發(fā)現(xiàn)默認(rèn)的構(gòu)造器,那么將使用byType方式。


如果直接使用propertyconstructor-arg注入依賴的話,那么將總是覆蓋自動(dòng)裝配。而且目前也不支持簡(jiǎn)單類型的自動(dòng)裝配,這里所說的簡(jiǎn)單類型包括基本類型、String、Class以及簡(jiǎn)單類型的數(shù)組(這一點(diǎn)已經(jīng)被設(shè)計(jì),將考慮作為一個(gè)功能提供)。byTypeconstructor自動(dòng)裝配模式也可用于數(shù)組和指定類型的集合。在這種情況下容器中的所有匹配的自動(dòng)裝配對(duì)象將被用于滿足各種依賴。對(duì)于key值類型為 String的強(qiáng)類型Map也可以被自動(dòng)裝配。一個(gè)自動(dòng)裝配的Map的value值將由所匹配類型的bean所填充。而Map的key值則是相應(yīng)的bean的名字。

自動(dòng)裝配還可以與依賴檢查結(jié)合使用,這樣依賴檢查將在自動(dòng)裝配完成之后被執(zhí)行。

理解自動(dòng)裝配的優(yōu)缺點(diǎn)是很重要的。其中優(yōu)點(diǎn)包括:

  • 自動(dòng)裝配能顯著減少配置的數(shù)量。不過,采用bean模板(見這里)也可以達(dá)到同樣的目的。

  • 自動(dòng)裝配可以使配置與java代碼同步更新。例如,如果你需要給一個(gè)java類增加一個(gè)依賴,那么該依賴將被自動(dòng)實(shí)現(xiàn)而不需要修改配置。因此強(qiáng)烈推薦在開發(fā)過程中采用自動(dòng)裝配,而在系統(tǒng)趨于穩(wěn)定的時(shí)候改為顯式裝配的方式。

自動(dòng)裝配的一些缺點(diǎn):

  • 盡管自動(dòng)裝配比顯式裝配更神奇,但是,正如上面所提到的,Spring會(huì)盡量避免在裝配不明確的時(shí)候進(jìn)行猜測(cè),因?yàn)檠b配不明確可能出現(xiàn)難以預(yù)料的結(jié)果,而且Spring所管理的對(duì)象之間的關(guān)聯(lián)關(guān)系也不再能清晰的進(jìn)行文檔化。

  • 對(duì)于那些根據(jù)Spring配置文件生成文檔的工具來說,自動(dòng)裝配將會(huì)使這些工具沒法生成依賴信息。

另一個(gè)問題需要注意的是,當(dāng)根據(jù)類型進(jìn)行自動(dòng)裝配的時(shí)候,容器中可能存在多個(gè)bean定義跟自動(dòng)裝配的setter方法和構(gòu)造器參數(shù)類型匹配。雖然對(duì)于數(shù)組、集合以及Map,不存在這個(gè)問題,但是對(duì)于單值依賴來說,就會(huì)存在模棱兩可的問題。如果bean定義不唯一,裝配時(shí)就會(huì)拋出異常,面對(duì)這種場(chǎng)景我們有幾個(gè)方案進(jìn)行選擇:第一個(gè)方案就是棄自動(dòng)裝配而改用顯式裝配;第二個(gè)方案就是在bean定義中通過設(shè)置'autowire-candidate'屬性為'false'來將該bean排除在自動(dòng)裝配候選名單之外(詳情見接下來的章節(jié));第三個(gè)方案是通過在bean定義中設(shè)置'primary'屬性為'true'來將該bean設(shè)置為首選自動(dòng)裝配bean。最后,對(duì)于使用Java 5的用戶來說,可能會(huì)使用注解的形式來配置bean,關(guān)于這方面的內(nèi)容可見第?3.11?節(jié) “基于注解(Annotation-based)的配置”。

但決定是否使用自動(dòng)裝配式時(shí),沒有絕對(duì)的對(duì)錯(cuò)??紤]項(xiàng)目的實(shí)際是最好的辦法。比如項(xiàng)目通常不使用自動(dòng)裝配,那么使用它來僅僅裝配2個(gè)bean定義是很讓人困惑的。

3.3.5.1.?將bean排除在自動(dòng)裝配之外

你也可以針對(duì)單個(gè)bean設(shè)置其是否為被自動(dòng)裝配對(duì)象。當(dāng)采用XML格式配置bean時(shí),<bean/>元素的 autowire-candidate屬性可被設(shè)為false,這樣容器在查找自動(dòng)裝配對(duì)象時(shí)將不考慮該bean。

另一個(gè)做法就是使用對(duì)bean名字進(jìn)行模式匹配來對(duì)自動(dòng)裝配進(jìn)行限制。其做法是在<beans/>元素的'default-autowire-candidates'屬性中進(jìn)行設(shè)置。比如,將自動(dòng)裝配限制在名字以'Repository'結(jié)尾的bean,那么可以設(shè)置為"*Repository“。對(duì)于多個(gè)匹配模式則可以使用逗號(hào)進(jìn)行分隔。注意,如果在bean定義中的'autowire-candidate'屬性顯式的設(shè)置為'true''false',那么該容器在自動(dòng)裝配的時(shí)候優(yōu)先采用該屬性的設(shè)置,而模式匹配將不起作用。

對(duì)于那些從來就不會(huì)被其它bean采用自動(dòng)裝配的方式來注入的bean而言,這是有用的。不過這并不意味著被排除的bean自己就不能使用自動(dòng)裝配來注入其他bean,它是可以的,或者更準(zhǔn)確地說,應(yīng)該是它不會(huì)被考慮作為其他bean自動(dòng)裝配的候選者。

3.3.6.?依賴檢查

Spring除了能對(duì)容器中bean的依賴設(shè)置進(jìn)行檢查外,還可以檢查bean定義中實(shí)際屬性值的設(shè)置,當(dāng)然也包括采用自動(dòng)裝配方式設(shè)置屬性值的檢查。

當(dāng)需要確保bean的所有屬性值(或者屬性類型)被正確設(shè)置的時(shí)候,那么這個(gè)功能會(huì)非常有用。當(dāng)然,在很多情況下,bean類的某些屬性會(huì)具有默認(rèn)值,或者有些屬性并不會(huì)在所有場(chǎng)景下使用,因此這項(xiàng)功能會(huì)存在一定的局限性。就像自動(dòng)裝配一樣,依賴檢查也可以針對(duì)每一個(gè)bean進(jìn)行設(shè)置。依賴檢查默認(rèn)為not,它有幾種不同的使用模式,在xml配置文件中,可以在bean定義中為dependency-check屬性使用以下幾種值:

表?3.3.?依賴檢查方式

模式 說明
none

沒有依賴檢查,如果bean的屬性沒有值的話可以不用設(shè)置。

simple

對(duì)于原始類型及集合(除協(xié)作者外的一切東西)執(zhí)行依賴檢查

object

僅對(duì)協(xié)作者執(zhí)行依賴檢查

all

對(duì)協(xié)作者,原始類型及集合執(zhí)行依賴檢查


假若你在使用Java 5,可以采用源代碼級(jí)的注解(annotations)來進(jìn)行配置,關(guān)于這方面的內(nèi)容可以在第?25.3.1?節(jié) “@Required”這一節(jié)找到。

3.3.7.?方法注入

在大部分情況下,容器中的bean都是singleton類型的。如果一個(gè)singleton bean要引用另外一個(gè)singleton bean,或者一個(gè)非singleton bean要引用另外一個(gè)非singleton bean時(shí),通常情況下將一個(gè)bean定義為另一個(gè)bean的property值就可以了。不過對(duì)于具有不同生命周期的bean來說這樣做就會(huì)有問題了,比如在調(diào)用一個(gè)singleton類型bean A的某個(gè)方法時(shí),需要引用另一個(gè)非singleton(prototype)類型的bean B,對(duì)于bean A來說,容器只會(huì)創(chuàng)建一次,這樣就沒法在需要的時(shí)候每次讓容器為bean A提供一個(gè)新的的bean B實(shí)例。

上述問題的一個(gè)解決辦法就是放棄控制反轉(zhuǎn)。通過實(shí)現(xiàn)BeanFactoryAware接口(見這里)讓bean A能夠感知bean 容器,并且在需要的時(shí)候通過使用getBean("B")方式(見這里)向容器請(qǐng)求一個(gè)新的bean B實(shí)例??聪孪旅孢@個(gè)例子,其中故意使用了這種方法:

// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;

// lots of Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;

public class CommandManager implements BeanFactoryAware {

   private BeanFactory beanFactory;

   public Object process(Map commandState) {
      // grab a new instance of the appropriate Command
      Command command = createCommand();
      // set the state on the (hopefully brand new) Command instance
      command.setState(commandState);
      return command.execute();
   }

   // the Command returned here could be an implementation that executes asynchronously, or whatever
   protected Command createCommand() {
      return (Command) this.beanFactory.getBean("command"); // notice the Spring API dependency
   }

   public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
      this.beanFactory = beanFactory;
   }
}

上面的例子顯然不是最好的,因?yàn)闃I(yè)務(wù)代碼和Spring Framework產(chǎn)生了耦合。方法注入,作為Spring IoC容器的一種高級(jí)特性,可以以一種干凈的方法來處理這種情況。

3.3.7.1.?Lookup方法注入

Lookup方法注入利用了容器的覆蓋受容器管理的bean方法的能力,從而返回指定名字的bean實(shí)例。在上述場(chǎng)景中,Lookup方法注入適用于原型bean。Lookup方法注入的內(nèi)部機(jī)制是Spring利用了CGLIB庫(kù)在運(yùn)行時(shí)生成二進(jìn)制代碼功能,通過動(dòng)態(tài)創(chuàng)建Lookup方法bean的子類而達(dá)到復(fù)寫Lookup方法的目的。

如果你看下上個(gè)代碼段中的代碼(CommandManager類),Spring容器動(dòng)態(tài)覆蓋了createCommand()方法的實(shí)現(xiàn)。你的CommandManager類不會(huì)有一點(diǎn)對(duì)Spring的依賴,在下面這個(gè)例子中也是一樣的:

package fiona.apple;

// no more Spring imports! 

public abstract class CommandManager {

   public Object process(Object commandState) {
      // grab a new instance of the appropriate Command interface
      Command command = createCommand();
      // set the state on the (hopefully brand new) Command instance
      command.setState(commandState);
      return command.execute();
   }

    // okay... but where is the implementation of this method?
   protected abstract Command createCommand();
}

在包含被注入方法的客戶類中(此處是CommandManager),此方法的定義必須按以下形式進(jìn)行:

<public|protected> [abstract] <return-type> theMethodName(no-arguments);

如果方法是抽象的,動(dòng)態(tài)生成的子類會(huì)實(shí)現(xiàn)該方法。否則,動(dòng)態(tài)生成的子類會(huì)覆蓋類里的具體方法。讓我們來看個(gè)例子:

<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="command" class="fiona.apple.AsyncCommand" scope="prototype">
  <!-- inject dependencies here as required -->
</bean>

<!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
  <lookup-method name="createCommand" bean="command"/>
</bean>

在上面的例子中,標(biāo)識(shí)為commandManager的bean在需要一個(gè)新的command bean實(shí)例時(shí),會(huì)調(diào)用createCommand方法。重要的一點(diǎn)是,必須將command部署為prototype。當(dāng)然也可以指定為singleton,如果是這樣的話,那么每次將返回相同的command bean實(shí)例!

請(qǐng)注意,為了讓這個(gè)動(dòng)態(tài)子類得以正常工作,需要把CGLIB的jar文件放在classpath里。另外,Spring容器要子類化的類不能是final的,要覆蓋的方法也不能是final的。同樣的,要測(cè)試一個(gè)包含抽象方法的類也稍微有些不同,你需要自己編寫它的子類提供該抽象方法的樁實(shí)現(xiàn)。最后,作為方法注入目標(biāo)的bean不能是序列化的(serialized)。

提示

有興趣的讀者也許已經(jīng)發(fā)現(xiàn)ServiceLocatorFactoryBean(在org.springframework.beans.factory.config包里)的用法和ObjectFactoryCreatingFactoryBean的有些相似,不同的是它允許你指定自己的lookup接口,不一定非要用Spring的lookup接口,比如ObjectFactory。要詳細(xì)了解這種方法請(qǐng)參考ServiceLocatorFactoryBean的Javadocs(它的確減少了對(duì)Spring的耦合)。

3.3.7.2.?自定義方法的替代方案

比起Lookup 方法注入來,還有一種很少用到的方法注入形式,該注入能使用bean的另一個(gè)方法實(shí)現(xiàn)去替換自定義的方法。除非你真的需要該功能,否則可以略過本節(jié)。

當(dāng)使用基于XML配置元數(shù)據(jù)文件時(shí),可以在bean定義中使用replaced-method元素來達(dá)到用另一個(gè)方法來取代已有方法的目的??紤]下面的類,我們將覆蓋computeValue方法:

public class MyValueCalculator {

  public String computeValue(String input) {
    // some real code...
  }

  // some other methods...

}

實(shí)現(xiàn)org.springframework.beans.factory.support.MethodReplacer接口的類提供了新的方法定義。


public class ReplacementComputeValue implements MethodReplacer {

    public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
        // get the input value, work with it, and return a computed result
        String input = (String) args[0];
        ... 
        return ...;
    }
}

下面的bean定義中指定了要配置的原始類和將要覆寫的方法:

<bean id="myValueCalculator class="x.y.z.MyValueCalculator">
  <!-- arbitrary method replacement -->
  <replaced-method name="computeValue" replacer="replacementComputeValue">
    <arg-type>String</arg-type>
  </replaced-method>
</bean>

<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>

<replaced-method/>元素內(nèi)可包含一個(gè)或多個(gè)<arg-type/>元素,這些元素用來標(biāo)明被覆寫的方法簽名。只有被覆寫(override)的方法存在重載(overload)的情況(同名的多個(gè)方法變體)才會(huì)使用方法簽名。為了方便,參數(shù)的類型字符串可以采用全限定類名的簡(jiǎn)寫。例如,下面的字符串都表示參數(shù)類型為java.lang.String

    java.lang.String
    String
    Str

參數(shù)的個(gè)數(shù)通常足夠用來區(qū)別每個(gè)可能的選擇,這個(gè)捷徑能減少很多鍵盤輸入的工作,它允許你只輸入最短的匹配參數(shù)類型的字符串。



[2] 參見第?3.3.1?節(jié) “注入依賴”

前の記事: 次の記事: