從零學習Spring

一、Spring簡介

Spring是一個開源框架,它由Rod Johnson建立。它是爲了解決企業應用開發的複雜性而建立的。Spring使用基本的JavaBean來完成之前只可能由EJB完成的事情。然而,Spring的用途不只限於服務器端的開發。從簡單性、可測試性和鬆耦合的角度而言,任何Java應用均可以從Spring中受益。 Spring是一個輕量級的控制反轉(IoC)和麪向切面(AOP)的容器框架。前端

二、Spring體系結構

Spring 有可能成爲全部企業應用程序的一站式服務點,然而,Spring 是模塊化的,容許你挑選和選擇適用於你的模塊,沒必要要把剩餘部分也引入。下面的部分對在 Spring 框架中全部可用的模塊給出了詳細的介紹。java

Spring 框架提供約 20 個模塊,能夠根據應用程序的要求來使用。程序員

其中有七大主要的模塊web

2.一、核心容器

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

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

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

  • context模塊創建在由core和 beans 模塊的基礎上創建起來的,它以一種相似於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,DAO,ORM,OXM,JMS 和事務處理模塊,它們的細節以下:

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

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

  • DAO 模塊提供了對JDBC、Hibernate、Mybatis等DAO層支持。

  • 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自動處理,編程式事務粒度更細)

2.三、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模塊的功能。

2.四、其餘

還有其餘一些重要的模塊,像 AOP,Aspects,Instrumentation,Web 和測試模塊,它們的細節以下:

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

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

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

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

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

三、Spring體系詳解

3.一、Spring IoC 容器

Spring 容器是 Spring 框架的核心。容器將建立對象,把它們鏈接在一塊兒,配置它們,並管理他們的整個生命週期從建立到銷燬。Spring 容器使用依賴注入(DI)來管理組成一個應用程序的組件。 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 的應用程序,其中它的數據量和速度是顯著。

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

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

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

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

3.1.一、Spring Bean定義的三種方式

Spring容器啓動配置(web.xml文件)

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
複製代碼

1、基於XML的配置

適用場景:

  • Bean實現類來自第三方類庫,如:DataSource等
  • 須要命名空間配置,如:context,aop,mvc等
<beans>
    <import resource=「resource1.xml」 />//導入其餘配置文件Bean的定義
    <import resource=「resource2.xml」 />
    
    <bean id="userService" class="cn.lovepi.***.UserService" init-method="init" destory-method="destory"> 
    </bean>
    <bean id="message" class="java.lang.String">
        <constructor-arg index="0" value="test"></constructor-arg>
    </bean>
</beans>
複製代碼

2、基於註解的配置

適用場景:

  • 項目中本身開發使用的類,如controller、service、dao等

一、在applicationContext.xml配置掃描包路徑

<context:component-scan base-package="com.lovepi.spring"> 
    <context:include-filter type="regex" expression="com.lovepi.spring.*"/> //包含的目標類
    <context:exclude-filter type="aspectj" expression="cn.lovepi..*Controller+"/>   //排除的目標類
</context:component-scan>
複製代碼
  1. 使用註解聲明bean

Spring提供了四個註解,這些註解的做用與上面的XML定義bean效果一致,在於將組件交給Spring容器管理。組件的名稱默認是類名(首字母變小寫),能夠本身修改:

  • @Component:當對組件的層次難以定位的時候使用這個註解
  • @Controller:表示控制層的組件
  • @Service:表示業務邏輯層的組件
  • @Repository:表示數據訪問層的組件

3、基於Java類的配置

適用場景:

  • 須要經過代碼控制對象建立邏輯的場景
  • 實現零配置,消除xml配置文件

步驟以下:

  • 使用@Configuration註解須要做爲配置的類,表示該類將定義Bean的元數據
  • 使用@Bean註解相應的方法,該方法名默認就是Bean的名稱,該方法返回值就是Bean的對象。
  • AnnotationConfigApplicationContext或子類進行加載基於java類的配置

3.1.二、Spring Bean 做用域

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

Spring 框架支持如下五個做用域,分別爲singleton、prototype、request、session和global session,5種做用域說明以下所示

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

3.1.三、Spring Bean 生命週期

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

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

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

3.1.四、Spring 依賴注入

使用了Spring框架以後,對象的實例再也不由調用者來建立,而是由Spring容器來建立,Spring容器會負責控制程序之間的關係。這樣控制權便由應用代碼轉移到Spring容器,控制權發生了反轉,這就是Spring的控制反轉

從Spring容器來看,Spring容器負責將被依賴對象賦值給調用者的成員變量,這就至關於爲調用者注入了它依賴的實例,這就是Spring的依賴注入

1、setter 注入

這是最簡單的注入方式,假設有一個TestController,類中須要實例化一個TestService對象,那麼就能夠定義一個private的TestService成員變量,而後建立TestService的set方法(這是ioc的注入入口):

public class TestController {
    private TestService testService;

    //注入testService
    public void setTestService(TestService testService) {
        this.testService = testService;
    }

    public void test() {
        testService.test();
    }

}

複製代碼
public class TestService {
    public void test(){
        System.out.println("測試方法");
    }
}

複製代碼

spring的xml文件:

<bean id="testController111" class="com.test.day.TestController">
    <property name="testService" ref="testService"></property>
</bean>

<bean id="testService" class="com.test.day.TestService">

</bean>
複製代碼

2、構造器注入

這種方式的注入是指帶有參數的構造函數注入,看下面的例子,建立成員變量TestService,可是並未設置對象的set方法,因此就不能支持第一種注入方式,這裏的注入方式是在TestController的構造函數中注入,也就是說在建立TestController對象時要將TestService傳進來:

public class TestController {
    private TestService testService;

    public TestController(TestService testService){
        this.testService = testService;
    }

    public void test() {
        testService.test();
    }

}

複製代碼
public class TestService {
    public void test(){
        System.out.println("測試方法");
    }
}

複製代碼

spring的xml文件:

<bean id="testController" class="com.test.day.TestController">
    <constructor-arg  name="testService" index="0" ref="testService"></constructor-arg>
</bean>

<bean id="testService" class="com.test.day.TestService">
複製代碼

3、靜態工廠注入

靜態工廠顧名思義,就是經過調用靜態工廠的方法來獲取本身須要的對象,爲了讓spring管理全部對象,咱們不能直接經過"工程類.靜態方法()"來獲取對象,而是依然經過spring注入的形式獲取:

靜態工廠類:

public class StaticFactory {
    //靜態工廠
    public static final TestService getTestService(){
        return new TestService();
    }
}
複製代碼
public class TestController {
    private TestService testService;

    //注入testService
    public void setTestService(TestService testService) {
        this.testService = testService;
    }

    public void test() {
        testService.test();
    }

}
複製代碼
public class TestService {
    public void test(){
        System.out.println("測試方法");
    }
}

複製代碼

spring的xml文件:

<bean id="testController" class="com.test.day.TestController">
    <property name="testService" ref="testService"></property>
</bean>

<!--注意這裏注入的是靜態工廠類-->
<bean id="testService" class="com.test.day.StaticFactory" factory-method="getTestService">

</bean>
複製代碼

4、實例工廠注入

實例工廠的意思是獲取對象實例的方法不是靜態的,因此你須要首先new工廠類,再調用普通的實例方法:

實例工廠類:

public class ExamplesFactory {
    //實例工廠
    public TestService getTestService(){
        return new TestService();
    }
}

複製代碼
public class TestController {
    private TestService testService;

    //注入testService
    public void setTestService(TestService testService) {
        this.testService = testService;
    }

    public void test() {
        testService.test();
    }

}
複製代碼
public class TestService {
    public void test(){
        System.out.println("測試方法");
    }
}

複製代碼

spring的xml配置文件:

<bean id="testController" class="com.test.day.TestController">
    <property name="testService" ref="testService"></property>
</bean>

<bean id="testService" factory-bean="examplesFactory" factory-method="getTestService">

</bean>

<bean id="examplesFactory" class="com.test.day.ExamplesFactory">

</bean>
複製代碼

5、註解注入 目前使用最普遍的 @Autowired:自動裝配,基於@Autowired的自動裝配,默認是根據類型注入

public class TestController {
    @Autowired
    private TestService testService;

    public String test() {
        testService.test();
        return null;
    }

}

複製代碼
public class TestService {
    public void test(){
        System.out.println("測試方法");
    }
}

複製代碼

spring的xml配置文件:

<context:component-scan base-package="com.test.day">
        <context:include-filter type="regex" expression="com.test.day.*"/>
    </context:component-scan>
複製代碼

提供一個測試方法:

public class Test {
    @org.junit.Test
    public void test(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring/spring-context.xml");
        TestController controller = ac.getBean(TestController.class);
        controller.test();

    }
}
複製代碼

3.1.五、Spring Beans 自動裝配

學會如何使用元素來聲明 bean 和經過使用 XML 配置文件中的和元素來注入 。

Spring 容器能夠在不使用和 元素的狀況下自動裝配相互協做的 bean 之間的關係,這有助於減小編寫一個大的基於 Spring 的應用程序的 XML 配置的數量。

自動裝配模式

下列自動裝配模式,它們可用於指示 Spring 容器爲來使用自動裝配進行依賴注入。你可使用元素的 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 來自動裝配。

1、Spring 自動裝配 byName

這種模式由屬性名稱指定自動裝配。Spring 容器看做 beans,在 XML 配置文件中 beans 的 auto-wire 屬性設置爲 byName。而後,它嘗試將它的屬性與配置文件中定義爲相同名稱的 beans 進行匹配和鏈接。若是找到匹配項,它將注入這些 beans,不然,它將拋出異常。

直接修改以前的setter注入的代碼,只須要修改一下配置文件便可

<bean id="testController111" class="com.test.day.TestController" autowire="byName">
    <!--        <property name="testService" ref="testService"></property>-->
</bean>

<bean id="testService" class="com.test.day.TestService">

</bean>
複製代碼

2、Spring 自動裝配 byType

這種模式由屬性類型指定自動裝配。Spring 容器看做 beans,在 XML 配置文件中 beans 的 autowire 屬性設置爲 byType。而後,若是它的 type 剛好與配置文件中 beans 名稱中的一個相匹配,它將嘗試匹配和鏈接它的屬性。若是找到匹配項,它將注入這些 beans,不然,它將拋出異常。

和上面的例子沒有什麼區別,除了 XML 配置文件改爲「byType」。

<bean id="testController" class="com.test.day.TestController"  autowire="byType">
    <!--<property name="testService"  ref="testService"></property>-->
</bean>

<bean id="testService" class="com.test.day.TestService">

</bean>
複製代碼

3、Spring 構造函數自動裝配

這種模式與 byType 很是類似,但它應用於構造器參數。Spring 容器看做 beans,在 XML 配置文件中 beans 的 autowire 屬性設置爲 constructor。而後,它嘗試把它的構造函數的參數與配置文件中 beans 名稱中的一個進行匹配和連線。若是找到匹配項,它會注入這些 bean,不然,它會拋出異常。

修改一下Controller,使用構造器的方式

public class TestController {
    private TestService testService;

    public TestController(TestService testService){
        this.testService = testService;
    }

    public void test() {
        testService.test();
    }

}

複製代碼

配置文件

<bean id="testController" class="com.test.day.TestController"  autowire="constructor">
    <!--<property name="testService"  ref="testService"></property>-->
</bean>

<bean id="testService" class="com.test.day.TestService">

</bean>
複製代碼

3.二、Spring AOP

Spring 框架的一個關鍵組件是面向方面的編程(AOP)框架。面向方面的編程須要把程序邏輯分解成不一樣的部分稱爲所謂的關注點。跨一個應用程序的多個點的功能被稱爲橫切關注點,這些橫切關注點在概念上獨立於應用程序的業務邏輯。有各類各樣的常見的很好的方面的例子,如日誌記錄、審計、聲明式事務、安全性和緩存等。

AOP 術語

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

通知的類型

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

1、基於XML

2、基於註解

搞個簡單的例子

爲了測試異常,改一下service

public class TestService {
    public void test(){
        System.out.println("測試方法");
        int i = 1 / 0;
    }
}

複製代碼

添加一個切面類

@Aspect
@Component
public class LogAsp {
    private final static Logger logger = LoggerFactory.getLogger(LogAsp.class);

    // 聲明一個切入點
    @Pointcut("execution(public * com.test.day.TestService.*(..))")
    public void aspect() {
    }

    @Before("aspect()")
    public void beforeAdvice(){
        logger.info("前置通知。。。");
    }

    @After("aspect()")
    public void afterAdvice(){
        logger.info("後置通知。。。");
    }

    @AfterReturning(pointcut = "aspect()", returning="retVal")
    public void afterReturningAdvice(Object retVal){
        logger.info("返回後通知。。。" );
    }

    @AfterThrowing(pointcut = "aspect()", throwing = "ex")
    public void AfterThrowingAdvice(Exception ex){
        logger.info("拋出異常後通知...");
    }
    
    // @Around("aspect()")
    // public Object aroundAdvice(ProceedingJoinPoint pjp){
    //     Object obj = null;
    //     try {
    //         Object[] args = pjp.getArgs();// 獲得方法所需的參數
    //         logger.info("環繞通知:前置...");
    //         //明確調用業務層方法
    //         obj = pjp.proceed(args);
    //         logger.info("環繞通知:後置...");
    //         return obj;
    //     } catch (Throwable throwable) {
    //         logger.info("環繞通知:異常...");
    //         throw new RuntimeException(throwable);
    //     }finally {
    //         logger.info("環繞通知:最終...");
    //     }
    // }
}

複製代碼

修改一下spring配置文件

<context:component-scan base-package="com.test.day">
    <context:include-filter type="regex" expression="com.test.day.*"/>
</context:component-scan>

<!--經過配置織入@Aspectj切面-->
<aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
複製代碼

注意:aop:aspectj-autoproxy 正常是須要配置在 spring-mvc.xml 中的,我是爲了測試只有一個配置文件就放在一塊兒了。

啓動測試類,查看打印結果,麼得問題

3.三、Spring 事務管理

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

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

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

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

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

局部事物 vs. 全局事務

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

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

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

編程式 vs. 聲明式

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

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

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

3.四、Spring Web MVC 框架

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

  • 模型封裝了應用程序數據,而且一般它們由 POJO 組成。

  • 視圖主要用於呈現模型數據,而且一般它生成客戶端的瀏覽器能夠解釋的 HTML 輸出。

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

DispatcherServlet

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

  • 用戶發送請求至前端控制器DispatcherServlet
  • DispatcherServlet收到請求調用HandlerMapping處理器映射器。
  • 處理器映射器根據請求url找到具體的處理器,生成處理器對象及處理器攔截器(若是有則生成)一併返回給DispatcherServlet。
  • DispatcherServlet經過HandlerAdapter處理器適配器調用處理器
  • 執行處理器(Controller,也叫後端控制器)。
  • Controller執行完成返回ModelAndView
  • HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet
  • DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器
  • ViewReslover解析後返回具體View
  • DispatcherServlet對View進行渲染視圖(即將模型數據填充至視圖中)。
  • DispatcherServlet響應用戶

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

四、常見問題分析

4.一、BeanFactory和ApplicationContext有什麼區別?

  • 一、BeanFactory和ApplicationContext是Spring的兩大核心接口,均可以當作Spring的容器。其中ApplicationContext是BeanFactory的子接口,除了提供BeanFactory所具備的功能外,還提供了更完整的框架功能(國際化、訪問資源、載入多個(有繼承關係)上下文等)

  • 二、BeanFactroy採用的是延遲加載形式來注入Bean的,即只有在使用到某個Bean時(調用getBean()),纔對該Bean進行加載實例化。這樣,咱們就不能發現一些存在的Spring的配置問題。若是Bean的某一個屬性沒有注入,BeanFacotry加載後,直至第一次使用調用getBean方法纔會拋出異常。

  • 三、ApplicationContext,它是在容器啓動時,一次性建立了全部的Bean。這樣,在容器啓動時,咱們就能夠發現Spring中存在的配置錯誤,這樣有利於檢查所依賴屬性是否注入。 ApplicationContext啓動後預載入全部的單實例Bean,經過預載入單實例bean ,確保當你須要的時候,你就不用等待,由於它們已經建立好了。它還能夠爲Bean配置lazy-init=true來讓Bean延遲實例化。

  • 四、相對於基本的BeanFactory,ApplicationContext 惟一的不足是佔用內存空間。當應用程序配置Bean較多時,程序啓動較慢。

4.二、Spring BeanFactory 與 FactoryBean 的區別?

  • BeanFactory是一個factory,是spring的IOC的工場,而FactoryBean是個bean,它們兩個只是名字很類似。

  • BeanFactory是一個IOC工場,用於管理和建立Bean,它是IOC最基本的接口,爲其餘的IOC工場提供規範,不少其餘的spring容器都實現了它,如ApplicationContext、XMLBeanFactory等。它提供了經過bean的名字獲取實例、判斷bean是否在工場中、判斷是否爲單例等方法。

  • 對FactoryBean而言,這個Bean不是簡單的Bean,而是一個能生產或者修飾對象生成的工廠Bean,它的實現與設計模式中的工廠模式和修飾器模式相似

4.三、Spring如何處理線程併發問題?

  • 在Spring中,絕大部分Bean均可以聲明爲singleton做用域,由於Spring對一些Bean中非線程安全狀態採用ThreadLocal進行處理,解決線程安全問題。

  • ThreadLocal和線程同步機制都是爲了解決多線程中相同變量的訪問衝突問題。同步機制採用了「時間換空間」的方式,僅提供一份變量,不一樣的線程在訪問前須要獲取鎖,沒得到鎖的線程則須要排隊。而ThreadLocal採用了「空間換時間」的方式。

  • ThreadLocal會爲每個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問衝突。由於每個線程都擁有本身的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,能夠把不安全的變量封裝進ThreadLocal。

4.四、Spring 框架中都用到了哪些設計模式?

  • 工廠模式:BeanFactory就是簡單工廠模式的體現,用來建立對象的實例;

  • 單例模式:Bean默認爲單例模式。

  • 代理模式:Spring的AOP功能用到了JDK的動態代理和CGLIB字節碼生成技術;

  • 模板方法:用來解決代碼重複的問題。好比. RestTemplate, JmsTemplate, JpaTemplate。

  • 觀察者模式:定義對象鍵一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都會獲得通知被制動更新,如Spring中listener的實現--ApplicationListener。

4.五、Spring 同一個aspect,不一樣advice的執行順序?

沒有異常狀況下的執行順序:

  • around before advice(環繞通知:前置)
  • before advice(前置通知)
  • target method execution (方法執行)
  • around after advice(環繞通知:後置)
  • after advice(後置通知)
  • afterReturning(返回後通知)

有異常狀況下的執行順序:

  • around before advice(環繞通知:前置)
  • before advice(前置通知)
  • target method execution(方法執行)
  • after advice(後置通知)
  • afterThrowing(拋出異常後通知)
  • throw exception(拋出異常)

持續更新中。。。

相關文章
相關標籤/搜索