Spring一文完結~

目錄

一、概述

二、Spring體系結構

三、Spring環境配置

四、Spring IoC容器

五、Spring BeanFactory容器

六、Spring ApplicationContext容器

七、Spring Bean定義

八、Spring Bean作用域

九、Spring Bean生命週期

十、Spring Bean後置處理器

十一、Spring Bean定義繼承

十二、Spring依賴注入

十三、注入內部Beans

十四、注入集合

十五、Beans自動裝配

十六、基於註解的配置

十七、Spring基於Java的配置

十八、Spring中的事件處理

十九、Spring中的自定義事件

二十、AOP術語

二十一、Spring中基於AOP的XML架構

二十二、Spring 中基於AOP的@AspectJ

二十三、Spring JDBC框架

二十四、Spring中SQL的存儲過程

二十五、Spring事務管理

二十六、Spring Web MVC框架

二十七、Spring MVC Hello World例子

二十八、Spring MVC表單處理例子

二十九、Spring 頁面重定向例子

三十、Spring靜態頁面例子

 

後記:


一、概述

Spring是最受歡迎的企業級Java應用程序開發框架(現在好像不能那麼說了,因爲現在SpringBoot纔是獨領風騷啊),用Spring框架來創建性能好、易於測試、可重用的代碼。

Spring框架是一個開源的Java平臺,它最初是由Rod Johnson編寫的,並且於2003年6月首次在Apache2.0許可下發布。

Spring框架的核心特性是可用來開發任何的Java應用程序,但是在Java EE平臺上構建web應用程序是需要擴展的。Spring框架的目標是使J2EE開發變得更容易使用,通過啓動基於POJO(POJO(Plain Ordinary Java Object)簡單的Java對象,實際就是普通JavaBeans,是爲了避免和EJB(企業JavaBean)混淆所創造的簡稱)編程模型來促進良好的編程實踐。

1、使用Spring框架的好處

在有HTML+CSS+JS(jQuery)+Bootstrap+servlet+JSP(EL/JSTL)知識,雖然前端開發的難度降低了,前後端無服務器因爲JSP應用動態開發也容易了,但是兩者之間的交互和總的結構還是不夠清晰。有了前端依舊沒辦法很快設計好後端的接口,這個是目前我的問題,所以看看Spring框架能否解決呢?

  • Spring 可以使開發人員使用 POJOs 開發企業級的應用程序。只使用 POJOs 的好處是你不需要一個 EJB 容器產品,比如一個應用程序服務器,但是你可以選擇使用一個健壯的 servlet 容器,比如 Tomcat 或者一些商業產品。

  • Spring 在一個單元模式中是有組織的。即使包和類的數量非常大,你只要擔心你需要的,而其它的就可以忽略了。

  • Spring 不會讓你白費力氣做重複工作,它真正的利用了一些現有的技術,像ORM 框架、日誌框架、JEE、Quartz 和 JDK 計時器,其他視圖技術。

  • 測試一個用 Spring 編寫的應用程序很容易,因爲環境相關的代碼被移動到這個框架中。此外,通過使用 JavaBean-style POJOs,它在使用依賴注入注入測試數據時變得更容易。

  • Spring 的 web 框架是一個設計良好的 web MVC 框架,它爲比如 Structs 或者其他工程上的或者不怎麼受歡迎的 web 框架提供了一個很好的供替代的選擇。MVC模式導致應用程序的不同方面(輸入邏輯,業務邏輯和UI邏輯)分離,同時提供這些元素之間的鬆散耦合。

    • 模型(Model)封裝了應用程序數據,通常它們將由POJO類組成。

    • 視圖(View)負責渲染模型數據,一般來說它生成客戶端瀏覽器可以解釋HTML輸出。

    • 控制器(Controller)負責處理用戶請求並構建適當的模型,並將其傳遞給視圖進行渲染。

  • Spring 對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大降低。

  • 輕量級的 IOC (控制反轉(Inversion of Control,縮寫爲IoC),是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。)容器往往是輕量級的,例如,特別是當與 EJB 容器相比的時候。這有利於在內存和 CPU 資源有限的計算機上開發和部署應用程序。

  • Spring提供了一致的事務管理接口,可向下擴展到(使用一個單一的數據庫,例如)本地事務並擴展到全局事務(例如,使用 JTA)。

2、依賴注入(DI)

Spring最認同的技術是控制反轉的依賴注入(DI)模式。控制反轉(IoC)是一個通用的概念,它可以用許多不同的方式去表達,依賴注入僅僅是控制反轉的一個具體例子。

當編寫一個複雜的Java應用程序時,應用程序類應該儘可能的獨立於其它的java類來增加這些類可重用可能性,當進行單元測試時,可以使它們獨立於其他類進行測試。依賴註釋(或者有時被稱爲配線)有助於將這些類粘合在一起,並且在同一時間讓它們保持獨立。

到底什麼是依賴注入?讓我們將這兩個詞分開來看一看。這裏將依賴關係部分轉化爲兩個類之間的關聯。例如,類A依賴於類B現在。現在,讓我們看一看第二部分,注入。所有這一切都意味着類B通過IoC被注入到類A中。

依賴注入可以以向構造函數傳遞參數的方式發生,或者通過時候用setter方法post-construction。依賴注入是Spring框架的核心部分。

3、面向切面的程序設計(AOP)

Spring框架的一個關鍵組件是面向切面的程序設計(AOP)框架。一個程序中跨越多個點的功能被稱爲橫切關注點,這些橫切關注點在概念上獨立於應用程序的業務邏輯。有各種各樣常見的很好的相關方面的例子,比如日誌記錄、聲明性事務、安全性,和緩存等等。

在OOP中模塊化的關鍵單元是類,而在AOP中模塊的關鍵單元是切面。AOP幫助你將橫切關注點從它們所影響的對象中分離出來,然而依賴注入幫助你的應用程序對象從彼此中分離出來。

Spring框架的AOP模塊提供了面向切面的程序設計實現,可以定義諸如方向攔截器和切入點等,從而使實現功能的代碼徹底的解耦出來。使用源碼級的元數據,可以以用類似於.Net屬性的方式合併行爲信息到代碼中。


二、Spring體系結構

Spring有可能成爲所有企業應用程序的一站式服務店,然而,Spring是模塊化的,允許你挑選和選擇適用於你的模塊,不必要把的剩餘部分也引入。Spring框架提供約20個模塊,可以根據應用程序的要求來使用:

 

 

1、核心容器

核心容器由spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring表達式語言,Spring Expression Language)模塊組成,細節如下:

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

  • spring-beans 模塊提供 BeanFactory,工廠模式的微妙實現,它移除了編碼式單例的需要,並且可以把配置和依賴從實際編碼邏輯中解耦。

  • context模塊建立在由corebeans 模塊的基礎上建立起來的,它以一種類似於JNDI註冊的方式訪問對象。Context模塊繼承自Bean模塊,並且添加了國際化(比如,使用資源束)、事件傳播、資源加載和透明地創建上下文(比如,通過Servelet容器)等功能。Context模塊也支持Java EE的功能,比如EJB、JMX和遠程調用等。ApplicationContext接口是Context模塊的焦點。spring-context-support提供了對第三方庫集成到Spring上下文的支持,比如緩存(EhCache, Guava, JCache)、郵件(JavaMail)、調度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。

  • spring-expression模塊提供了強大的表達式語言,用於在運行時查詢和操作對象圖。它是JSP2.1規範中定義的統一表達式語言的擴展,支持set和get屬性值、屬性賦值、方法調用、訪問數組集合及索引的內容、邏輯算術運算、命名變量、通過名字從Spring IoC容器檢索對象,還支持列表的投影、選擇以及聚合等。

它們完整依賴關係如下:

 

2、數據訪問/集成

數據訪問/集成層包括JDBC,ORM,OXM,JMS和事物處理模塊,它們的細節如下:

(注:JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service)

  • JDBC 模塊提供了JDBC抽象層,它消除了冗長的JDBC編碼和對數據庫供應商特定錯誤代碼的解析。

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

  • OXM 模塊提供了對OXM實現的支持,比如JAXB、Castor、XML Beans、JiBX、XStream等。

  • JMS 模塊包含生產(produce)和消費(consume)消息的功能。從Spring 4.1開始,集成了spring-messaging模塊。。

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

3、Web

Web層由Web,Web-MVC,Web-Socket和Web-Portlet組成:

  • Web 模塊提供面向web的基本功能和麪向web的應用上下文,比如多部分(multipart)文件上傳功能、使用Servlet監聽器初始化IoC容器等。它還包括HTTP客戶端以及Spring遠程調用中與web相關的部分。。

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

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

  • Web-Portlet 模塊提供了用於Portlet環境的MVC實現,並反映了spring-webmvc模塊的功能。

4、其它

還有一些重要的模塊,像AOP,Aspects,Instrumentation,Web和測試模塊:

  • AOP 模塊提供了面向方面的編程實現,允許你定義方法攔截器和切入點對代碼進行乾淨地解耦,從而使實現功能的代碼徹底的解耦出來。使用源碼級的元數據,可以用類似於.Net屬性的方式合併行爲信息到代碼中。

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

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

  • Messaging 模塊爲 STOMP 提供了支持作爲在應用程序中 WebSocket 子協議的使用。它也支持一個註解編程模型,它是爲了選路和處理來自 WebSocket 客戶端的 STOMP 信息。

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


三、Spring環境配置

這裏建議還是配置好java環境之後,在IDEA裏面直接創建Spring項目就好,它會自動給你導包。如果是eclipse的話也可以,相關教程也是有的。

這裏介紹當你已經配置好環境之後(如果是IDEA就是直接創建Spring項目即可,會自動導包)。

1、創建源文件

首先我們在Spring項目下創建名爲com.tutorialspoint的包(src下),在包裏面創建HelloWorld.java文件的內容:

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);
   }
}

然後再創建MainApp.java:

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");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
   }
}

關於主要程序有以下兩個要點需要注意:

  • 第一步是我們使用框架 API ClassPathXmlApplicationContext() 來創建應用程序的上下文。這個 API 加載 beans 的配置文件並最終基於所提供的 API,它處理創建並初始化所有的對象,即在配置文件中提到的 beans。

  • 第二步是使用已創建的上下文的 getBean() 方法來獲得所需的 bean。這個方法使用 bean 的 ID 返回一個最終可以轉換爲實際對象的通用對象。一旦有了對象,你就可以使用這個對象調用任何類的方法。

2、創建bean的配置文件

你需要創建一個Bean的配置文件,該文件時一個XML文件,並且作爲粘合bean的粘合劑即類。這個文件需要在src目錄下創建,通常開發人員保存該文件名稱爲Beans.xml文件(或者applicationContext.xml)或者是任何你喜歡的名稱。但你必須確保這個文件在CLASSPATH中是可用的,並在主應用程序中使用相同的名稱,而在MainApp.java文件中創建應用程序的上下文。

Beans.xml用於給不同的bean分配唯一的ID,並且控制不同值的對象的創建,而不會影響Spring的任何源文件。例如,在下面的文件你可以爲message變量傳遞任何值:

<?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>

當Spring應用程序被加載到內存中時,框架利用了上面的配置文件來創建所有已經定義的beans,並且按照標籤定義爲它們分配一個唯一的ID。你可以使用標籤來傳遞在創建對象時不同變量的值。

3、運行程序

一旦你完成了創建源代碼和bean的配置文件後,就可以準備編譯和運行你的程序了。


四、Spring IoC容器

Spring容器是Spring框架的核心。容器將創建對象,把它們連接在一起,配置它們,並管理它們的整個生命週期從創建到銷燬。Spring容器使用依賴注入(DI)來管理組成一個應用程序的組件。這些對象被稱爲Spring Beans。

通過閱讀配置元數據提供的指令,容器知道哪些對象進行實例化、配置和組裝。配置元數據可以通過XML,Java註釋或Java代碼來表示。下圖是Spring如何工作的高級視圖。Spring IoC容器利用Java的POJO類和配置元數據來生成完全配置和可執行的系統或應用程序。

 

IOC容器具有依賴註釋功能的容器,它可以創建對象,IOC容器負責實例化、定位、配置應用程序中的對象及建立這些對象間的依賴。通常new一個實例,控制權由程序員控制,而“控制反轉”是指new實例工作不由程序員來做,而是交給Spring容器來做。在Spring中BeanFactory是IOC容器的實際代表者。

Spring提供了以下兩種不同類型的容器:

序號 容器 & 描述
1 Spring BeanFactory 容器它是最簡單的容器,給 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口來定義。BeanFactory 或者相關的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的與 Spring 整合的第三方框架的反向兼容性的目的。
2 Spring ApplicationContext 容器該容器添加了更多的企業特定的功能,例如從一個屬性文件中解析文本信息的能力,發佈應用程序事件給感興趣的事件監聽器的能力。該容器是由 org.springframework.context.ApplicationContext 接口定義。

ApplicationContext容器包括BeanFactory容器的所有功能,所以通常認爲包含BeanFactory。BeanFactory仍然可以用於輕量級的應用程序,如移動設備或基於applet的應用程序,其中它的數據量和速度是顯著的。


五、Spring BeanFactory容器

這是一個最簡單的容器,它的主要功能是爲依賴注入(DI)提供支持,這個容器接口在org.springframewordk.beans.factory.BeanFactor中被定義。

BeanFactory和相關的接口,比如BeanFactoryAware、DisposableBean、InitializingBean,仍舊保留在Spring中,主要目的是向後者兼容已經存在的和那些Spring整合在一起的第三方框架。

在Spring中,有大量對BeanFactory接口的實現。其中,最常被使用的是XmlBeanFactory類。這個容器從一個XML文件中讀取配置元數據,由這些元數據來生成一個被配置化的系統或者應用。

在資源寶貴的移動設備或者基於applet的應用當中,BeanFactory會被優先選擇。否則,一般使用的是ApplicationgContext,除非你有更好的理由選擇BeanFactory。


六、Spring ApplicationContext容器

Application Context是BeanFactory的子接口,也被稱爲Spring上下文。

Application Context是spring中較高級的容器。和BeanFactory類似,它可以加載配置文件中定義的bean,將所有的bean集中在一起,當有請求的時候分配bean。另外,它增加了企業所需要的功能,比如,從屬性文件中解析文本信息和將事件傳遞給所指定的監聽器。這個容器在org.springframework.context.ApplicationContext interface接口中定義。

ApplicationContext包含BeanFactory所有的功能,一般情況下,相對於BeanFactory,ApplicationContext會更加優秀。當然,BeanFactory仍然可以在輕量級應用中使用。

最常被使用的ApplicationContext接口實現:

  • FileSystemXmlApplicationContext:該容器從 XML 文件中加載已被定義的 bean。在這裏,你需要提供給構造器 XML 文件的完整路徑。

  • ClassPathXmlApplicationContext:該容器從 XML 文件中加載已被定義的 bean。在這裏,你不需要提供 XML 文件的完整路徑,只需正確配置 CLASSPATH 環境變量即可,因爲,容器會從 CLASSPATH 中搜索 bean 配置文件。

  • WebXmlApplicationContext:該容器會在一個 web 應用程序的範圍內加載在 XML 文件中已被定義的 bean。


七、Spring Bean定義

Bean對象是構成應用程序的支柱也是由Spring IoC容器管理的。bean是一個被實例化,組裝,並通過Spring IoC容器所管理的對象。這些bean是由容器提供的配置元數據創建的。

bean定義包含成爲配置元數據的信息,下述容器也需要知道配置元數據:

  • 如何創建一個 bean

  • bean 的生命週期的詳細信息

  • bean 的依賴關係

上述所有的配置元數據轉換成一組構成每個bean定義的下列屬性:

屬性 描述
class 這個屬性是強制性的,並且指定用來創建 bean 的 bean 類。
name 這個屬性指定唯一的 bean 標識符。在基於 XML 的配置元數據中,你可以使用 ID 和/或 name 屬性來指定 bean 標識符。
scope 這個屬性指定由特定的 bean 定義創建的對象的作用域,它將會在 bean 作用域的章節中進行討論。
constructor-arg 它是用來注入依賴關係的,並會在接下來的章節中進行討論。
properties 它是用來注入依賴關係的,並會在接下來的章節中進行討論。
autowiring mode 它是用來注入依賴關係的,並會在接下來的章節中進行討論。
lazy-initialization mode 延遲初始化的 bean 告訴 IoC 容器在它第一次被請求時,而不是在啓動時去創建一個 bean 實例。
initialization 方法 在 bean 的所有必需的屬性被容器設置之後,調用回調方法。它將會在 bean 的生命週期章節中進行討論。
destruction 方法 當包含該 bean 的容器被銷燬時,使用回調方法。它將會在 bean 的生命週期章節中進行討論。

1、Bean與Spring容器的關係:

 

2、Spring配置元數據

Spring IoC容器完全由實際編寫的配置元數據的格式解耦,有三個重要的方法把配置元數據提供給Spring容器:

  • 基於 XML 的配置文件

  • 基於註解的配置

  • 基於 Java 的配置

對於基於XML的配置,Spring2.0以後使用Schema的格式,使得不同類型的配置擁有了自己的命名空間,使配置文件更具擴展性。

 

你已經看到了如何把基於XML的配置元素提供給容器,但是我們要看另一個例子,這個配置文件中不同的bean定義,包括延遲初始化,初始化方法和銷燬方法的:

<?xml version="1.0" encoding="UTF-8"?>
​
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
​
   <!-- A simple bean definition -->
   <bean id="..." class="...">
       <!-- collaborators and configuration for this bean go here -->
   </bean>
​
   <!-- A bean definition with lazy init set on -->
   <bean id="..." class="..." lazy-init="true">
       <!-- collaborators and configuration for this bean go here -->
   </bean>
​
   <!-- A bean definition with initialization method -->
   <bean id="..." class="..." init-method="...">
       <!-- collaborators and configuration for this bean go here -->
   </bean>
​
   <!-- A bean definition with destruction method -->
   <bean id="..." class="..." destroy-method="...">
       <!-- collaborators and configuration for this bean go here -->
   </bean>
​
   <!-- more bean definitions go here -->
​
</beans>

在上述示例中:

1)xmlns="http://www.springframework.org/schema/beans",默認命名空間:它沒有命名空間,用於Spring Bean的定義;

2)xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance",xsi命名空間:這個命名空間用於爲每個文檔中命名空間指定相應的Schema樣式文件,是標準組織定義的標準命名空間。


八、Spring Bean作用域

當Spring中定義一個bean時,你必須聲明該bean的作用域的選項。例如,爲了強制Spring在每次需要時都產生一個新的bean實例,你應該聲明bean的作用域屬性爲prototype。同理,如果你想讓Spring在每次需要時都返回同一個bean實例,你應該聲明bean的作用域的屬性爲singleton。

Spring框架支持以下五個作用域,分別爲singleton、prototype、request、session和global session:

作用域 描述
singleton 在spring IoC容器僅存在一個Bean實例,Bean以單例方式存在,默認值
prototype 每次從容器中調用Bean時,都返回一個新的實例,即每次調用getBean()時,相當於執行newXxxBean()
request 每次HTTP請求都會創建一個新的Bean,該作用域僅適用於WebApplicationContext環境
session 同一個HTTP Session共享一個Bean,不同Session使用不同的Bean,僅適用於WebApplicationContext環境
global-session 一般用於Portlet應用環境,該運用域僅適用於WebApplicationContext環境

1、singleton作用域

singleton是默認的作用域,也就是說,當定義Bean時,如果沒有指定作用域配置,則Bean的作用域被默認爲singleton。

當一個bean的作用域爲Singleton,那麼Spring IoC容器中只會存在一個共享的bean實例,並且對所有bean的請求,只要id與該bean定義相匹配,則只會返回bean的統一實例。

也就是說,當將一個bean定義設置爲singleton作用域的時候,Spring IoC容器只會創建該bean定義的唯一實例。

Singleton是單例類型,就是在創建起容器時就自動創建了一個bean的對象,不管你是否使用,他都存在了,每次獲取到的對象都是同一個對象。

<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="singleton">
    <!-- collaborators and configuration for this bean go here -->
</bean>

2、prototype作用域

當一個bean的作用域爲Prototype,表示一個bean定義對應多個對象實例。Prototype作用的bean會導致在每次對該bean請求(將其注入到另一個bean中,或者以程序的方式調用容器的getBean()方法)時都會創建一個新的bean實例。Prototype是原型類型,它在我們創建容器的時候並沒有實例化,而是我們獲取bean的時候纔會去創建一個對象,而且我們每次獲取到的對象都不是同一個對象。根據經驗,對有狀態的bean應該使用prototype作用域,而對無狀態的bean則應該使用singleton作用域。


九、Spring Bean生命週期

理解Spring bean的生命週期很容易。當一個bean被實例化時,它可能需要執行一些初始化使它轉換爲可用狀態。同樣,當bean不需要,並且從容器中移除時,可能需要做一些清除工作。

爲了定義安裝和拆卸一個bean,我們要聲明init-method和destroy-method參數。init-method屬性指定一個方法,在實例化bean時立即調用該方法。同樣,destroy-method指定一個方法,只有從容器中移除bean之後,才能調用該方法。

Bean的生命週期可以表達爲:Bean的定義——-Bean的初始化——Bean的使用——Bean的銷燬

1、初始化調用

org.springframework..beans.factory.InitializingBean接口指定一個單一的方法:

void afterPropertiesSet() throws Exception;

因此,你可以簡單的實現上述接口和初始化工作可以在afterPropertiesSet()方法中執行,如下所示:

public class ExampleBean implements InitializingBean {
   public void afterPropertiesSet() {
      // do some initialization work
   }
}

在基於XML的配置元數據的情況下,你可以使用init-method屬性來指定帶有void無參方法的名稱。

<bean id="exampleBean" 
         class="examples.ExampleBean" init-method="init"/>

下面是類的定義:

public class ExampleBean {
   public void init() {
      // do some initialization work
   }
}

2、銷燬回調

org.springframework.beans.factory.DisposableBean接口指定一個單一的方法:

void destroy() throws Exception;

因此你可以簡單的實現上述接口並且結束工作可以在destroy()方法中執行,如下:

public class ExampleBean implements DisposableBean {
   public void destroy() {
      // do some destruction work
   }
}

在基於XML的配置元數據的情況下,可以使用destroy-method屬性來指定帶有void無參數方法的名稱。例如:

<bean id="exampleBean"
         class="examples.ExampleBean" destroy-method="destroy"/>

下面是類的定義:

public class ExampleBean {
   public void destroy() {
      // do some destruction work
   }
}

如果你在非web應用程序環境中使用Spring的IoC容器;例如在豐富的客戶端桌面環境中;那麼在JVM中你要註冊關閉hook。這樣做可以確保正常關閉,爲了讓所有資源都被釋放,可以在單個beans上調用destroy方法。

建議你不要十四用InitializingBean或者DisposableBean的回調方法,因爲XML匹配值在命名方法上提供了極大的靈活性。

 

3、例子:

步驟 描述
1 創建一個名稱爲 SpringExample 的項目,並且在創建項目的 src 文件夾中創建一個包 com.tutorialspoint
2 使用 Add External JARs 選項,添加所需的 Spring 庫,解釋見 Spring Hello World Example 章節。
3 com.tutorialspoint 包中創建 Java 類 HelloWorldMainApp
4 src 文件夾中創建 Beans 配置文件 Beans.xml
5 最後一步是創建的所有 Java 文件和 Bean 配置文件的內容,並運行應用程序,解釋如下所示。

上面是eclipse中的步驟,如果是IDEA,直接創建類之後配置Beans.xml即可。

1)HelloWorld.java:

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.");
   }
}

2)MainApp.java

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();
   }
}

3)配置方法

<?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"
       init-method="init" destroy-method="destroy">
       <property name="message" value="Hello World!"/>
   </bean>
​
</beans>

4、默認的初始化和銷燬方法

如果你有太多具有相同名稱的初始化或銷燬方法的Bean,那麼你不需要在每一個bean上聲明初始化方法和銷燬方法。框架使用元素中的default-init-method和default-destroy-method屬性提供了靈活的配置這種情況。

<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"
    default-init-method="init" 
    default-destroy-method="destroy">
​
   <bean id="..." class="...">
       <!-- collaborators and configuration for this bean go here -->
   </bean>
​
</beans>

十、Spring Bean後置處理器

Bean後置處理器允許在調用初始化方法前後對Bean進行額外的處理。

BeanPostProcessor接口定義回調方法,你可以實現該方法來提供自己的實例化邏輯,依賴解析邏輯等。你也可以在Spring容器通過插入一個或多個BeanPostProcessor的實現來完成實例化,配置和初始化一個bean之後實現一些自定義邏輯回調方法。

你可以配置多個BeanPostProcessor接口,通過設置BeanPostProcessor實現的Ordered接口提供的order屬性來控制這些BeanPostProcessor接口的執行順序。

BeanPostProcessor可以對bean(或對象)實例進行操作,這意味着Spring IoC容器實例化一個bean實例,然後BeanPostProcessor接口進行它們的工作。

ApplicationContext會自動檢測由BeanPostProcessor接口的實現定義的bean,註冊這些bean爲後置處理器,然後通過在容器中創建bean,在適當的時候調用它。

例子:

1)HelloWorld.java:

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.");
   }
}

2)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
   }
}

3)MainApp.java:

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();
   }
}

4)配置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"
       init-method="init" destroy-method="destroy">
       <property name="message" value="Hello World!"/>
   </bean>

   <bean class="com.tutorialspoint.InitHelloWorld" />

</beans>

十一、Spring Bean定義繼承

bean定義可以包含很多的配置信息,包括構造函數的參數,屬性值,容器的具體信息例如初始化信息,靜態工廠方法名,等等。

Spring Bean定義的繼承與java類的繼承無關,但是繼承的概念是一樣的。你可以定義一個父bean的定義作爲模板和其它子bean就可以從父bean中繼承所需的配置。

當你使用基於XML的配置元數據時,通過使用父屬性,指定父bean作爲該屬性的值來表明子bean的定義。

例子:

我們在適當的位置使用 Eclipse IDE,然後按照下面的步驟來創建一個 Spring 應用程序:

步驟 描述
1 創建一個名稱爲 SpringExample 的項目,並且在創建項目的 src 文件夾中創建一個包 com.tutorialspoint
2 使用 Add External JARs 選項,添加所需的 Spring 庫,解釋見 Spring Hello World Example 章節。
3 com.tutorialspoint 包中創建 Java 類 HelloWorldHelloIndiaMainApp
4 src 文件夾中創建 Beans 配置文件 Beans.xml
5 最後一步是創建的所有 Java 文件和 Bean 配置文件的內容,並運行應用程序,解釋如下所示。

下面是配置文件 Beans.xml,在該配置文件中我們定義有兩個屬性 message1message2 的 “helloWorld” bean。然後,使用 parent 屬性把 “helloIndia” bean 定義爲 “helloWorld” bean 的孩子。這個子 bean 繼承 message2 的屬性,重寫 message1 的屬性,並且引入一個屬性 message3

<?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="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>

</beans>

HelloWorld.java:

package com.tutorialspoint;
public class HelloWorld {
   private String message1;
   private String message2;
   public void setMessage1(String message){
      this.message1  = message;
   }
   public void setMessage2(String message){
      this.message2  = message;
   }
   public void getMessage1(){
      System.out.println("World Message1 : " + message1);
   }
   public void getMessage2(){
      System.out.println("World Message2 : " + message2);
   }
}

HelloIndia.java

package com.tutorialspoint;

public class HelloIndia {
   private String message1;
   private String message2;
   private String message3;

   public void setMessage1(String message){
      this.message1  = message;
   }

   public void setMessage2(String message){
      this.message2  = message;
   }

   public void setMessage3(String message){
      this.message3  = message;
   }

   public void getMessage1(){
      System.out.println("India Message1 : " + message1);
   }

   public void getMessage2(){
      System.out.println("India Message2 : " + message2);
   }

   public void getMessage3(){
      System.out.println("India Message3 : " + message3);
   }
}

MainApp.java:

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");

      HelloWorld objA = (HelloWorld) context.getBean("helloWorld");

      objA.getMessage1();
      objA.getMessage2();

      HelloIndia objB = (HelloIndia) context.getBean("helloIndia");
      objB.getMessage1();
      objB.getMessage2();
      objB.getMessage3();
   }
}

 

1、Bean定義模板

你可以創建一個Bean定義模板,不需要話太多功夫它就可以被其它子bean定義使用。在定義一個Bean定義模板時,你不應該使用類的屬性,而應該指定帶true值的抽象屬性:

<?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="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>

</beans>

父bean自身不能被實例化,因爲它是不完整的,而且它被明確的標記爲抽象的。當一個定義是抽象的,它僅僅作爲一個純粹的模板bean定義來使用,充當子定義的父定義使用。


十二、Spring依賴注入

Spring框架的核心能力之一就是通過哦依賴注入的方式來管理Bean之間的依賴關係。

1、依賴注入

買個基於應用程序的java都有幾個對象,這些對象一起工作來呈現出終端用戶所看到的工作的應用程序。當編寫一個複雜的java應用程序時,應用程序類應該儘可能獨立於其他的java類來增加可重用的可能性,並且在做單元測試時,測試獨立於其他類的獨立性。依賴注入(或有時成爲佈線)有助於把這些類粘合在一起,同時保持他們獨立。

假設你有一個包含文本編輯器組件的應用程序,並且你想要提供拼寫檢查。標準代碼看起來是這樣的:

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

在這裏我們所做的就是創建一個TextEditor和SpellChecker之間的依賴關係。在控制反轉的場景中,我們反而會做這樣的事情:

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

 

在這裏,TextEditor 不應該擔心 SpellChecker 的實現。SpellChecker 將會獨立實現,並且在 TextEditor 實例化的時候將提供給 TextEditor,整個過程是由 Spring 框架的控制。

在這裏,我們已經從 TextEditor 中刪除了全面控制,並且把它保存到其他地方(即 XML 配置文件),且依賴關係(即 SpellChecker 類)通過類構造函數被注入到 TextEditor 類中。因此,控制流通過依賴注入(DI)已經“反轉”,因爲你已經有效地委託依賴關係到一些外部系統。

依賴注入的第二種方法是通過 TextEditor 類的 Setter 方法,我們將創建 SpellChecker 實例,該實例將被用於調用 setter 方法來初始化 TextEditor 的屬性。

序號 依賴注入類型 & 描述
1 Constructor-based dependency injection當容器調用帶有多個參數的構造函數類時,實現基於構造函數的 DI,每個代表在其他類中的一個依賴關係。
2 Setter-based dependency injection基於 setter 方法的 DI 是通過在調用無參數的構造函數或無參數的靜態工廠方法實例化 bean 之後容器調用 beans 的 setter 方法來實現的。

1、Spring基於構造函數的依賴注入

當容器調用有一組參數的類構造函數時,基於構造函數的DI就完成了,其中每個參數代表一個對其他類的依賴。

例子:

TextEditor.java:

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();
   }
}

SpllChecker.java

package com.tutorialspoint;
public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   } 
}

MainApp.java:

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();
   }
}

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">

   <!-- 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>

</beans>

 

2、構造函數參數解析

如果存在不止一個參數時,把參數傳遞給構造函數時,可能會存在歧義。要解決這個問題,那麼構造函數的參數在bean定義殊勳就是把這些參數提供給適當的構造函數的順序就可以了。

 

3、基於設值函數的依賴注入

當容器調用一個無參的構造函數或一個無參的靜態factory方法來初始化你的bean後,通過容器在你的bean上設值函數,基於設值函數的DI就完成了。


十三、注入內部Beans

正如你所知道的Java內部類是在其他類的範圍內被定義的,同理,inner beans也是在其它bean的範圍內定義的bean。

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="outerBean" class="...">
      <property name="target">
         <bean id="innerBean" class="..."/>
      </property>
   </bean>

</beans>

十四、注入集合

你已經看到了如何使用value屬性來配置基本數據類型,也使用了property標籤的ref屬性來配置對象引用。這兩種情況下處理一個值傳遞給一個bean。

如果你想傳遞多個值,如Java Collection類型List、Set、Map和Properites,那麼有Spring提供了四種類型的集合的配置元素:

元素 描述
<list> 它有助於連線,如注入一列值,允許重複。
<set> 它有助於連線一組值,但不能重複。
<map> 它可以用來注入名稱-值對的集合,其中名稱和值可以是任何類型。
<props> 它可以用來注入名稱-值對的集合,其中名稱和值都是字符串類型。
<?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">

   <!-- Definition for javaCollection -->
   <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>

</beans>

十五、Beans自動裝配

你已經知道使用bean元素來聲明bean和通過使用XML配置文件中的constructor-arg和property元素來注入。

Spring容器可以在不適用constructor-arg和property元素的情況下自動裝配互相協助的bean之間的關係,這有助於減少編寫一個大的基於Spring的應用程序的XML配置的數量。

1、自動裝配模式:

下列自動裝配模式,它們可以用於指示Spring容器爲來使用自動裝配進行依賴注入,你可以使用bean元素的autowire屬性爲一個bean定義自動裝配模式。

模式 描述
no 這是默認的設置,它意味着沒有自動裝配,你應該使用顯式的bean引用來連線。你不用爲了連線做特殊的事。在依賴注入章節你已經看到這個了。
byName 由屬性名自動裝配。Spring 容器看到在 XML 配置文件中 bean 的自動裝配的屬性設置爲 byName。然後嘗試匹配,並且將它的屬性與在配置文件中被定義爲相同名稱的 beans 的屬性進行連接。
byType 由屬性數據類型自動裝配。Spring 容器看到在 XML 配置文件中 bean 的自動裝配的屬性設置爲 byType。然後如果它的類型匹配配置文件中的一個確切的 bean 名稱,它將嘗試匹配和連接屬性的類型。如果存在不止一個這樣的 bean,則一個致命的異常將會被拋出。
constructor 類似於 byType,但該類型適用於構造函數參數類型。如果在容器中沒有一個構造函數參數類型的 bean,則一個致命錯誤將會發生。
autodetect Spring首先嚐試通過 constructor 使用自動裝配來連接,如果它不執行,Spring 嘗試通過 byType 來自動裝配。

2、自動裝配的侷限性

當自動裝配始終在同一個項目中使用時,它的效果最好。如果通常不適用自動裝配,它可能會使開發人員混淆的使用它來連接只有一個或兩個bean定義。不過,自動裝配可以顯著減少需要指定的屬性或構造器屬性,但你應該在使用它們之前考慮到自動裝配的侷限性和缺點。

限制 描述
重寫的可能性 你可以使用總是重寫自動裝配的 <constructor-arg>和 <property> 設置來指定依賴關係。
原始數據類型 你不能自動裝配所謂的簡單類型包括基本類型,字符串和類。
混亂的本質 自動裝配不如顯式裝配精確,所以如果可能的話儘可能使用顯式裝配。

十六、基於註解的配置

從Spring2.5開始就可以使用註解來配置依賴注入。而不是採用XML來描述一個bean連線。你可以使用相關類,方法或字段聲明的註解,將bean配置移動到組件類本身。

在XML注入之前進行註解注入,因此後者的配置將通過兩種方式的屬性連線被前者重寫。

註解連線在默認情況下在Spring容器中打不開。因此,在可以使用基於註解的連線之前,我們將需要我們在Spring配置文件中啓用它。所以如果你想要在Spring應用程序中使用任何註解,可以考慮下面的配置文件:

<?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-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>
   <!-- bean definitions go here -->

</beans>

一旦被配置後,你就可以開始註解你的代碼,表明Spring應該自動鏈接值到屬性、方法和構造函數。讓我們來看看幾個重要的註解:

序號 註解 & 描述
1 @Required@Required 註解應用於 bean 屬性的 setter 方法。
2 @Autowired@Autowired 註解可以應用到 bean 屬性的 setter 方法,非 setter 方法,構造函數和屬性。
3 @Qualifier通過指定確切的將被連線的 bean,@Autowired 和 @Qualifier 註解可以用來刪除混亂。
4 JSR-250 AnnotationsSpring 支持 JSR-250 的基礎的註解,其中包括了 @Resource,@PostConstruct 和 @PreDestroy 註解。

1)Spring @Required註釋

@Required 註釋應用於 bean 屬性的 setter 方法,它表明受影響的 bean 屬性在配置時必須放在 XML 配置文件中,否則容器就會拋出一個 BeanInitializationException 異常。

示例:

讓我們使 Eclipse IDE 處於工作狀態,請按照下列步驟創建一個 Spring 應用程序:

步驟 描述
1 創建一個名爲 SpringExample 的項目,並且在所創建項目的 src 文件夾下創建一個名爲 com.tutorialspoint 的包。
2 使用 Add External JARs 選項添加所需的 Spring 庫文件,就如在 Spring Hello World Example 章節中解釋的那樣。
3 com.tutorialspoint 包下創建 Java 類 StudentMainApp
4 src 文件夾下創建 Beans 配置文件 Beans.xml
5 最後一步是創建所有 Java 文件和 Bean 配置文件的內容,並且按如下解釋的那樣運行應用程序。

下面是 Student.java 文件的內容:

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;
   }
}

下面是 MainApp.java 文件的內容:

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");
      Student student = (Student) context.getBean("student");
      System.out.println("Name : " + student.getName() );
      System.out.println("Age : " + student.getAge() );
   }
}

下面是配置文件 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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>

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

      <!-- try without passing age and check the result -->
      <!-- property name="age"  value="11"-->
   </bean>

</beans>

一旦你已經完成的創建了源文件和 bean 配置文件,讓我們運行一下應用程序。如果你的應用程序一切都正常的話,這將引起 BeanInitializationException 異常,並且會輸出一下錯誤信息和其他日誌消息:

Property 'age' is required for bean 'student'

下一步,在你按照如下所示從 “age” 屬性中刪除了註釋,你可以嘗試運行上面的示例:

<?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-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>

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

</beans>

現在上面的示例將產生如下結果:

Name : Zara
Age : 11

2)Spring @Autowired註釋

@Autowired 註釋對在哪裏和如何完成自動連接提供了更多的細微的控制。

@Autowired 註釋可以在 setter 方法中被用於自動連接 bean,就像 @Autowired 註釋,容器,一個屬性或者任意命名的可能帶有多個參數的方法。

Setter 方法中的 @Autowired

你可以在 XML 文件中的 setter 方法中使用 @Autowired 註釋來除去 元素。當 Spring遇到一個在 setter 方法中使用的 @Autowired 註釋,它會在方法中視圖執行 byType 自動連接。

示例

讓我們使 Eclipse IDE 處於工作狀態,然後按照如下步驟創建一個 Spring 應用程序:

步驟 描述
1 創建一個名爲 SpringExample 的項目,並且在所創建項目的 src 文件夾下創建一個名爲 com.tutorialspoint 的包。
2 使用 Add External JARs 選項添加所需的 Spring 庫文件,就如在 Spring Hello World Example 章節中解釋的那樣。
3 com.tutorialspoint 包下創建 Java 類 TextEditor, SpellCheckerMainApp
4 src 文件夾下創建 Beans 配置文件 Beans.xml
5 最後一步是創建所有 Java 文件和 Bean 配置文件的內容,並且按如下解釋的那樣運行應用程序。

這裏是 TextEditor.java 文件的內容:

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();
   }
}

下面是另一個依賴的類文件 SpellChecker.java 的內容:

package com.tutorialspoint;
public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling(){
      System.out.println("Inside checkSpelling." );
   }  
}

下面是 MainApp.java 文件的內容:

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();
   }
}

下面是配置文件 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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>

   <!-- 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>

</beans>

一旦你已經完成的創建了源文件和 bean 配置文件,讓我們運行一下應用程序。如果你的應用程序一切都正常的話,這將會輸出以下消息:

Inside SpellChecker constructor.
Inside checkSpelling.

屬性中的 @Autowired

你可以在屬性中使用 @Autowired 註釋來除去 setter 方法。當時使用 爲自動連接屬性傳遞的時候,Spring 會將這些傳遞過來的值或者引用自動分配給那些屬性。所以利用在屬性中 @Autowired 的用法,你的 TextEditor.java 文件將變成如下所示:

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();
   }
}

下面是配置文件 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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
   </bean>

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

</beans>

一旦你在源文件和 bean 配置文件中完成了上面兩處改變,讓我們運行一下應用程序。如果你的應用程序一切都正常的話,這將會輸出以下消息:

Inside TextEditor constructor.
Inside SpellChecker constructor.
Inside checkSpelling.

構造函數中的 @Autowired

你也可以在構造函數中使用 @Autowired。一個構造函數 @Autowired 說明當創建 bean 時,即使在 XML 文件中沒有使用 元素配置 bean ,構造函數也會被自動連接。讓我們檢查一下下面的示例。

這裏是 TextEditor.java 文件的內容:

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();
   }
}

下面是配置文件 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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>

   <!-- 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>

</beans>

一旦你在源文件和 bean 配置文件中完成了上面兩處改變,讓我們運行一下應用程序。如果你的應用程序一切都正常的話,這將會輸出以下消息:

Inside SpellChecker constructor.Inside TextEditor constructor.
Inside checkSpelling.

@Autowired 的(required=false)選項

默認情況下,@Autowired 註釋意味着依賴是必須的,它類似於 @Required 註釋,然而,你可以使用 @Autowired 的 (required=false) 選項關閉默認行爲。

即使你不爲 age 屬性傳遞任何參數,下面的示例也會成功運行,但是對於 name 屬性則需要一個參數。你可以自己嘗試一下這個示例,因爲除了只有 Student.java 文件被修改以外,它和 @Required 註釋示例是相似的。

package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class Student {
   private Integer age;
   private String name;
   @Autowired(required=false)
   public void setAge(Integer age) {
      this.age = age;
   }  
   public Integer getAge() {
      return age;
   }
   @Autowired
   public void setName(String name) {
      this.name = name;
   }   
   public String getName() {
      return name;
   }
}

3)Spring@Quqlifier註釋

可能會有這樣一種情況,當你創建多個具有相同類型的 bean 時,並且想要用一個屬性只爲它們其中的一個進行裝配,在這種情況下,你可以使用 @Qualifier 註釋和 @Autowired 註釋通過指定哪一個真正的 bean 將會被裝配來消除混亂。

4)Spring JSR-250註釋

Spring還使用基於 JSR-250 註釋,它包括 @PostConstruct, @PreDestroy 和 @Resource 註釋。因爲你已經有了其他的選擇,儘管這些註釋並不是真正所需要的,但是關於它們仍然讓我給出一個簡短的介紹。

@PostConstruct 和 @PreDestroy 註釋:

爲了定義一個 bean 的安裝和卸載,我們使用 init-method 和/或 destroy-method 參數簡單的聲明一下 。init-method 屬性指定了一個方法,該方法在 bean 的實例化階段會立即被調用。同樣地,destroy-method 指定了一個方法,該方法只在一個 bean 從容器中刪除之前被調用。

你可以使用 @PostConstruct 註釋作爲初始化回調函數的一個替代,@PreDestroy 註釋作爲銷燬回調函數的一個替代。


十七、Spring基於Java的配置

到現在,你已經會使用XML配置文件來配置Spring bean。如果你熟悉使用XML配置,那麼不需要在學習任何進行基於Java的配置。

基於 Java 的配置選項,可以使你在不用配置 XML 的情況下編寫大多數的 Spring,但是一些有幫助的基於 Java 的註解,解釋如下:

@Configuration 和 @Bean 註解

帶有 @Configuration 的註解類表示這個類可以使用 Spring IoC 容器作爲 bean 定義的來源。@Bean 註解告訴 Spring,一個帶有 @Bean 的註解方法將返回一個對象,該對象應該被註冊爲在 Spring 應用程序上下文中的 bean。最簡單可行的 @Configuration 類如下所示:

package com.tutorialspoint;
import org.springframework.context.annotation.*;
@Configuration
public class HelloWorldConfig {
   @Bean 
   public HelloWorld helloWorld(){
      return new HelloWorld();
   }
}

等同於XML配置:

<beans>
   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld" />
</beans>

十八、Spring中的事件處理

Spring 的核心是 ApplicationContext,它負責管理 beans 的完整生命週期。當加載 beans 時,ApplicationContext 發佈某些類型的事件。例如,當上下文啓動時,ContextStartedEvent 發佈,當上下文停止時,ContextStoppedEvent 發佈。

通過 ApplicationEvent 類和 ApplicationListener 接口來提供在 ApplicationContext 中處理事件。如果一個 bean 實現 ApplicationListener,那麼每次 ApplicationEvent 被髮布到 ApplicationContext 上,那個 bean 會被通知。

Spring 提供了以下的標準事件:

序號 Spring 內置事件 & 描述
1 ContextRefreshedEventApplicationContext 被初始化或刷新時,該事件被髮布。這也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法來發生。
2 ContextStartedEvent當使用 ConfigurableApplicationContext 接口中的 start() 方法啓動 ApplicationContext 時,該事件被髮布。你可以調查你的數據庫,或者你可以在接受到這個事件後重啓任何停止的應用程序。
3 ContextStoppedEvent當使用 ConfigurableApplicationContext 接口中的 stop() 方法停止 ApplicationContext 時,發佈這個事件。你可以在接受到這個事件後做必要的清理的工作。
4 ContextClosedEvent當使用 ConfigurableApplicationContext 接口中的 close() 方法關閉 ApplicationContext 時,該事件被髮布。一個已關閉的上下文到達生命週期末端;它不能被刷新或重啓。
5 RequestHandledEvent這是一個 web-specific 事件,告訴所有 bean HTTP 請求已經被服務。

十九、Spring中的自定義事件

步驟:

步驟 描述
1 創建一個名稱爲 SpringExample 的項目,並且在創建項目的 src 文件夾中創建一個包 com.tutorialspoint。
2 使用 Add External JARs 選項,添加所需的 Spring 庫,解釋見 Spring Hello World Example 章節。
3 通過擴展 ApplicationEvent,創建一個事件類 CustomEvent。這個類必須定義一個默認的構造函數,它應該從 ApplicationEvent 類中繼承的構造函數。
4 一旦定義事件類,你可以從任何類中發佈它,假定 EventClassPublisher 實現了 ApplicationEventPublisherAware。你還需要在 XML 配置文件中聲明這個類作爲一個 bean,之所以容器可以識別 bean 作爲事件發佈者,是因爲它實現了 ApplicationEventPublisherAware 接口。
5 發佈的事件可以在一個類中被處理,假定 EventClassHandler 實現了 ApplicationListener 接口,而且實現了自定義事件的 onApplicationEvent 方法。
6 src 文件夾中創建 bean 的配置文件 Beans.xml 和 MainApp 類,它可以作爲一個 Spring 應用程序來運行。
7 最後一步是創建的所有 Java 文件和 Bean 配置文件的內容,並運行應用程序,解釋如下所示。

二十、AOP術語

讓我們熟悉一下AOP概念和術語:

描述
Aspect 一個模塊具有一組提供橫切需求的 APIs。例如,一個日誌模塊爲了記錄日誌將被 AOP 方面調用。應用程序可以擁有任意數量的方面,這取決於需求。
Join point 在你的應用程序中它代表一個點,你可以在插件 AOP 方面。你也能說,它是在實際的應用程序中,其中一個操作將使用 Spring AOP 框架。
Advice 這是實際行動之前或之後執行的方法。這是在程序執行期間通過 Spring AOP 框架實際被調用的代碼。
Pointcut 這是一組一個或多個連接點,通知應該被執行。你可以使用表達式或模式指定切入點正如我們將在 AOP 的例子中看到的。
Introduction 引用允許你添加新方法或屬性到現有的類中。
Target object 被一個或者多個方面所通知的對象,這個對象永遠是一個被代理對象。也稱爲被通知對象。
Weaving Weaving 把方面連接到其它的應用程序類型或者對象上,並創建一個被通知的對象。這些可以在編譯時,類加載時和運行時完成。

1、通知類型:

通知 描述
前置通知 在一個方法執行之前,執行通知。
後置通知 在一個方法執行之後,不考慮其結果,執行通知。
返回後通知 在一個方法執行之後,只有在方法成功完成時,才能執行通知。
拋出異常後通知 在一個方法執行之後,只有在方法退出拋出異常時,才能執行通知。
環繞通知 在建議方法調用之前和之後,執行通知。

2、實現自定義切面

Spring 支持 @AspectJ annotation style 的方法和基於模式的方法來實現自定義方面。這兩種方法已經在下面兩個子節進行了詳細解釋。

方法 描述
XML Schema based 方面是使用常規類以及基於配置的 XML 來實現的。
@AspectJ based @AspectJ 引用一種聲明方面的風格作爲帶有 Java 5 註釋的常規 Java 類註釋。

二十一、Spring中基於AOP的XML架構

使用aop命名空間標籤,需要導入spring-aop j框架,如:

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

   <!-- bean definition & AOP specific configuration -->

1、聲明一個aspect

一個 aspect 是使用 元素聲明的,支持的 bean 是使用 ref 屬性引用的,如下所示:

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

2、聲明一個切入點

一個切入點有助於確定使用不同建議執行的感興趣的連接點(即方法)。在處理基於配置的 XML 架構時,切入點將會按照如下所示定義:

<aop:config>
   <aop:aspect id="myAspect" ref="aBean">
   <aop:pointcut id="businessService"
      expression="execution(* com.xyz.myapp.service.*.*(..))"/>
   ...
   </aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>

二十二、Spring 中基於AOP的@AspectJ

@AspectJ 作爲通過 Java 5 註釋註釋的普通的 Java 類,它指的是聲明 aspects 的一種風格。通過在你的基於架構的 XML 配置文件中包含以下元素,@AspectJ 支持是可用的。

<aop:aspectj-autoproxy/>

1、聲明一個aspect

Aspects 類和其他任何正常的 bean 一樣,除了它們將會用 @AspectJ 註釋之外,它和其他類一樣可能有方法和字段,如下所示:

package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AspectModule {
}

二十三、Spring JDBC框架

1、JDBC框架概述

在使用普通的 JDBC 數據庫時,就會很麻煩的寫不必要的代碼來處理異常,打開和關閉數據庫連接等。但 Spring JDBC 框架負責所有的低層細節,從開始打開連接,準備和執行 SQL 語句,處理異常,處理事務,到最後關閉連接。

所以當從數據庫中獲取數據時,你所做的是定義連接參數,指定要執行的 SQL 語句,每次迭代完成所需的工作。

Spring JDBC 提供幾種方法和數據庫中相應的不同的類與接口。我將給出使用 JdbcTemplate 類框架的經典和最受歡迎的方法。這是管理所有數據庫通信和異常處理的中央框架類。

2、JdbcTemplate類

JdbcTemplate 類執行 SQL 查詢、更新語句和存儲過程調用,執行迭代結果集和提取返回參數值。它也捕獲 JDBC 異常並轉換它們到 org.springframework.dao 包中定義的通用類、更多的信息、異常層次結構。

JdbcTemplate* 類的實例是線程安全配置的。所以你可以配置 JdbcTemplate 的單個實例,然後將這個共享的引用安全地注入到多個 DAOs 中。

使用 JdbcTemplate 類時常見的做法是在你的 Spring 配置文件中配置數據源,然後共享數據源 bean 依賴注入到 DAO 類中,並在數據源的設值函數中創建了 JdbcTemplate。

3、配置數據源

我們在數據庫 TEST 中創建一個數據庫表 Student。假設你正在使用 MySQL 數據庫,如果你使用其他數據庫,那麼你可以改變你的 DDL 和相應的 SQL 查詢。

CREATE TABLE Student(
   ID   INT NOT NULL AUTO_INCREMENT,
   NAME VARCHAR(20) NOT NULL,
   AGE  INT NOT NULL,
   PRIMARY KEY (ID)
);

現在,我們需要提供一個數據源到 JdbcTemplate 中,所以它可以配置本身來獲得數據庫訪問。你可以在 XML 文件中配置數據源,其中一段代碼如下所示:

<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
   <property name="url" value="jdbc:mysql://localhost:3306/TEST"/>
   <property name="username" value="root"/>
   <property name="password" value="password"/>
</bean>

4、執行SQL語句

我們看看如何使用 SQL 和 jdbcTemplate 對象在數據庫表中執行 CRUD(創建、讀取、更新和刪除)操作。

查詢一個整數類型:

String SQL = "select count(*) from Student";
int rowCount = jdbcTemplateObject.queryForInt( SQL );

查詢一個 long 類型:

String SQL = "select count(*) from Student";
long rowCount = jdbcTemplateObject.queryForLong( SQL );

一個使用綁定變量的簡單查詢:

String SQL = "select age from Student where id = ?";
int age = jdbcTemplateObject.queryForInt(SQL, new Object[]{10});

查詢字符串:

String SQL = "select name from Student where id = ?";
String name = jdbcTemplateObject.queryForObject(SQL, new Object[]{10}, String.class);

查詢並返回一個對象:

String SQL = "select * from Student where id = ?";
Student student = jdbcTemplateObject.queryForObject(SQL, 
                  new Object[]{10}, new StudentMapper());
public class StudentMapper implements RowMapper<Student> {
   public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
      Student student = new Student();
      student.setID(rs.getInt("id"));
      student.setName(rs.getString("name"));
      student.setAge(rs.getInt("age"));
      return student;
   }
}

查詢並返回多個對象:

String SQL = "select * from Student";
List<Student> students = jdbcTemplateObject.query(SQL,
                         new StudentMapper());
public class StudentMapper implements RowMapper<Student> {
   public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
      Student student = new Student();
      student.setID(rs.getInt("id"));
      student.setName(rs.getString("name"));
      student.setAge(rs.getInt("age"));
      return student;
   }
}

在表中插入一行:

String SQL = "insert into Student (name, age) values (?, ?)";
jdbcTemplateObject.update( SQL, new Object[]{"Zara", 11} );

更新表中的一行:

String SQL = "update Student set name = ? where id = ?";
jdbcTemplateObject.update( SQL, new Object[]{"Zara", 10} );

從表中刪除一行:

String SQL = "delete Student where id = ?";
jdbcTemplateObject.update( SQL, new Object[]{20} );

5、執行DDL語句

你可以使用 jdbcTemplate 中的 execute(..) 方法來執行任何 SQL 語句或 DDL 語句。下面是一個使用 CREATE 語句創建一個表的示例:

String SQL = "CREATE TABLE Student( " +
   "ID   INT NOT NULL AUTO_INCREMENT, " +
   "NAME VARCHAR(20) NOT NULL, " +
   "AGE  INT NOT NULL, " +
   "PRIMARY KEY (ID));"
jdbcTemplateObject.execute( SQL );

6、Spring JDBC框架例子:

步驟 描述
1 創建一個名爲 SpringExample 的項目,並在創建的項目中的 src 文件夾下創建包 com.tutorialspoint
2 使用 Add External JARs 選項添加必需的 Spring 庫,解釋見 Spring Hello World Example 章節。
3 在項目中添加 Spring JDBC 指定的最新的庫 mysql-connector-java.jarorg.springframework.jdbc.jarorg.springframework.transaction.jar。如果這些庫不存在,你可以下載它們。
4 創建 DAO 接口 StudentDAO 並列出所有必需的方法。儘管這一步不是必需的而且你可以直接編寫 StudentJDBCTemplate 類,但是作爲一個好的實踐,我們最好還是做這一步。
5 com.tutorialspoint 包下創建其他的必需的 Java 類 StudentStudentMapperStudentJDBCTemplateMainApp
6 確保你已經在 TEST 數據庫中創建了 Student 表。並確保你的 MySQL 服務器運行正常,且你可以使用給出的用戶名和密碼讀/寫訪問數據庫。
7 src 文件夾下創建 Beans 配置文件 Beans.xml
8 最後一步是創建所有的 Java 文件和 Bean 配置文件的內容並按照如下所示的方法運行應用程序。

1)數據庫接口文件StudentDAO.java

package com.tutorialspoint;
import java.util.List;
import javax.sql.DataSource;
public interface StudentDAO {
   /** 
    * This is the method to be used to initialize
    * database resources ie. connection.
    */
   public void setDataSource(DataSource ds);
   /** 
    * This is the method to be used to create
    * a record in the Student table.
    */
   public void create(String name, Integer age);
   /** 
    * This is the method to be used to list down
    * a record from the Student table corresponding
    * to a passed student id.
    */
   public Student getStudent(Integer id);
   /** 
    * This is the method to be used to list down
    * all the records from the Student table.
    */
   public List<Student> listStudents();
   /** 
    * This is the method to be used to delete
    * a record from the Student table corresponding
    * to a passed student id.
    */
   public void delete(Integer id);
   /** 
    * This is the method to be used to update
    * a record into the Student table.
    */
   public void update(Integer id, Integer age);
}

Stuent.java:

package com.tutorialspoint;
public class Student {
   private Integer age;
   private String name;
   private Integer id;
   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;
   }
   public void setId(Integer id) {
      this.id = id;
   }
   public Integer getId() {
      return id;
   }
}

StudentMapper.java

package com.tutorialspoint;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
public class StudentMapper implements RowMapper<Student> {
   public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
      Student student = new Student();
      student.setId(rs.getInt("id"));
      student.setName(rs.getString("name"));
      student.setAge(rs.getInt("age"));
      return student;
   }
}

下面定義的DAO接口StudentDAO的實現類:

StudentJDBCTemplate.java:

package com.tutorialspoint;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class StudentJDBCTemplate implements StudentDAO {
   private DataSource dataSource;
   private JdbcTemplate jdbcTemplateObject; 
   public void setDataSource(DataSource dataSource) {
      this.dataSource = dataSource;
      this.jdbcTemplateObject = new JdbcTemplate(dataSource);
   }
   public void create(String name, Integer age) {
      String SQL = "insert into Student (name, age) values (?, ?)";     
      jdbcTemplateObject.update( SQL, name, age);
      System.out.println("Created Record Name = " + name + " Age = " + age);
      return;
   }
   public Student getStudent(Integer id) {
      String SQL = "select * from Student where id = ?";
      Student student = jdbcTemplateObject.queryForObject(SQL, 
                        new Object[]{id}, new StudentMapper());
      return student;
   }
   public List<Student> listStudents() {
      String SQL = "select * from Student";
      List <Student> students = jdbcTemplateObject.query(SQL, 
                                new StudentMapper());
      return students;
   }
   public void delete(Integer id){
      String SQL = "delete from Student where id = ?";
      jdbcTemplateObject.update(SQL, id);
      System.out.println("Deleted Record with ID = " + id );
      return;
   }
   public void update(Integer id, Integer age){
      String SQL = "update Student set age = ? where id = ?";
      jdbcTemplateObject.update(SQL, age, id);
      System.out.println("Updated Record with ID = " + id );
      return;
   }
}

MainApp.java:

package com.tutorialspoint;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.tutorialspoint.StudentJDBCTemplate;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = 
             new ClassPathXmlApplicationContext("Beans.xml");
      StudentJDBCTemplate studentJDBCTemplate = 
      (StudentJDBCTemplate)context.getBean("studentJDBCTemplate");    
      System.out.println("------Records Creation--------" );
      studentJDBCTemplate.create("Zara", 11);
      studentJDBCTemplate.create("Nuha", 2);
      studentJDBCTemplate.create("Ayan", 15);
      System.out.println("------Listing Multiple Records--------" );
      List<Student> students = studentJDBCTemplate.listStudents();
      for (Student record : students) {
         System.out.print("ID : " + record.getId() );
         System.out.print(", Name : " + record.getName() );
         System.out.println(", Age : " + record.getAge());
      }
      System.out.println("----Updating Record with ID = 2 -----" );
      studentJDBCTemplate.update(2, 20);
      System.out.println("----Listing Record with ID = 2 -----" );
      Student student = studentJDBCTemplate.getStudent(2);
      System.out.print("ID : " + student.getId() );
      System.out.print(", Name : " + student.getName() );
      System.out.println(", Age : " + student.getAge());      
   }
}

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 ">

   <!-- Initialization for data source -->
   <bean id="dataSource" 
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
      <property name="url" value="jdbc:mysql://localhost:3306/TEST"/>
      <property name="username" value="root"/>
      <property name="password" value="password"/>
   </bean>

   <!-- Definition for studentJDBCTemplate bean -->
   <bean id="studentJDBCTemplate" 
      class="com.tutorialspoint.StudentJDBCTemplate">
      <property name="dataSource"  ref="dataSource" />    
   </bean>

</beans>

二十四、Spring中SQL的存儲過程

SimpleJdbcCall 類可以被用於調用一個包含 IN 和 OUT 參數的存儲過程。你可以在處理任何一個 RDBMS 時使用這個方法,就像 Apache Derby, DB2, MySQL, Microsoft SQL Server, Oracle,和 Sybase。


二十五、Spring事務管理

事務管理

一個數據庫事務是一個被視爲單一的工作單元的操作序列。這些操作應該要麼完整地執行,要麼完全不執行。事務管理是一個重要組成部分,RDBMS 面向企業應用程序,以確保數據完整性和一致性。事務的概念可以描述爲具有以下四個關鍵屬性說成是 ACID

  • 原子性:事務應該當作一個單獨單元的操作,這意味着整個序列操作要麼是成功,要麼是失敗的。

  • 一致性:這表示數據庫的引用完整性的一致性,表中唯一的主鍵等。

  • 隔離性:可能同時處理很多有相同的數據集的事務,每個事務應該與其他事務隔離,以防止數據損壞。

  • 持久性:一個事務一旦完成全部操作後,這個事務的結果必須是永久性的,不能因系統故障而從數據庫中刪除。

一個真正的 RDBMS 數據庫系統將爲每個事務保證所有的四個屬性。使用 SQL 發佈到數據庫中的事務的簡單視圖如下:

  • 使用 begin transaction 命令開始事務。

  • 使用 SQL 查詢語句執行各種刪除、更新或插入操作。

  • 如果所有的操作都成功,則執行提交操作,否則回滾所有操作。

Spring 框架在不同的底層事務管理 APIs 的頂部提供了一個抽象層。Spring 的事務支持旨在通過添加事務能力到 POJOs 來提供給 EJB 事務一個選擇方案。Spring 支持編程式和聲明式事務管理。EJBs 需要一個應用程序服務器,但 Spring 事務管理可以在不需要應用程序服務器的情況下實現。

局部事物 vs. 全局事務

局部事務是特定於一個單一的事務資源,如一個 JDBC 連接,而全局事務可以跨多個事務資源事務,如在一個分佈式系統中的事務。

局部事務管理在一個集中的計算環境中是有用的,該計算環境中應用程序組件和資源位於一個單位點,而事務管理只涉及到一個運行在一個單一機器中的本地數據管理器。局部事務更容易實現。

全局事務管理需要在分佈式計算環境中,所有的資源都分佈在多個系統中。在這種情況下事務管理需要同時在局部和全局範圍內進行。分佈式或全局事務跨多個系統執行,它的執行需要全局事務管理系統和所有相關係統的局部數據管理人員之間的協調。

編程式 vs. 聲明式

Spring 支持兩種類型的事務管理:

  • 編程式事務管理 :這意味着你在編程的幫助下有管理事務。這給了你極大的靈活性,但卻很難維護。

  • 聲明式事務管理 :這意味着你從業務代碼中分離事務管理。你僅僅使用註釋或 XML 配置來管理事務。

聲明式事務管理比編程式事務管理更可取,儘管它不如編程式事務管理靈活,但它允許你通過代碼控制事務。但作爲一種橫切關注點,聲明式事務管理可以使用 AOP 方法進行模塊化。Spring 支持使用 Spring AOP 框架的聲明式事務管理。

Spring 事務抽象

Spring 事務抽象的關鍵是由 org.springframework.transaction.PlatformTransactionManager 接口定義,如下所示:

 

public interface PlatformTransactionManager {
   TransactionStatus getTransaction(TransactionDefinition definition);
   throws TransactionException;
   void commit(TransactionStatus status) throws TransactionException;
   void rollback(TransactionStatus status) throws TransactionException;
}
序號 方法 & 描述
1 TransactionStatus getTransaction(TransactionDefinition definition)根據指定的傳播行爲,該方法返回當前活動事務或創建一個新的事務。
2 void commit(TransactionStatus status)該方法提交給定的事務和關於它的狀態。
3 void rollback(TransactionStatus status)該方法執行一個給定事務的回滾。

TransactionDefinition 是在 Spring 中事務支持的核心接口,它的定義如下:

 

public interface TransactionDefinition {
   int getPropagationBehavior();
   int getIsolationLevel();
   String getName();
   int getTimeout();
   boolean isReadOnly();
}
序號 方法 & 描述
1 int getPropagationBehavior()該方法返回傳播行爲。Spring 提供了與 EJB CMT 類似的所有的事務傳播選項。
2 int getIsolationLevel()該方法返回該事務獨立於其他事務的工作的程度。
3 String getName()該方法返回該事務的名稱。
4 int getTimeout()該方法返回以秒爲單位的時間間隔,事務必須在該時間間隔內完成。
5 boolean isReadOnly()該方法返回該事務是否是隻讀的。

下面是隔離級別的可能值:

序號 隔離 & 描述
1 TransactionDefinition.ISOLATION_DEFAULT這是默認的隔離級別。
2 TransactionDefinition.ISOLATION_READ_COMMITTED表明能夠阻止誤讀;可以發生不可重複讀和虛讀。
3 TransactionDefinition.ISOLATION_READ_UNCOMMITTED表明可以發生誤讀、不可重複讀和虛讀。
4 TransactionDefinition.ISOLATION_REPEATABLE_READ表明能夠阻止誤讀和不可重複讀;可以發生虛讀。
5 TransactionDefinition.ISOLATION_SERIALIZABLE表明能夠阻止誤讀、不可重複讀和虛讀。

下面是傳播類型的可能值:

序號 傳播 & 描述
1 TransactionDefinition.PROPAGATION_MANDATORY支持當前事務;如果不存在當前事務,則拋出一個異常。
2 TransactionDefinition.PROPAGATION_NESTED如果存在當前事務,則在一個嵌套的事務中執行。
3 TransactionDefinition.PROPAGATION_NEVER不支持當前事務;如果存在當前事務,則拋出一個異常。
4 TransactionDefinition.PROPAGATION_NOT_SUPPORTED不支持當前事務;而總是執行非事務性。
5 TransactionDefinition.PROPAGATION_REQUIRED支持當前事務;如果不存在事務,則創建一個新的事務。
6 TransactionDefinition.PROPAGATION_REQUIRES_NEW創建一個新事務,如果存在一個事務,則把當前事務掛起。
7 TransactionDefinition.PROPAGATION_SUPPORTS支持當前事務;如果不存在,則執行非事務性。
8 TransactionDefinition.TIMEOUT_DEFAULT使用默認超時的底層事務系統,或者如果不支持超時則沒有。

TransactionStatus 接口爲事務代碼提供了一個簡單的方法來控制事務的執行和查詢事務狀態。

 

public interface TransactionStatus extends SavepointManager {
   boolean isNewTransaction();
   boolean hasSavepoint();
   void setRollbackOnly();
   boolean isRollbackOnly();
   boolean isCompleted();
}
序號 方法 & 描述
1 boolean hasSavepoint()該方法返回該事務內部是否有一個保存點,也就是說,基於一個保存點已經創建了嵌套事務。
2 boolean isCompleted()該方法返回該事務是否完成,也就是說,它是否已經提交或回滾。
3 boolean isNewTransaction()在當前事務時新的情況下,該方法返回 true。
4 boolean isRollbackOnly()該方法返回該事務是否已標記爲 rollback-only。
5 void setRollbackOnly()該方法設置該事務爲 rollback-only 標記。

二十六、Spring Web MVC框架

MVC 框架提供了模型-視圖-控制的體系結構和可以用來開發靈活、鬆散耦合的 web 應用程序的組件。MVC 模式導致了應用程序的不同方面(輸入邏輯、業務邏輯和 UI 邏輯)的分離,同時提供了在這些元素之間的鬆散耦合。

  • 模型封裝了應用程序數據,並且通常它們由 POJO 組成。

  • 視圖主要用於呈現模型數據,並且通常它生成客戶端的瀏覽器可以解釋的 HTML 輸出。

  • 控制器主要用於處理用戶請求,並且構建合適的模型並將其傳遞到視圖呈現。

DispatcherServlet

Spring Web 模型-視圖-控制(MVC)框架是圍繞 DispatcherServlet 設計的,DispatcherServlet 用來處理所有的 HTTP 請求和響應。Spring Web MVC DispatcherServlet 的請求處理的工作流程如下圖所示:

 

下面是對應於 DispatcherServlet 傳入 HTTP 請求的事件序列:

  • 收到一個 HTTP 請求後,DispatcherServlet 根據 HandlerMapping 來選擇並且調用適當的控制器

  • 控制器接受請求,並基於使用的 GET 或 POST 方法來調用適當的 service 方法。Service 方法將設置基於定義的業務邏輯的模型數據,並返回視圖名稱到 DispatcherServlet 中。

  • DispatcherServlet 會從 ViewResolver 獲取幫助,爲請求檢取定義視圖。

  • 一旦確定視圖,DispatcherServlet 將把模型數據傳遞給視圖,最後呈現在瀏覽器中。

上面所提到的所有組件,即 HandlerMapping、Controller 和 ViewResolver 是 WebApplicationContext 的一部分,而 WebApplicationContext 是帶有一些對 web 應用程序必要的額外特性的 ApplicationContext 的擴展。

需求的配置

你需要映射你想讓 DispatcherServlet 處理的請求,通過使用在 web.xml 文件中的一個 URL 映射。下面是一個顯示聲明和映射 HelloWeb DispatcherServlet 的示例:

 

web.xml 文件將被保留在你的應用程序的 WebContent/WEB-INF 目錄下。好的,在初始化 HelloWeb DispatcherServlet 時,該框架將嘗試加載位於該應用程序的 WebContent/WEB-INF 目錄中文件名爲 [servlet-name]-servlet.xml 的應用程序內容。在這種情況下,我們的文件將是 HelloWeb-servlet.xml

接下來,`` 標籤表明哪些 URLs 將被 DispatcherServlet 處理。這裏所有以 .jsp 結束的 HTTP 請求將由 HelloWeb DispatcherServle t處理。

如果你不想使用默認文件名 [servlet-name]-servlet.xml 和默認位置 WebContent/WEB-INF,你可以通過在 web.xml 文件中添加 servlet 監聽器 ContextLoaderListener 自定義該文件的名稱和位置,如下所示:

<web-app...>

....
<context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/HelloWeb-servlet.xml</param-value>
</context-param>
<listener>
   <listener-class>
      org.springframework.web.context.ContextLoaderListener
   </listener-class>
</listener>
</web-app>

現在,檢查 HelloWeb-servlet.xml 文件的請求配置,該文件位於 web 應用程序的 WebContent/WEB-INF 目錄下:

 

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   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
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:component-scan base-package="com.tutorialspoint" />

   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/WEB-INF/jsp/" />
      <property name="suffix" value=".jsp" />
   </bean>

</beans>

以下是關於 HelloWeb-servlet.xml 文件的一些要點:

  • [servlet-name]-servlet.xml 文件將用於創建 bean 定義,重新定義在全局範圍內具有相同名稱的任何已定義的 bean。

  • `` 標籤將用於激活 Spring MVC 註釋掃描功能,該功能允許使用註釋,如 @Controller 和 @RequestMapping 等等。

  • InternalResourceViewResolver 將使用定義的規則來解決視圖名稱。按照上述定義的規則,一個名稱爲 hello 的邏輯視圖將發送給位於 /WEB-INF/jsp/hello.jsp 中實現的視圖。

下一節將向你展示如何創建實際的組件,例如控制器,模式和視圖。

定義控制器

DispatcherServlet 發送請求到控制器中執行特定的功能。@Controller 註釋表明一個特定類是一個控制器的作用。@RequestMapping 註釋用於映射 URL 到整個類或一個特定的處理方法。

 

@Controller
@RequestMapping("/hello")
public class HelloController{
   @RequestMapping(method = RequestMethod.GET)
   public String printHello(ModelMap model) {
      model.addAttribute("message", "Hello Spring MVC Framework!");
      return "hello";
   }
}

@Controller 註釋定義該類作爲一個 Spring MVC 控制器。在這裏,第一次使用的 @RequestMapping 表明在該控制器中處理的所有方法都是相對於 /hello 路徑的。下一個註釋 @RequestMapping(method = RequestMethod.GET) 用於聲明 printHello() 方法作爲控制器的默認 service 方法來處理 HTTP GET 請求。你可以在相同的 URL 中定義其他方法來處理任何 POST 請求。

你可以用另一種形式來編寫上面的控制器,你可以在 @RequestMapping 中添加額外的屬性,如下所示:

 

@Controller
public class HelloController{
   @RequestMapping(value = "/hello", method = RequestMethod.GET)
   public String printHello(ModelMap model) {
      model.addAttribute("message", "Hello Spring MVC Framework!");
      return "hello";
   }
}

屬性表明 URL 映射到哪個處理方法,方法屬性定義了 service 方法來處理 HTTP GET 請求。關於上面定義的控制器,這裏有以下幾個要注意的要點:

  • 你將在一個 service 方法中定義需要的業務邏輯。你可以根據每次需求在這個方法中調用其他方法。

  • 基於定義的業務邏輯,你將在這個方法中創建一個模型。你可以設置不同的模型屬性,這些屬性將被視圖訪問並顯示最終的結果。這個示例創建了一個帶有屬性 “message” 的模型。

  • 一個定義的 service 方法可以返回一個包含視圖名稱的字符串用於呈現該模型。這個示例返回 “hello” 作爲邏輯視圖的名稱。

創建 JSP 視圖

對於不同的表示技術,Spring MVC 支持許多類型的視圖。這些包括 JSP、HTML、PDF、Excel 工作表、XML、Velocity 模板、XSLT、JSON、Atom 和 RSS 提要、JasperReports 等等。但我們最常使用利用 JSTL 編寫的 JSP 模板。所以讓我們在 /WEB-INF/hello/hello.jsp 中編寫一個簡單的 hello 視圖:

<html>
   <head>
   <title>Hello Spring MVC</title>
   </head>
   <body>
   <h2>${message}</h2>
   </body>
</html>

其中,${message} 是我們在控制器內部設置的屬性。你可以在你的視圖中有多個屬性顯示。

Spring Web MVC 框架例子

基於上述概念,讓我們看看一些重要的例子來幫助你建立 Spring Web 應用程序:

序號 例子 & 描述
1 Spring MVC Hello World Example這個例子將解釋如何編寫一個簡單的 Spring Web Hello World 應用程序。
2 Spring MVC Form Handling Example這個例子將解釋如何編寫一個 Spring Web 應用程序,它使用 HTML 表單提交數據到控制器,並且顯示處理結果。
3 Spring Page Redirection Example學習在 Spring MVC 框架中如何使用頁面重定向功能。
4 Spring Static Pages Example學習在 Spring MVC 框架中如何訪問靜態頁面和動態頁面。
5 Spring Exception Handling Example學習在 Spring MVC 框架中如何處理異常。

二十七、Spring MVC Hello World例子

1、HelloController.java文件

這裏是 HelloController.java 文件的內容:

package com.tutorialspoint;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.ui.ModelMap;
@Controller
@RequestMapping("/hello")
public class HelloController{ 
   @RequestMapping(method = RequestMethod.GET)
   public String printHello(ModelMap model) {
      model.addAttribute("message", "Hello Spring MVC Framework!");
      return "hello";
   }
}

下面是 Spring Web 配置文件 web.xml 的內容

<web-app id="WebApp_ID" version="2.4"
   xmlns="http://java.sun.com/xml/ns/j2ee" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

   <display-name>Spring MVC Application</display-name>

   <servlet>
      <servlet-name>HelloWeb</servlet-name>
      <servlet-class>
         org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>

   <servlet-mapping>
      <servlet-name>HelloWeb</servlet-name>
      <url-pattern>/</url-pattern>
   </servlet-mapping>

</web-app>

下面是另一個 Spring Web 配置文件 HelloWeb-servlet.xml 的內容

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   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
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:component-scan base-package="com.tutorialspoint" />

   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/WEB-INF/jsp/" />
      <property name="suffix" value=".jsp" />
   </bean>

</beans>

下面是 Spring 視圖文件 hello.jsp 的內容

<%@ page contentType="text/html; charset=UTF-8" %>
<html>
<head>
<title>Hello World</title>
</head>
<body>
   <h2>${message}</h2>
</body>
</html>

二十八、Spring MVC表單處理例子

Spring MVC 表單處理例子

下面的例子說明了如何編寫一個簡單的基於 web 的應用程序,它利用了使用 Spring 的 Web MVC 框架的 HTML 表單。爲了開始使用它,讓我們在恰當的位置使用 Eclipse IDE,然後按照下面的步驟使用 Spring 的 Web 框架來開發一個動態的基於表單的 Web 應用程序:

步驟 描述
1 創建一個名稱爲 HelloWeb動態 Web 項目,並且在已創建的項目的 src 文件夾中創建一個包 com.tutorialspoint
2 將上面提到的 Spring 和其他庫拖拽到文件夾 WebContent/WEB-INF/lib 中。
3 com.tutorialspoint 包下創建一個 Java 類 StudentStudentController
4 WebContent/WEB-INF 文件夾下創建 Spring 的配置文件 Web.xmlHelloWeb-servlet.xml
5 WebContent/WEB-INF 文件夾下創建名稱爲 jsp 的子文件夾。在這個子文件夾下創建視圖文件 student.jspresult.jsp
6 最後一步是創建所有的源代碼和配置文件的內容,並導出該應用程序,正如下面解釋的一樣。

這裏是 Student.java 文件的內容:

package com.tutorialspoint;
public class Student {
   private Integer age;
   private String name;
   private Integer id;
   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;
   }
   public void setId(Integer id) {
      this.id = id;
   }
   public Integer getId() {
      return id;
   }
}

下面是 StudentController.java 文件的內容:

package com.tutorialspoint;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.ui.ModelMap;
@Controller
public class StudentController {
   @RequestMapping(value = "/student", method = RequestMethod.GET)
   public ModelAndView student() {
      return new ModelAndView("student", "command", new Student());
   }   
   @RequestMapping(value = "/addStudent", method = RequestMethod.POST)
   public String addStudent(@ModelAttribute("SpringWeb")Student student, 
   ModelMap model) {
      model.addAttribute("name", student.getName());
      model.addAttribute("age", student.getAge());
      model.addAttribute("id", student.getId());      
      return "result";
   }
}

在這裏,第一個 service 方法 student(),我們已經在名稱爲 “command” 的 ModelAndView 對象中傳遞一個空的 Student 對象,因爲 spring 框架需要一個名稱的 “command” 的對象,如果你在 JSP 文件中使用 form:form 標籤。所以,當 student() 方法被調用時,它返回 student.jsp 視圖。

第二個 service 方法 addStudent() 將調用 HelloWeb/addStudent URL 中的 POST 方法。你將根據提交的信息準備好你的模型對象。最後一個 “result” 視圖會從 service 方法中返回,它將導致呈現 result.jsp。

下面是 Spring Web 配置文件 web.xml 的內容

<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <display-name>Spring MVC Form Handling</display-name>

    <servlet>
        <servlet-name>HelloWeb</servlet-name>
        <servlet-class>
           org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>HelloWeb</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

下面是另一個 Spring Web 配置文件 HelloWeb-servlet.xml 的內容

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   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
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:component-scan base-package="com.tutorialspoint" />

   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/WEB-INF/jsp/" />
      <property name="suffix" value=".jsp" />
   </bean>

</beans>

下面是 Spring 視圖文件 student.jsp 的內容

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
    <title>Spring MVC Form Handling</title>
</head>
<body>

<h2>Student Information</h2>
<form:form method="POST" action="/HelloWeb/addStudent">
   <table>
    <tr>
        <td><form:label path="name">Name</form:label></td>
        <td><form:input path="name" /></td>
    </tr>
    <tr>
        <td><form:label path="age">Age</form:label></td>
        <td><form:input path="age" /></td>
    </tr>
    <tr>
        <td><form:label path="id">id</form:label></td>
        <td><form:input path="id" /></td>
    </tr>
    <tr>
        <td colspan="2">
            <input type="submit" value="Submit"/>
        </td>
    </tr>
</table>  
</form:form>
</body>
</html>

下面是 Spring 視圖文件 result.jsp 的內容

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
    <title>Spring MVC Form Handling</title>
</head>
<body>

<h2>Submitted Student Information</h2>
   <table>
    <tr>
        <td>Name</td>
        <td>${name}</td>
    </tr>
    <tr>
        <td>Age</td>
        <td>${age}</td>
    </tr>
    <tr>
        <td>ID</td>
        <td>${id}</td>
    </tr>
</table>  
</body>
</html>

最後,下面是包含在你的 web 應用程序中的 Spring 和其他庫的列表。你僅僅需要將這些文件拖拽到 WebContent/WEB-INF/lib 文件夾中。

  • commons-logging-x.y.z.jar

  • org.springframework.asm-x.y.z.jar

  • org.springframework.beans-x.y.z.jar

  • org.springframework.context-x.y.z.jar

  • org.springframework.core-x.y.z.jar

  • org.springframework.expression-x.y.z.jar

  • org.springframework.web.servlet-x.y.z.jar

  • org.springframework.web-x.y.z.jar

  • spring-web.jar

一旦你完成了創建源代碼和配置文件後,導出你的應用程序。右鍵單擊你的應用程序,並且使用 Export > WAR File 選項,並且在 Tomcat 的 webapps 文件夾中保存你的 HelloWeb.war 文件。

現在啓動你的 Tomcat 服務器,並且確保你能夠使用標準的瀏覽器訪問 webapps 文件夾中的其他 web 頁面。現在嘗試訪問該 URL http://localhost:8080/HelloWeb/student。如果你的 Spring Web 應用程序一切都正常,你應該看到下面的結果。


二十九、Spring 頁面重定向例子

下面的例子說明了如何編寫一個簡單的基於 web 的應用程序,它利用重定向來傳送一個 http 請求到另一個頁面中。爲了開始使用它,讓我們在恰當的位置使用 Eclipse IDE,然後按照下面的步驟使用 Spring 的 Web 框架來開發一個動態的基於表單的 Web 應用程序:

步驟 描述
1 創建一個名稱爲 HelloWeb動態 Web 項目,並且在已創建的項目的 src 文件夾中創建一個包 com.tutorialspoint
2 將上面提到的 Spring 和其他庫拖拽到文件夾 WebContent/WEB-INF/lib 中。
3 com.tutorialspoint 包下創建一個 Java 類 WebController
4 WebContent/WEB-INF 文件夾下創建 Spring 的配置文件 Web.xmlHelloWeb-servlet.xml
5 WebContent/WEB-INF 文件夾下創建名稱爲 jsp 的子文件夾。在這個子文件夾下創建視圖文件 index.jspfinal.jsp
6 最後一步是創建所有的源代碼和配置文件的內容,並導出該應用程序,正如下面解釋的一樣。

這裏是 WebController.java 文件的內容:

package com.tutorialspoint;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class WebController {
   @RequestMapping(value = "/index", method = RequestMethod.GET)
   public String index() {
       return "index";
   }   
   @RequestMapping(value = "/redirect", method = RequestMethod.GET)
   public String redirect() {     
      return "redirect:finalPage";
   }   
   @RequestMapping(value = "/finalPage", method = RequestMethod.GET)
   public String finalPage() {     
      return "final";
   }
}

下面是 Spring Web 配置文件 web.xml 的內容

<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <display-name>Spring Page Redirection</display-name>

    <servlet>
        <servlet-name>HelloWeb</servlet-name>
        <servlet-class>
           org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>HelloWeb</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

下面是另一個 Spring Web 配置文件 HelloWeb-servlet.xml 的內容

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   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
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.tutorialspoint" />

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
    </bean>
</beans>

下面是 Spring 視圖文件 index.jsp 文件的內容。這將是一個登陸頁面,這個頁面將發送一個請求來訪問重定向 service 方法,該方法將把這個請求重定向到另一個 service 方法中,最後將顯示 final.jsp 頁面。

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
    <title>Spring Page Redirection</title>
</head>
<body>
<h2>Spring Page Redirection</h2>
<p>Click below button to redirect the result to new page</p>
<form:form method="GET" action="/HelloWeb/redirect">
<table>
    <tr>
    <td>
    <input type="submit" value="Redirect Page"/>
    </td>
    </tr>
</table>  
</form:form>
</body>
</html>

下面是 Spring 視圖文件 final.jsp 的內容。這是最終的重定向頁面。

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
    <title>Spring Page Redirection</title>
</head>
<body>

<h2>Redirected Page</h2>

</body>
</html>

最後,下面是包含在你的 web 應用程序中的 Spring 和其他庫的列表。你僅僅需要將這些文件拖拽到 WebContent/WEB-INF/lib 文件夾中。

  • commons-logging-x.y.z.jar

  • org.springframework.asm-x.y.z.jar

  • org.springframework.beans-x.y.z.jar

  • org.springframework.context-x.y.z.jar

  • org.springframework.core-x.y.z.jar

  • org.springframework.expression-x.y.z.jar

  • org.springframework.web.servlet-x.y.z.jar

  • org.springframework.web-x.y.z.jar

  • spring-web.jar

一旦你完成了創建源代碼和配置文件後,導出你的應用程序。右鍵單擊你的應用程序,並且使用 Export > WAR File 選項,並且在 Tomcat 的 webapps 文件夾中保存你的 HelloWeb.war 文件。

現在啓動你的 Tomcat 服務器,並且確保你能夠使用標準的瀏覽器訪問 webapps 文件夾中的其他 web 頁面。現在嘗試訪問該 URL http://localhost:8080/HelloWeb/index。如果你的 Spring Web 應用程序一切都正常,你應該看到下面的結果


三十、Spring靜態頁面例子

 

下面的例子說明了如何使用 Spring MVC 框架來編寫一個簡單的基於 web 的應用程序,它可以在 mvc:resources 標籤的幫助下訪問靜態頁面和動態頁面。爲了開始使用它,讓我們在恰當的位置使用 Eclipse IDE,然後按照下面的步驟使用 Spring 的 Web 框架來開發一個動態的基於表單的 Web 應用程序:

步驟 描述
1 創建一個名稱爲 HelloWeb動態 Web 項目,並且在已創建的項目的 src 文件夾中創建一個包 com.tutorialspoint
2 將上面提到的 Spring 和其他庫拖拽到文件夾 WebContent/WEB-INF/lib 中。
3 com.tutorialspoint 包下創建一個 Java 類 WebController
4 WebContent/WEB-INF 文件夾下創建 Spring 的配置文件 Web.xmlHelloWeb-servlet.xml
5 WebContent/WEB-INF 文件夾下創建名稱爲 jsp 的子文件夾。在這個子文件夾下創建一個視圖文件 index.jsp
6 WebContent/WEB-INF 文件夾下創建名稱爲 pages 的子文件夾。在這個子文件夾下創建一個靜態文件 final.htm
7 最後一步是創建所有的源代碼和配置文件的內容,並導出該應用程序,正如下面解釋的一樣。

這裏是 WebController.java 文件的內容:

package com.tutorialspoint;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class WebController {
   @RequestMapping(value = "/index", method = RequestMethod.GET)
   public String index() {
       return "index";
   }   
   @RequestMapping(value = "/staticPage", method = RequestMethod.GET)
   public String redirect() {     
      return "redirect:/pages/final.htm";
   }
}

下面是 Spring Web 配置文件 web.xml 的內容

<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <display-name>Spring Page Redirection</display-name>

    <servlet>
        <servlet-name>HelloWeb</servlet-name>
        <servlet-class>
           org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>HelloWeb</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

下面是另一個 Spring Web 配置文件 HelloWeb-servlet.xml 的內容

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

    <context:component-scan base-package="com.tutorialspoint" />

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
    </bean>

    <mvc:resources mapping="/pages/**" location="/WEB-INF/pages/" />
    <mvc:annotation-driven/>

</beans>

在這裏,mvc:resources..../ 標籤被用來映射靜態頁面。 mapping 屬性必須是一個指定一個 http 請求的 URL 模式的 Ant 模式。 location 屬性必須指定一個或者多個具有包含圖片,樣式表,JavaScript 和其他靜態內容的靜態頁面的資源目錄位置。多個資源位置可以使用逗號分隔這些值的列表來被指定。

下面是 Spring 視圖文件 WEB-INF/jsp/index.jsp 的內容。這將是一個登陸頁面,這個頁面將發送一個請求來訪問 staticPage 的 service 方法,它將重定向這個請求到 WEB-INF/pages 文件夾中的一個可用的靜態頁面。

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
    <title>Spring Landing Page</title>
</head>
<body>
<h2>Spring Landing Pag</h2>
<p>Click below button to get a simple HTML page</p>
<form:form method="GET" action="/HelloWeb/staticPage">
<table>
    <tr>
    <td>
    <input type="submit" value="Get HTML Page"/>
    </td>
    </tr>
</table>  
</form:form>
</body>
</html>

下面是 Spring 視圖文件 WEB-INF/pages/final.htm 的內容。

<html>
<head>
    <title>Spring Static Page</title>
</head>
<body>

<h2>A simple HTML page</h2>

</body>
</html>

最後,下面是包含在你的 web 應用程序中的 Spring 和其他庫的列表。你僅僅需要將這些文件拖拽到 WebContent/WEB-INF/lib 文件夾中。

  • commons-logging-x.y.z.jar

  • org.springframework.asm-x.y.z.jar

  • org.springframework.beans-x.y.z.jar

  • org.springframework.context-x.y.z.jar

  • org.springframework.core-x.y.z.jar

  • org.springframework.expression-x.y.z.jar

  • org.springframework.web.servlet-x.y.z.jar

  • org.springframework.web-x.y.z.jar

  • spring-web.jar

一旦你完成了創建源代碼和配置文件後,導出你的應用程序。右鍵單擊你的應用程序,並且使用 Export > WAR File 選項,並且在 Tomcat 的 webapps 文件夾中保存你的 HelloWeb.war 文件。

現在啓動你的 Tomcat 服務器,並且確保你能夠使用標準的瀏覽器訪問 webapps 文件夾中的其他 web 頁面。現在嘗試訪問該 URL http://localhost:8080/HelloWeb/index。 如果你的 Spring Web 應用程序一切都正常,你應該看到下面的結果


後記:

     站在巨人的肩膀上,希望有一天我也可以爲其添加高度。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章