Spring基礎知識1

參考W3C Spring教程

Spring致力于J2EE應用的各種解決方案顾腊,而不僅僅專注于某一層解決方案粤铭。可以說Spring是企業(yè)應用開發(fā)的“一站式”選擇杂靶, Spring貫穿于表現(xiàn)層梆惯、業(yè)務層、持久層吗垮,然而Spring并不想取代那些已經(jīng)有的框架垛吗,而是以高度的開放性,與這些已有的框架進行整合烁登。

Spring目標:

  • 1.讓現(xiàn)有的技術(shù)更容易使用
    Spring堅持一個原則:不重新造輪子怯屉。
  • 2.促進良好的編程習慣

1.概述

  • Spring 是最受歡迎的企業(yè)級 Java 應用程序開發(fā)框架,數(shù)以百萬的來自世界各地的開發(fā)人員使用 Spring 框架來創(chuàng)建性能好饵沧、易于測試锨络、可重用的代碼。
    Spring 框架的核心特性是可以用于開發(fā)任何 Java 應用程序狼牺,但是在 Java EE 平臺上構(gòu)建 web 應用程序是需要擴展的羡儿。 Spring 框架的目標是使 J2EE 開發(fā)變得更容易使用,通過啟用基于 POJO 編程模型來促進良好的編程實踐锁右。
  • 依賴注入
    Spring 最認同的技術(shù)是控制反轉(zhuǎn)的依賴注入(DI)模式失受⊙忍控制反轉(zhuǎn)(IoC)是一個通用的概念咏瑟,它可以用許多不同的方式去表達拂到,依賴注入僅僅是控制反轉(zhuǎn)的一個具體的例子。
    當編寫一個復雜的 Java 應用程序時码泞,應用程序類應該盡可能的獨立于其他的 Java 類來增加這些類可重用可能性兄旬,當進行單元測試時,可以使它們獨立于其他類進行測試余寥。依賴注入(或者有時被稱為配線)有助于將這些類粘合在一起领铐,并且在同一時間讓它們保持獨立。
    到底什么是依賴注入宋舷?讓我們將這兩個詞分開來看一看绪撵。這里將依賴關(guān)系部分轉(zhuǎn)化為兩個類之間的關(guān)聯(lián)。例如祝蝠,類 A 依賴于類 B∫粽現(xiàn)在,讓我們看一看第二部分绎狭,注入细溅。所有這一切都意味著類 B 將通過 IoC 被注入到類 A 中。
  • AOP
    Spring 框架的一個關(guān)鍵組件是面向切面的程序設計(AOP)框架儡嘶。一個程序中跨越多個點的功能被稱為橫切關(guān)注點喇聊,這些橫切關(guān)注點在概念上獨立于應用程序的業(yè)務邏輯。有各種各樣常見的很好的關(guān)于方面的例子蹦狂,比如日志記錄誓篱、聲明性事務、安全性凯楔,和緩存等等燕鸽。
    在 OOP 中模塊化的關(guān)鍵單元是類,而在 AOP 中模塊化的關(guān)鍵單元是方面啼辣。AOP 幫助你將橫切關(guān)注點從它們所影響的對象中分離出來啊研,然而依賴注入幫助你將你的應用程序?qū)ο髲谋舜酥蟹蛛x出來。

2鸥拧、關(guān)鍵概念

2.1 POJO編程模型

  • 簡單的java對象(plain old java objects)党远。旨在簡化java應用程序(特別是企業(yè)級)的編碼、測試以及部署等階段富弦。
  • EJB編程模型存在的問題
    (1)它提供了一種與運行時平臺相結(jié)合的分布式業(yè)務組建模型沟娱,運行時該平臺提供了執(zhí)行EJB組件所需要的所有中間件服務。
    (2)可測試性艱難腕柜。JNDI查找是依賴注入的早期形式济似,但由于其拉式性質(zhì)矫废,使得在單元測試期間使對組件隔離變得非常困難(因為對JNDI上下文的依賴)。
    (3)部署耗時且易于出錯砰蠢。
    (4)EJB編程模型趨向于將開發(fā)人員的風格轉(zhuǎn)向面向過程程序設計風格蓖扑。
  • POJO編程模型的優(yōu)點
    (1)編寫應用程序類非常快速和簡單台舱。因為編寫的類不需要依賴任何特定的API律杠,不需要視線任何特定的接口或擴展自某一特定的框架類。
    (2)以面向?qū)ο蟮姆绞絹砭幊叹和铮毮P吞幚順I(yè)務邏輯柜去,可以讓行為處理更加豐富

2.2 輕量級容器和IOC

  • 1.輕量級容器
    (1)容器(container):在該環(huán)境中,所有組件都被創(chuàng)建和裝配拆宛,并提供了所需的中間件服務嗓奢。
    (2)Java EE平臺提供了多個這樣的容器,每一個專門容器為應用程序的一個特定層提供服務浑厚。
    (3)Spring container也是一個容器股耽,在這個里面,應用程序被裝配瞻颂,彼此創(chuàng)建豺谈,并以一種輕量級的方式提供中間件服務。
    (4)容器可以向環(huán)境提供所被預期的服務:
    ①生命周期管理
    ②依賴解析
    ③組件查找
    ④應用程序配置
    其余更優(yōu)預期的服務:事務管理贡这、安全性茬末、線程管理、對象和資源池盖矫、對組件的遠程訪問丽惭、通過JMX之類的API管理組件、容器的擴展和定制辈双。
    (5)一個輕量級的容器(lightweight container)包含上述所有功能责掏,同時不依賴這些API編寫應用程序代碼。輕量級容器沒有入侵性湃望,啟動非郴怀模快,不需要將其部署到一個功能齊全的Java EE應用程序服務器上就可以使用這些服務证芭。
    Spring application framework是最著名的輕量級容器之一瞳浦。

  • 2.控制反轉(zhuǎn)
    (1)容器及其管理的組件所提供的最重要的好處是可插拔的體系結(jié)構(gòu)。
    (2)組件實現(xiàn)接口废士,用來訪問其他組件提供的服務叫潦。
    (3)容器創(chuàng)建組件及所依賴的服務,并將之裝配在一起官硝。
    (4)組件類中矗蕊,在運行時由容器實例將依賴組件注入組件短蜕。
    對依賴項的控制由組件轉(zhuǎn)到容器,這種模式就成為反轉(zhuǎn)控制inversion of controll傻咖,簡稱IOC朋魔。
    IOC是容器的基本功能之一,主要有兩種形式:
    (1)依賴查找(dependence lookup)
    在依賴查找中没龙,容器向管理組件提供的回調(diào)方法铺厨,被組件用來與容器進行交互并顯式的獲取它們的依賴項缎玫。
    這種情況下硬纤,通常使用一個查找上下文來訪問依賴及容器管理的資源。
    J2EE環(huán)境中赃磨,通過查找上下文即JNDI上下文筝家,訪問EJB組件及其他資源,如JDBCDataSource和JMS ConnectionFactory邻辉。
    (2)依賴注入(dependence injection)
    在依賴注入中溪王,組件提供了合適構(gòu)造函數(shù)和setter方法,以便容器可以注入依賴組件值骇。
    隨著Spring application framework 和其他輕量級IOC框架出現(xiàn)莹菱,容器根據(jù)自己的配置機制來確定組件實例化和需要的依賴組件。
    J2EE向Java EE演化的過程中吱瘩,使用JDNI進行的顯式依賴查找被逐步轉(zhuǎn)變?yōu)殡[式依賴注入方法道伟。

2.3 依賴注入DI

  • 1、基本原則:應用程序?qū)ο蟛粦撠撠煵檎宜鼈兯蕾嚨馁Y源或者協(xié)作者使碾,而是由IOC容器處理對象創(chuàng)建和依賴注入蜜徽,從而導致資源查找外部化,從應用程序代碼轉(zhuǎn)移到容器票摇。

  • 2拘鞋、給系統(tǒng)帶來的好處:
    (1)完全刪除應用程序中的查找邏輯代碼,依賴項以可插拔的方式注入到目標組件中矢门。
    (2)組件不需要知道依賴項的位置或類盆色,很容易進行組件的單元測試。
    (3)對容器API沒有任何的依賴祟剔。
    (4)不需要實現(xiàn)任何特殊接口隔躲。

  • 3、兩種依賴注入方法
    (1)構(gòu)造函數(shù)注入
    (2)setter注入
    一個好的容器可以同時支持這兩個種方法峡扩,并允許混合使用蹭越。

  • 4、setter注入
    (1)當一個對象被實例化之后就會馬上調(diào)用setter方法教届。
    ①該注入在組件的創(chuàng)建和初始化階段發(fā)生响鹃,并且在處理業(yè)務方法調(diào)用之前完成驾霜。
    ②setter方法是javabean規(guī)范的一部分。
    ③使用javabean屬性使簡單屬性外部化买置。
    (2)優(yōu)點:組件在創(chuàng)建之后可以進行重新配置粪糙。
    ①組件依賴可以在運行時更改。
    ②現(xiàn)有的類提供了getter和setter方法來訪問它們的屬性忿项。
    (3)缺點:并不是所有的依賴項都可以在使用前被注入蓉冈,從而使組件處于一種部分配置狀態(tài)。

  • 5轩触、構(gòu)造函數(shù)注入
    (1)bean可以利用構(gòu)造函數(shù)參數(shù)來表達依賴項寞酿,這樣就可以在組件創(chuàng)建期間注入依賴項。
    (2)出于線程安全的考慮脱柱,也需要使用構(gòu)造函數(shù)注入伐弹。
    (3)可以像注入構(gòu)造函數(shù)參數(shù)那樣注入簡單的屬性。
    (4)優(yōu)點
    ①保證容器中每一個被管理的組件都處于一致的狀態(tài)榨为,并在創(chuàng)建之后可立刻使用惨好。
    ②編寫的代碼量比setter注入編寫的代碼量要少一些。
    (5)缺點
    ①在組件創(chuàng)建完畢后就無法再對組件進行重新分配随闺。除非為相關(guān)屬性提供一個setter作為構(gòu)造函數(shù)參數(shù)坞生。
    ②具體繼承可能有問題计济。

3.Spring體系結(jié)構(gòu)

3.1 核心容器

核心容器由spring-core,spring-beans,spring-context逆皮,spring-context-support和spring-expression(SpEL西设,Spring表達式語言柳譬,Spring Expression Language)等模塊組成群扶,它們的細節(jié)如下:

  • spring-core模塊提供了框架的基本組成部分,包括 IoC 和依賴注入功能笨使。

  • spring-beans 模塊提供 BeanFactory卿樱,工廠模式的微妙實現(xiàn),它移除了編碼式單例的需要硫椰,并且可以把配置和依賴從實際編碼邏輯中解耦繁调。

  • context模塊建立在由core和 beans 模塊的基礎上建立起來的,它以一種類似于JNDI注冊的方式訪問對象靶草。Context模塊繼承自Bean模塊蹄胰,并且添加了國際化(比如,使用資源束)奕翔、事件傳播裕寨、資源加載和透明地創(chuàng)建上下文(比如,通過Servelet容器)等功能。Context模塊也支持Java EE的功能宾袜,比如EJB捻艳、JMX和遠程調(diào)用等。ApplicationContext接口是Context模塊的焦點庆猫。spring-context-support提供了對第三方庫集成到Spring上下文的支持认轨,比如緩存(EhCache, Guava, JCache)、郵件(JavaMail)月培、調(diào)度(CommonJ, Quartz)嘁字、模板引擎(FreeMarker, JasperReports, Velocity)等。

  • spring-expression模塊提供了強大的表達式語言杉畜,用于在運行時查詢和操作對象圖纪蜒。它是JSP2.1規(guī)范中定義的統(tǒng)一表達式語言的擴展,支持set和get屬性值寻行、屬性賦值霍掺、方法調(diào)用匾荆、訪問數(shù)組集合及索引的內(nèi)容拌蜘、邏輯算術(shù)運算、命名變量牙丽、通過名字從Spring IoC容器檢索對象简卧,還支持列表的投影、選擇以及聚合等烤芦。举娩。

3.2 數(shù)據(jù)訪問/集成

數(shù)據(jù)訪問/集成層包括 JDBC,ORM构罗,OXM铜涉,JMS 和事務處理模塊,它們的細節(jié)如下:
(注:JDBC=Java Data Base Connectivity遂唧,ORM=Object Relational Mapping芙代,OXM=Object XML Mapping,JMS=Java Message Service)

  • JDBC 模塊提供了JDBC抽象層盖彭,它消除了冗長的JDBC編碼和對數(shù)據(jù)庫供應商特定錯誤代碼的解析纹烹。

  • ORM 模塊提供了對流行的對象關(guān)系映射API的集成,包括JPA召边、JDO和Hibernate等铺呵。通過此模塊可以讓這些ORM框架和spring的其它功能整合,比如前面提及的事務管理隧熙。

  • OXM 模塊提供了對OXM實現(xiàn)的支持片挂,比如JAXB、Castor、XML Beans音念、JiBX滋将、XStream等。

  • JMS 模塊包含生產(chǎn)(produce)和消費(consume)消息的功能症昏。從Spring 4.1開始随闽,集成了spring-messaging模塊。肝谭。

  • 事務模塊為實現(xiàn)特殊接口類及所有的 POJO 支持編程式和聲明式事務管理掘宪。(注:編程式事務需要自己寫beginTransaction()、commit()攘烛、rollback()等事務管理方法魏滚,聲明式事務是通過注解或配置由spring自動處理,編程式事務粒度更細)

3.3 Web

Web 層由 Web坟漱,Web-MVC鼠次,Web-Socket 和 Web-Portlet 組成,它們的細節(jié)如下:

  • Web 模塊提供面向web的基本功能和面向web的應用上下文芋齿,比如多部分(multipart)文件上傳功能腥寇、使用Servlet監(jiān)聽器初始化IoC容器等。它還包括HTTP客戶端以及Spring遠程調(diào)用中與web相關(guān)的部分觅捆。赦役。

  • Web-MVC 模塊為web應用提供了模型視圖控制(MVC)和REST Web服務的實現(xiàn)。Spring的MVC框架可以使領(lǐng)域模型代碼和web表單完全地分離栅炒,且可以與Spring框架的其它所有功能進行集成掂摔。

  • Web-Socket 模塊為 WebSocket-based 提供了支持,而且在 web 應用程序中提供了客戶端和服務器端之間通信的兩種方式赢赊。

  • Web-Portlet 模塊提供了用于Portlet環(huán)境的MVC實現(xiàn)乙漓,并反映了spring-webmvc模塊的功能。

3.4 其他

還有其他一些重要的模塊释移,像 AOP叭披,Aspects,Instrumentation秀鞭,Web 和測試模塊趋观,它們的細節(jié)如下:

  • AOP 模塊提供了面向方面的編程實現(xiàn),允許你定義方法攔截器和切入點對代碼進行干凈地解耦锋边,從而使實現(xiàn)功能的代碼徹底的解耦出來皱坛。使用源碼級的元數(shù)據(jù),可以用類似于.Net屬性的方式合并行為信息到代碼中豆巨。

  • Aspects 模塊提供了與 AspectJ 的集成剩辟,這是一個功能強大且成熟的面向切面編程(AOP)框架。

  • Instrumentation 模塊在一定的應用服務器中提供了類 instrumentation 的支持和類加載器的實現(xiàn)。

  • Messaging 模塊為 STOMP 提供了支持作為在應用程序中 WebSocket 子協(xié)議的使用贩猎。它也支持一個注解編程模型熊户,它是為了選路和處理來自 WebSocket 客戶端的 STOMP 信息。

  • 測試模塊支持對具有 JUnit 或 TestNG 框架的 Spring 組件的測試吭服。

4.Spring IoC容器

  • Spring 容器是 Spring 框架的核心嚷堡。容器將創(chuàng)建對象,把它們連接在一起艇棕,配置它們蝌戒,并管理他們的整個生命周期從創(chuàng)建到銷毀。Spring 容器使用依賴注入(DI)來管理組成一個應用程序的組件沼琉。這些對象被稱為 Spring Beans北苟。
    通過閱讀配置元數(shù)據(jù)提供的指令,容器知道對哪些對象進行實例化打瘪,配置和組裝友鼻。配置元數(shù)據(jù)可以通過 XML,Java 注釋或 Java 代碼來表示闺骚。下圖是 Spring 如何工作的高級視圖彩扔。 Spring IoC 容器利用 Java 的 POJO 類和配置元數(shù)據(jù)來生成完全配置和可執(zhí)行的系統(tǒng)或應用程序。


  • Spring的兩種容器:
    1)Spring BeanFactory 容器
    它是最簡單的容器葛碧,給 DI 提供了基本的支持借杰,它用org.springframework.beans.factory.BeanFactory 接口來定義。BeanFactory 或者相關(guān)的接口进泼,如 BeanFactoryAware,InitializingBean纤虽,DisposableBean乳绕,在 Spring 中仍然存在具有大量的與 Spring 整合的第三方框架的反向兼容性的目的。
    2)Spring ApplicationContext 容器
    該容器添加了更多的企業(yè)特定的功能逼纸,例如從一個屬性文件中解析文本信息的能力洋措,發(fā)布應用程序事件給感興趣的事件監(jiān)聽器的能力。該容器是由 org.springframework.context.ApplicationContext 接口定義杰刽。
    ApplicationContext 容器包括 BeanFactory 容器的所有功能菠发。

4.1 Spring BeanFactory容器

  • 這是一個最簡單的容器,它主要的功能是為依賴注入 (DI) 提供支持贺嫂,這個容器接口在 org.springframework.beans.factory.BeanFactory中被定義滓鸠。 BeanFactory 和相關(guān)的接口,比如BeanFactoryAware第喳、 DisposableBean糜俗、InitializingBean,仍舊保留在 Spring 中,主要目的是向后兼容已經(jīng)存在的和那些 Spring 整合在一起的第三方框架悠抹。
    在 Spring 中珠月,有大量對 BeanFactory 接口的實現(xiàn)。其中楔敌,最常被使用的是 XmlBeanFactory 類啤挎。這個容器從一個 XML 文件中讀取配置元數(shù)據(jù),由這些元數(shù)據(jù)來生成一個被配置化的系統(tǒng)或者應用卵凑。
    在資源寶貴的移動設備或者基于 applet 的應用當中侵浸, BeanFactory 會被優(yōu)先選擇。否則氛谜,一般使用的是 ApplicationContext掏觉,除非你有更好的理由選擇 BeanFactory。
package com.tutorialspoint;
public class HelloWorld {
   private String message;
   public void setMessage(String message){
    this.message  = message;
   }
   public void getMessage(){
    System.out.println("Your Message : " + message);
   }
}

  • 測試程序
package com.tutorialspoint;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class MainApp {
   public static void main(String[] args) {
      XmlBeanFactory factory = new XmlBeanFactory
                             (new ClassPathResource("Beans.xml"));
      HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");
      obj.getMessage();
   }
}

1)第一步利用框架提供的 XmlBeanFactory() API 去生成工廠 bean 以及利用 ClassPathResource() API 去加載在路徑 CLASSPATH 下可用的 bean 配置文件值漫。XmlBeanFactory() API 負責創(chuàng)建并初始化所有的對象澳腹,即在配置文件中提到的 bean。
2)第二步利用第一步生成的 bean 工廠對象的 getBean() 方法得到所需要的 bean杨何。 這個方法通過配置文件中的 bean ID 來返回一個真正的對象酱塔,該對象最后可以用于實際的對象。一旦得到這個對象危虱,就可以利用這個對象來調(diào)用任何方法羊娃。

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

   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
       <property name="message" value="Hello World!"/>
   </bean>

</beans>

4.2 Spring ApplicationContext容器

  • Application Context 是 spring 中較高級的容器。和 BeanFactory 類似埃跷,它可以加載配置文件中定義的 bean蕊玷,將所有的 bean 集中在一起,當有請求的時候分配 bean弥雹。 另外垃帅,它增加了企業(yè)所需要的功能,比如剪勿,從屬性文件中解析文本信息和將事件傳遞給所指定的監(jiān)聽器贸诚。這個容器在 org.springframework.context.ApplicationContext interface 接口中定義。
    ApplicationContext 包含 BeanFactory 所有的功能厕吉,一般情況下酱固,相對于 BeanFactory,ApplicationContext 會更加優(yōu)秀头朱。當然运悲,BeanFactory 仍可以在輕量級應用中使用,比如移動設備或者基于 applet 的應用程序髓窜。
  • 最常被使用的 ApplicationContext 接口實現(xiàn):
    1)FileSystemXmlApplicationContext:該容器從 XML 文件中加載已被定義的 bean扇苞。在這里欺殿,你需要提供給構(gòu)造器 XML 文件的完整路徑。
    2)ClassPathXmlApplicationContext:該容器從 XML 文件中加載已被定義的 bean鳖敷。在這里脖苏,你不需要提供 XML 文件的完整路徑,只需正確配置 CLASSPATH 環(huán)境變量即可定踱,因為棍潘,容器會從 CLASSPATH 中搜索 bean 配置文件。
    3)WebXmlApplicationContext:該容器會在一個 web 應用程序的范圍內(nèi)加載在 XML 文件中已被定義的 bean崖媚。

4.3 Spring Bean定義

  • 被稱作 bean 的對象是構(gòu)成應用程序的支柱也是由 Spring IoC 容器管理的亦歉。bean 是一個被實例化,組裝畅哑,并通過 Spring IoC 容器所管理的對象肴楷。這些 bean 是由用容器提供的配置元數(shù)據(jù)創(chuàng)建的,例如荠呐,已經(jīng)在先前章節(jié)看到的赛蔫,在 XML 的表單中的 定義。
    bean 定義包含稱為配置元數(shù)據(jù)的信息:
    1)如何創(chuàng)建一個 bean
    2)bean 的生命周期的詳細信息
    3)bean 的依賴關(guān)系


  • Spring 配置元數(shù)據(jù)
    Spring IoC 容器完全由實際編寫的配置元數(shù)據(jù)的格式解耦泥张。有下面三個重要的方法把配置元數(shù)據(jù)提供給 Spring 容器:
    1)基于 XML 的配置文件呵恢。
    2)基于注解的配置
    3)基于 Java 的配置

4.4 Spring Bean作用域

  • 當在 Spring 中定義一個 bean 時,你必須聲明該 bean 的作用域的選項媚创。例如渗钉,為了強制 Spring 在每次需要時都產(chǎn)生一個新的 bean 實例,你應該聲明 bean 的作用域的屬性為 prototype钞钙。同理鳄橘,如果你想讓 Spring 在每次需要時都返回同一個bean實例,你應該聲明 bean 的作用域的屬性為 singleton歇竟。
    Spring 框架支持以下五個作用域挥唠,如果你使用 web-aware ApplicationContext 時,其中三個是可用的焕议。


  • Prototype是原型類型,它在我們創(chuàng)建容器的時候并沒有實例化弧关,而是當我們獲取bean的時候才會去創(chuàng)建一個對象盅安,而且我們每次獲取到的對象都不是同一個對象。根據(jù)經(jīng)驗世囊,對有狀態(tài)的bean應該使用prototype作用域别瞭,而對無狀態(tài)的bean則應該使用singleton作用域。

4.5 Spring Bean生命周期

  • 理解 Spring bean 的生命周期很容易株憾。當一個 bean 被實例化時蝙寨,它可能需要執(zhí)行一些初始化使它轉(zhuǎn)換成可用狀態(tài)晒衩。同樣,當 bean 不再需要墙歪,并且從容器中移除時听系,可能需要做一些清除工作。
    為了定義安裝和拆卸一個 bean虹菲,我們只要聲明帶有 init-method 和/或 destroy-method 參數(shù)的 靠胜。init-method 屬性指定一個方法,在實例化 bean 時毕源,立即調(diào)用該方法浪漠。同樣,destroy-method 指定一個方法霎褐,只有從容器中移除 bean 之后址愿,才能調(diào)用該方法。
  • 如果你在非 web 應用程序環(huán)境中使用 Spring 的 IoC 容器冻璃;例如在豐富的客戶端桌面環(huán)境中响谓;那么在 JVM 中你要注冊關(guān)閉 hook。這樣做可以確保正常關(guān)閉俱饿,為了讓所有的資源都被釋放歌粥,可以在單個 beans 上調(diào)用 destroy 方法。
   <bean id="helloWorld" 
       class="com.tutorialspoint.HelloWorld"
       init-method="init" destroy-method="destroy">
       <property name="message" value="Hello World!"/>
   </bean>

4.6 Spring Bean后置處理器

  • BeanPostProcessor 接口定義回調(diào)方法拍埠,你可以實現(xiàn)該方法來提供自己的實例化邏輯失驶,依賴解析邏輯等。你也可以在 Spring 容器通過插入一個或多個 BeanPostProcessor 的實現(xiàn)來完成實例化枣购,配置和初始化一個bean之后實現(xiàn)一些自定義邏輯回調(diào)方法嬉探。
    你可以配置多個 BeanPostProcessor接口,通過設置 BeanPostProcessor 實現(xiàn)的 Ordered 接口提供的 order 屬性來控制這些 BeanPostProcessor 接口的執(zhí)行順序棉圈。
    BeanPostProcessor 可以對 bean(或?qū)ο螅嵗M行操作涩堤,這意味著 Spring IoC 容器實例化一個 bean 實例,然后 BeanPostProcessor 接口進行它們的工作分瘾。
    ApplicationContext 會自動檢測由 BeanPostProcessor 接口的實現(xiàn)定義的 bean胎围,注冊這些 bean 為后置處理器,然后通過在容器中創(chuàng)建 bean德召,在適當?shù)臅r候調(diào)用它白魂。
package com.tutorialspoint;
public class HelloWorld {
   private String message;
   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
   public void init(){
      System.out.println("Bean is going through init.");
   }
   public void destroy(){
      System.out.println("Bean will destroy now.");
   }
}
  • 在任何 bean 的初始化的之前和之后輸入該 bean 的名稱。你可以在初始化 bean 的之前和之后實現(xiàn)更復雜的邏輯上岗,因為你有兩個訪問內(nèi)置 bean 對象的后置處理程序的方法福荸。 InitHelloWorld.java 如下:
package com.tutorialspoint;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;
public class InitHelloWorld implements BeanPostProcessor {
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("BeforeInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("AfterInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
}
package com.tutorialspoint;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      context.registerShutdownHook();
   }
}
   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld"
       init-method="init" destroy-method="destroy">
       <property name="message" value="Hello World!"/>
   </bean>

   <bean class="com.tutorialspoint.InitHelloWorld" />
  • 輸出如下:
BeforeInitialization : helloWorld
Bean is going through init.
AfterInitialization : helloWorld
Your Message : Hello World!
Bean will destroy now.

4.7 Spring Bean定義繼承

   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
      <property name="message1" value="Hello World!"/>
      <property name="message2" value="Hello Second World!"/>
   </bean>

   <bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="helloWorld">
      <property name="message1" value="Hello India!"/>
      <property name="message3" value="Namaste India!"/>
   </bean>
  • 定義模板
   <bean id="beanTeamplate" abstract="true">
      <property name="message1" value="Hello World!"/>
      <property name="message2" value="Hello Second World!"/>
      <property name="message3" value="Namaste India!"/>
   </bean>

   <bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="beanTeamplate">
      <property name="message1" value="Hello India!"/>
      <property name="message3" value="Namaste India!"/>
   </bean>

5.Spring DI

  • 每個基于應用程序的 java 都有幾個對象,這些對象一起工作來呈現(xiàn)出終端用戶所看到的工作的應用程序肴掷。當編寫一個復雜的 Java 應用程序時敬锐,應用程序類應該盡可能獨立于其他 Java 類來增加這些類重用的可能性背传,并且在做單元測試時,測試獨立于其他類的獨立性台夺。依賴注入(或有時稱為布線)有助于把這些類粘合在一起径玖,同時保持他們獨立。
  • 假設你有一個包含文本編輯器組件的應用程序谒养,并且你想要提供拼寫檢查挺狰。標準代碼看起來是這樣的:
public class TextEditor {
   private SpellChecker spellChecker;  
   public TextEditor() {
      spellChecker = new SpellChecker();
   }
}

在這里我們所做的就是創(chuàng)建一個 TextEditor 和 SpellChecker 之間的依賴關(guān)系。在控制反轉(zhuǎn)的場景中买窟,我們反而會做這樣的事情:

public class TextEditor {
   private SpellChecker spellChecker;
   public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }
}

在這里丰泊,TextEditor 不應該擔心 SpellChecker 的實現(xiàn)。SpellChecker 將會獨立實現(xiàn)始绍,并且在 TextEditor 實例化的時候?qū)⑻峁┙o TextEditor瞳购,整個過程是由 Spring 框架的控制。
在這里亏推,我們已經(jīng)從 TextEditor 中刪除了全面控制学赛,并且把它保存到其他地方(即 XML 配置文件),且依賴關(guān)系(即 SpellChecker 類)通過類構(gòu)造函數(shù)被注入到 TextEditor 類中吞杭。因此盏浇,控制流通過依賴注入(DI)已經(jīng)“反轉(zhuǎn)”,因為你已經(jīng)有效地委托依賴關(guān)系到一些外部系統(tǒng)芽狗。

  • 依賴注入的第二種方法是通過 TextEditor 類的 Setter 方法绢掰,我們將創(chuàng)建 SpellChecker 實例,該實例將被用于調(diào)用 setter 方法來初始化 TextEditor 的屬性童擎。

5.1 Constructor-based dependency injection

  • 當容器調(diào)用帶有一組參數(shù)的類構(gòu)造函數(shù)時滴劲,基于構(gòu)造函數(shù)的 DI 就完成了,其中每個參數(shù)代表一個對其他類的依賴顾复。
package com.tutorialspoint;
public class TextEditor {
   private SpellChecker spellChecker;
   public TextEditor(SpellChecker spellChecker) {
      System.out.println("Inside TextEditor constructor." );
      this.spellChecker = spellChecker;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}
package com.tutorialspoint;
public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   } 
}
package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = 
             new ClassPathXmlApplicationContext("Beans.xml");
      TextEditor te = (TextEditor) context.getBean("textEditor");
      te.spellCheck();
   }
}
   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <constructor-arg ref="spellChecker"/>
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>
  • 輸出
Inside SpellChecker constructor.
Inside TextEditor constructor.
Inside checkSpelling.
  • 如果存在不止一個參數(shù)時班挖,當把參數(shù)傳遞給構(gòu)造函數(shù)時,可能會存在歧義芯砸。要解決這個問題萧芙,那么構(gòu)造函數(shù)的參數(shù)在 bean 定義中的順序就是把這些參數(shù)提供給適當?shù)臉?gòu)造函數(shù)的順序就可以了。
  • 最好的傳遞構(gòu)造函數(shù)參數(shù)的方式假丧,使用 index 屬性來顯式的指定構(gòu)造函數(shù)參數(shù)的索引末购。
  • 如果你想要向一個對象傳遞一個引用,你需要使用 標簽的 ref 屬性虎谢,如果你想要直接傳遞值,那么你應該使用如上所示的 value 屬性曹质。

5.2 Setter-based dependency injection

  • 當容器調(diào)用一個無參的構(gòu)造函數(shù)或一個無參的靜態(tài) factory 方法來初始化你的 bean 后婴噩,通過容器在你的 bean 上調(diào)用設值函數(shù)擎场,基于設值函數(shù)的 DI 就完成了。
  • 基于構(gòu)造函數(shù)注入和基于設值函數(shù)注入中的 Beans.xml 文件的區(qū)別几莽。唯一的區(qū)別就是在基于構(gòu)造函數(shù)注入中迅办,我們使用的是〈bean〉標簽中的〈constructor-arg〉元素,而在基于設值函數(shù)的注入中章蚣,我們使用的是〈bean〉標簽中的〈property〉元素站欺。

5.3 內(nèi)部bean

  • Java 內(nèi)部類是在其他類的范圍內(nèi)被定義的,同理纤垂,inner beans 是在其他 bean 的范圍內(nèi)定義的 bean矾策。
   <bean id="outerBean" class="...">
      <property name="target">
         <bean id="innerBean" class="..."/>
      </property>
   </bean>

5.4 注入集合

  • 如果想傳遞多個值,如 Java Collection 類型 List峭沦、Set贾虽、Map 和 Properties,應該怎么做呢吼鱼。為了處理這種情況蓬豁,Spring 提供了四種類型的集合的配置元素:


  • 傳遞集合值
   <bean id="javaCollection" class="com.tutorialspoint.JavaCollection">

      <!-- results in a setAddressList(java.util.List) call -->
      <property name="addressList">
         <list>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
         </list>
      </property>

      <!-- results in a setAddressSet(java.util.Set) call -->
      <property name="addressSet">
         <set>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
        </set>
      </property>

      <!-- results in a setAddressMap(java.util.Map) call -->
      <property name="addressMap">
         <map>
            <entry key="1" value="INDIA"/>
            <entry key="2" value="Pakistan"/>
            <entry key="3" value="USA"/>
            <entry key="4" value="USA"/>
         </map>
      </property>

      <!-- results in a setAddressProp(java.util.Properties) call -->
      <property name="addressProp">
         <props>
            <prop key="one">INDIA</prop>
            <prop key="two">Pakistan</prop>
            <prop key="three">USA</prop>
            <prop key="four">USA</prop>
         </props>
      </property>

   </bean>
  • 注入 bean 的引用
   <!-- Bean Definition to handle references and values -->
   <bean id="..." class="...">

      <!-- Passing bean reference  for java.util.List -->
      <property name="addressList">
         <list>
            <ref bean="address1"/>
            <ref bean="address2"/>
            <value>Pakistan</value>
         </list>
      </property>

      <!-- Passing bean reference  for java.util.Set -->
      <property name="addressSet">
         <set>
            <ref bean="address1"/>
            <ref bean="address2"/>
            <value>Pakistan</value>
         </set>
      </property>

      <!-- Passing bean reference  for java.util.Map -->
      <property name="addressMap">
         <map>
            <entry key="one" value="INDIA"/>
            <entry key ="two" value-ref="address1"/>
            <entry key ="three" value-ref="address2"/>
         </map>
      </property>

   </bean>

  • 注入 null 和空字符串的值
<bean id="..." class="exampleBean">
   <property name="email" value=""/>
</bean>
<bean id="..." class="exampleBean">
   <property name="email"><null/></property>
</bean>

6.Spring Beans自動裝配

  • Spring 容器可以在不使用<constructor-arg>和<property> 元素的情況下自動裝配相互協(xié)作的 bean 之間的關(guān)系,這有助于減少編寫一個大的基于 Spring 的應用程序的 XML 配置的數(shù)量菇肃。
  • 下列自動裝配模式地粪,它們可用于指示 Spring 容器為來使用自動裝配進行依賴注入。你可以使用<bean>元素的 autowire 屬性為一個 bean 定義指定自動裝配模式琐谤。


  • 局限性


6.1 byName

  • 這種模式由屬性名稱指定自動裝配蟆技。Spring 容器看作 beans,在 XML 配置文件中 beans 的 auto-wire 屬性設置為 byName笑跛。然后付魔,它嘗試將它的屬性與配置文件中定義為相同名稱的 beans 進行匹配和連接。如果找到匹配項飞蹂,它將注入這些 beans几苍,否則,它將拋出異常陈哑。
    例如妻坝,在配置文件中,如果一個 bean 定義設置為自動裝配 byName惊窖,并且它包含 spellChecker 屬性(即刽宪,它有一個 setSpellChecker(...) 方法),那么 Spring 就會查找定義名為 spellChecker 的 bean界酒,并且用它來設置這個屬性圣拄。你仍然可以使用 <property> 標簽連接其余的屬性。
   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor" 
      autowire="byName">
      <property name="name" value="Generic Text Editor" />
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>

6.2 byType

  • 這種模式由屬性類型指定自動裝配毁欣。Spring 容器看作 beans庇谆,在 XML 配置文件中 beans 的 autowire 屬性設置為 byType岳掐。然后,如果它的 type 恰好與配置文件中 beans 名稱中的一個相匹配饭耳,它將嘗試匹配和連接它的屬性串述。如果找到匹配項,它將注入這些 beans寞肖,否則纲酗,它將拋出異常。
    例如新蟆,在配置文件中觅赊,如果一個 bean 定義設置為自動裝配 byType,并且它包含 SpellChecker 類型的 spellChecker 屬性栅葡,那么 Spring 就會查找定義名為 SpellChecker 的 bean茉兰,并且用它來設置這個屬性。你仍然可以使用 <property> 標簽連接其余屬性欣簇。
   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor" 
      autowire="byType">
      <property name="name" value="Generic Text Editor" />
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="SpellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>

6.3 由構(gòu)造函數(shù)自動裝配

  • 這種模式與 byType 非常相似规脸,但它應用于構(gòu)造器參數(shù)。Spring 容器看作 beans熊咽,在 XML 配置文件中 beans 的 autowire 屬性設置為 constructor莫鸭。然后,它嘗試把它的構(gòu)造函數(shù)的參數(shù)與配置文件中 beans 名稱中的一個進行匹配和連線横殴。如果找到匹配項被因,它會注入這些 bean,否則衫仑,它會拋出異常梨与。
    例如,在配置文件中文狱,如果一個 bean 定義設置為通過構(gòu)造函數(shù)自動裝配粥鞋,而且它有一個帶有 SpellChecker 類型的參數(shù)之一的構(gòu)造函數(shù),那么 Spring 就會查找定義名為 SpellChecker 的 bean瞄崇,并用它來設置構(gòu)造函數(shù)的參數(shù)呻粹。你仍然可以使用 <constructor-arg> 標簽連接其余屬性。
   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor" 
      autowire="constructor">
      <constructor-arg value="Generic Text Editor"/>
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="SpellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>

7.Spring 基于注解的配置

  • 使用注解來配置依賴注入苏研。而不是采用 XML 來描述一個 bean 連線等浊,你可以使用相關(guān)類,方法或字段聲明的注解摹蘑,將 bean 配置移動到組件類本身筹燕。

7.1 @Required

  • @Required 注釋應用于 bean 屬性的 setter 方法,它表明受影響的 bean 屬性在配置時必須放在 XML 配置文件中,否則容器就會拋出一個 BeanInitializationException 異常庄萎。下面顯示的是一個使用 @Required 注釋的示例踪少。
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Required;
public class Student {
   private Integer age;
   private String name;
   @Required
   public void setAge(Integer age) {
      this.age = age;
   }
   public Integer getAge() {
      return age;
   }
   @Required
   public void setName(String name) {
      this.name = name;
   }
   public String getName() {
      return name;
   }
}
   <!-- Definition for student bean -->
   <bean id="student" class="com.tutorialspoint.Student">
      <property name="name"  value="Zara" />
      <property name="age"  value="11"/>
   </bean>

7.2 @Autowired

  • @Autowired 注釋對在哪里和如何完成自動連接提供了更多的細微的控制朴乖。
    @Autowired 注釋可以在 setter 方法中被用于自動連接 bean拴还,就像 @Autowired 注釋厉斟,容器,一個屬性或者任意命名的可能帶有多個參數(shù)的方法忍捡。
  • Setter 方法中的 @Autowired
    你可以在 XML 文件中的 setter 方法中使用 @Autowired 注釋來除去 元素。當 Spring遇到一個在 setter 方法中使用的 @Autowired 注釋切黔,它會在方法中視圖執(zhí)行 byType 自動連接砸脊。
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
   private SpellChecker spellChecker;
   @Autowired
   public void setSpellChecker( SpellChecker spellChecker ){
      this.spellChecker = spellChecker;
   }
   public SpellChecker getSpellChecker( ) {
      return spellChecker;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}
   <!-- Definition for textEditor bean without constructor-arg  -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>
  • 屬性中的@Autowired
    你可以在屬性中使用 @Autowired 注釋來除去 setter 方法。當時使用 為自動連接屬性傳遞的時候纬霞,Spring 會將這些傳遞過來的值或者引用自動分配給那些屬性凌埂。
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
   @Autowired
   private SpellChecker spellChecker;
   public TextEditor() {
      System.out.println("Inside TextEditor constructor." );
   }  
   public SpellChecker getSpellChecker( ){
      return spellChecker;
   }  
   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}
   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>
  • 構(gòu)造函數(shù)中的 @Autowired
    你也可以在構(gòu)造函數(shù)中使用 @Autowired。一個構(gòu)造函數(shù) @Autowired 說明當創(chuàng)建 bean 時诗芜,即使在 XML 文件中沒有使用 元素配置 bean 瞳抓,構(gòu)造函數(shù)也會被自動連接。
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
   private SpellChecker spellChecker;
   @Autowired
   public TextEditor(SpellChecker spellChecker){
      System.out.println("Inside TextEditor constructor." );
      this.spellChecker = spellChecker;
   }
   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}
   <!-- Definition for textEditor bean without constructor-arg  -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>
  • @Autowired 的(required=false)選項
    默認情況下伏恐,@Autowired 注釋意味著依賴是必須的孩哑,它類似于 @Required 注釋,然而翠桦,你可以使用 @Autowired 的 (required=false) 選項關(guān)閉默認行為横蜒。

7.3 @Qualifier 注釋

  • 可能會有這樣一種情況,當你創(chuàng)建多個具有相同類型的 bean 時销凑,并且想要用一個屬性只為它們其中的一個進行裝配丛晌,在這種情況下,你可以使用 @Qualifier 注釋和 @Autowired 注釋通過指定哪一個真正的 bean 將會被裝配來消除混亂
package com.tutorialspoint;
public class Student {
   private Integer age;
   private String name;
   public void setAge(Integer age) {
      this.age = age;
   }   
   public Integer getAge() {
      return age;
   }
   public void setName(String name) {
      this.name = name;
   }  
   public String getName() {
      return name;
   }
}
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Profile {
   @Autowired
   @Qualifier("student1")
   private Student student;
   public Profile(){
      System.out.println("Inside Profile constructor." );
   }
   public void printAge() {
      System.out.println("Age : " + student.getAge() );
   }
   public void printName() {
      System.out.println("Name : " + student.getName() );
   }
}
package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      Profile profile = (Profile) context.getBean("profile");
      profile.printAge();
      profile.printName();
   }
}
   <context:annotation-config/>

   <!-- Definition for profile bean -->
   <bean id="profile" class="com.tutorialspoint.Profile">
   </bean>

   <!-- Definition for student1 bean -->
   <bean id="student1" class="com.tutorialspoint.Student">
      <property name="name"  value="Zara" />
      <property name="age"  value="11"/>
   </bean>

   <!-- Definition for student2 bean -->
   <bean id="student2" class="com.tutorialspoint.Student">
      <property name="name"  value="Nuha" />
      <property name="age"  value="2"/>
   </bean>

7.4 Spring JSR-250 注釋

  • Spring還使用基于 JSR-250 注釋斗幼,它包括 @PostConstruct澎蛛, @PreDestroy 和 @Resource 注釋。
    為了定義一個 bean 的安裝和卸載孟岛,我們使用 init-method 和/或 destroy-method 參數(shù)簡單的聲明一下 瓶竭。init-method 屬性指定了一個方法,該方法在 bean 的實例化階段會立即被調(diào)用渠羞。同樣地斤贰,destroy-method 指定了一個方法,該方法只在一個 bean 從容器中刪除之前被調(diào)用次询。
    你可以使用 @PostConstruct 注釋作為初始化回調(diào)函數(shù)的一個替代荧恍,@PreDestroy 注釋作為銷毀回調(diào)函數(shù)的一個替代。
package com.tutorialspoint;
import javax.annotation.*;
public class HelloWorld {
   private String message;
   public void setMessage(String message){
      this.message  = message;
   }
   public String getMessage(){
      System.out.println("Your Message : " + message);
      return message;
   }
   @PostConstruct
   public void init(){
      System.out.println("Bean is going through init.");
   }
   @PreDestroy
   public void destroy(){
      System.out.println("Bean will destroy now.");
   }
}
   <context:annotation-config/>

   <bean id="helloWorld" 
       class="com.tutorialspoint.HelloWorld"
       init-method="init" destroy-method="destroy">
       <property name="message" value="Hello World!"/>
   </bean>
  • 可以在字段中或者 setter 方法中使用 @Resource 注釋,它和在 Java EE 5 中的運作是一樣的送巡。@Resource 注釋使用一個 ‘name’ 屬性摹菠,該屬性以一個 bean 名稱的形式被注入。你可以說骗爆,它遵循 by-name 自動連接語義次氨。
package com.tutorialspoint;
import javax.annotation.Resource;
public class TextEditor {
   private SpellChecker spellChecker;
   @Resource(name= "spellChecker")
   public void setSpellChecker( SpellChecker spellChecker ){
      this.spellChecker = spellChecker;
   }
   public SpellChecker getSpellChecker(){
      return spellChecker;
   }
   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}

7.5 基于Java的配置

  • 基于 Java 的配置選項,可以使你在不用配置 XML 的情況下編寫大多數(shù)的 Spring
  • @Configuration 和 @Bean 注解
    帶有 @Configuration 的注解類表示這個類可以使用 Spring IoC 容器作為 bean 定義的來源摘投。@Bean 注解告訴 Spring煮寡,一個帶有 @Bean 的注解方法將返回一個對象,該對象應該被注冊為在 Spring 應用程序上下文中的 bean犀呼。
package com.tutorialspoint;
import org.springframework.context.annotation.*;
@Configuration
public class HelloWorldConfig {
   @Bean 
   public HelloWorld helloWorld(){
      return new HelloWorld();
   }
}

等價于:
<beans>
   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld" />
</beans>
public static void main(String[] args) {
   ApplicationContext ctx = 
   new AnnotationConfigApplicationContext(HelloWorldConfig.class); 
   HelloWorld helloWorld = ctx.getBean(HelloWorld.class);
   helloWorld.setMessage("Hello World!");
   helloWorld.getMessage();
}
  • 可以加載各種配置類
package com.tutorialspoint;
import org.springframework.context.annotation.*;
@Configuration
public class TextEditorConfig {
   @Bean 
   public TextEditor textEditor(){
      return new TextEditor( spellChecker() );
   }
   @Bean 
   public SpellChecker spellChecker(){
      return new SpellChecker( );
   }
}
package com.tutorialspoint;
public class TextEditor {
   private SpellChecker spellChecker;
   public TextEditor(SpellChecker spellChecker){
      System.out.println("Inside TextEditor constructor." );
      this.spellChecker = spellChecker;
   }
   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}
package com.tutorialspoint;
public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling(){
      System.out.println("Inside checkSpelling." );
   }

}
package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext ctx = 
      new AnnotationConfigApplicationContext(TextEditorConfig.class);

      TextEditor te = ctx.getBean(TextEditor.class);

      te.spellCheck();
   }
}
  • @Import注解
    允許從另一個配置類中加載 @Bean 定義幸撕。
@Configuration
public class ConfigA {
   @Bean
   public A a() {
      return new A(); 
   }
}
@Configuration
@Import(ConfigA.class)
public class ConfigB {
   @Bean
   public B a() {
      return new A(); 
   }
}
public static void main(String[] args) {
   ApplicationContext ctx = 
   new AnnotationConfigApplicationContext(ConfigB.class); //只要指定B即可
   // now both beans A and B will be available...
   A a = ctx.getBean(A.class);
   B b = ctx.getBean(B.class);
}
  • 生命周期回調(diào)
    @Bean 注解支持指定任意的初始化和銷毀的回調(diào)方法,就像在 bean 元素中 Spring 的 XML 的初始化方法和銷毀方法的屬性外臂。
public class Foo {
   public void init() {
      // initialization logic
   }
   public void cleanup() {
      // destruction logic
   }
}

@Configuration
public class AppConfig {
   @Bean(initMethod = "init", destroyMethod = "cleanup" )
   public Foo foo() {
      return new Foo();
   }
}
  • 指定Bean的作用域
@Configuration
public class AppConfig {
   @Bean
   @Scope("prototype")
   public Foo foo() {
      return new Foo();
   }
}

7.6 Spring 中的事件處理

  • Spring 的核心是 ApplicationContext坐儿,它負責管理 beans 的完整生命周期。當加載 beans 時宋光,ApplicationContext 發(fā)布某些類型的事件貌矿。例如,當上下文啟動時跃须,ContextStartedEvent 發(fā)布站叼,當上下文停止時,ContextStoppedEvent 發(fā)布菇民。
    通過 ApplicationEvent 類和 ApplicationListener 接口來提供在 ApplicationContext 中處理事件尽楔。如果一個 bean 實現(xiàn) ApplicationListener,那么每次 ApplicationEvent 被發(fā)布到 ApplicationContext 上第练,那個 bean 會被通知阔馋。
  • 由于 Spring 的事件處理是單線程的,所以如果一個事件被發(fā)布娇掏,直至并且除非所有的接收者得到的該消息呕寝,該進程被阻塞并且流程將不會繼續(xù)。因此婴梧,如果事件處理被使用下梢,在設計應用程序時應注意。
  • 標準事件
    1)ContextRefreshedEvent
    ApplicationContext 被初始化或刷新時塞蹭,該事件被發(fā)布孽江。這也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法來發(fā)生。
    2)ContextStartedEvent
    當使用 ConfigurableApplicationContext 接口中的 start() 方法啟動 ApplicationContext 時番电,該事件被發(fā)布岗屏。你可以調(diào)查你的數(shù)據(jù)庫辆琅,或者你可以在接受到這個事件后重啟任何停止的應用程序。
    3)ContextStoppedEvent
    當使用 ConfigurableApplicationContext 接口中的 stop() 方法停止 ApplicationContext 時这刷,發(fā)布這個事件婉烟。你可以在接受到這個事件后做必要的清理的工作。
    4)ContextClosedEvent
    當使用 ConfigurableApplicationContext 接口中的 close() 方法關(guān)閉 ApplicationContext 時暇屋,該事件被發(fā)布似袁。一個已關(guān)閉的上下文到達生命周期末端;它不能被刷新或重啟率碾。
    5)RequestHandledEvent
    這是一個 web-specific 事件叔营,告訴所有 bean HTTP 請求已經(jīng)被服務。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末所宰,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子畜挥,更是在濱河造成了極大的恐慌仔粥,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蟹但,死亡現(xiàn)場離奇詭異躯泰,居然都是意外死亡,警方通過查閱死者的電腦和手機华糖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門麦向,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人客叉,你說我怎么就攤上這事诵竭。” “怎么了兼搏?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵卵慰,是天一觀的道長。 經(jīng)常有香客問我佛呻,道長裳朋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任吓著,我火速辦了婚禮鲤嫡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绑莺。我一直安慰自己暖眼,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布紊撕。 她就那樣靜靜地躺著罢荡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上区赵,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天惭缰,我揣著相機與錄音,去河邊找鬼笼才。 笑死漱受,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的骡送。 我是一名探鬼主播昂羡,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼摔踱!你這毒婦竟也來了虐先?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤派敷,失蹤者是張志新(化名)和其女友劉穎蛹批,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體篮愉,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡腐芍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了试躏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片猪勇。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖颠蕴,靈堂內(nèi)的尸體忽然破棺而出泣刹,到底是詐尸還是另有隱情,我是刑警寧澤裁替,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布项玛,位于F島的核電站,受9級特大地震影響弱判,放射性物質(zhì)發(fā)生泄漏襟沮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一昌腰、第九天 我趴在偏房一處隱蔽的房頂上張望开伏。 院中可真熱鬧,春花似錦遭商、人聲如沸固灵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽巫玻。三九已至丛忆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間仍秤,已是汗流浹背熄诡。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诗力,地道東北人凰浮。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像苇本,于是被迫代替她去往敵國和親袜茧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理瓣窄,服務發(fā)現(xiàn)笛厦,斷路器,智...
    卡卡羅2017閱讀 134,693評論 18 139
  • 如下是整篇文章的結(jié)構(gòu)俺夕,所需閱讀時間大約20min Spring簡介 Spring框架由Rod Johnson開發(fā)递递,...
    李序鍇閱讀 899評論 0 15
  • Spring簡介 spring框架由Rod Johnson開發(fā),2004年發(fā)布了Spring框架的第一版啥么。Spri...
    qiuqiu_hz閱讀 1,077評論 0 15
  • Spring框架是由于軟件開發(fā)的復雜性而創(chuàng)建的。Spring使用的是基本的JavaBean來完成以前只可能由EJB...
    OSET我要編程閱讀 2,709評論 0 3
  • 本篇文章記錄《數(shù)據(jù)倉庫與數(shù)據(jù)分析》課程相關(guān)的知識點贰逾,屬于大數(shù)據(jù)領(lǐng)域的理論基礎 1 什么是數(shù)據(jù)倉庫以及數(shù)據(jù)倉庫的特...
    needrunning閱讀 993評論 0 3