1. 程式人生 > 實用技巧 >JavaEE學習之Spring框架

JavaEE學習之Spring框架

Spring學習

一、Spring 簡介

二、Spring 體系結構

三、Spring 環境配置

四、Spring IOC(控制反轉)

五、Spring DI(依賴注入)

六、Spring AOP(面向方面的程式設計)

七、Spring 基於註解的配置

八、Spring JDBC

九、Spring 事務管理

一、Spring 簡介

  1. 簡介

  • Spring 是最受歡迎的企業級 Java 應用程式開發框架,數以百萬的來自世界各地的開發人員使用 Spring 框架來建立效能好、易於測試、可重用的程式碼。

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

  • Spring 是輕量級的框架,其基礎版本只有 2 MB 左右的大小。

  • Spring 框架的核心特性是可以用於開發任何 Java 應用程式,但是在 Java EE 平臺上構建 web 應用程式是需要擴充套件的。 Spring 框架的目標是使 J2EE 開發變得更容易使用,通過啟用基於 POJO 程式設計模型來促進良好的程式設計實踐。

  

  1. 三層架構

  • A 表現層 web層 MVC是表現層的一個設計模型

  • B 業務層 service層

  • C 持久層 dao層

二、Spring 體系結構

Spring 是模組化的,Spring 框架提供約 20 個模組,可以根據應用程式的要求來使用,允許你挑選和選擇適用於你的模組,不必要把剩餘部分也引入。

  

核心容器

核心容器由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容器檢索物件,還支援列表的投影、選擇以及聚合等。

它們的完整依賴關係如下圖所示:

  

資料訪問/整合

資料訪問/整合層包括 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自動處理,程式設計式事務粒度更細)

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模組的功能。

其他

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

  • AOP 模組提供了面向方面的程式設計實現,允許你定義方法攔截器和切入點對程式碼進行乾淨地解耦,從而使實現功能的程式碼徹底的解耦出來。使用原始碼級的元資料,可以用類似於.Net屬性的方式合併行為資訊到程式碼中。

  • Aspects 模組提供了與 AspectJ 的整合,這是一個功能強大且成熟的面向切面程式設計(AOP)框架。

  • Instrumentation 模組在一定的應用伺服器中提供了類 instrumentation 的支援和類載入器的實現。

  • Messaging 模組為 STOMP 提供了支援作為在應用程式中 WebSocket 子協議的使用。它也支援一個註解程式設計模型,它是為了選路和處理來自 WebSocket 客戶端的 STOMP 資訊。

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

三、Spring 環境配置

  1. spring相關jar包

  1. spring 核心配置檔案(applicationContext.xml)

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
    "http://www.springframework.org/dtd/spring-beans-2.0.dtd">

    <beans>

    <!--告訴spring幫我們建立物件-->
    <bean name="user" class="cn.edu.dgut.pojo.User"></bean>

    </beans>

  2. 測試類(SpringDemo01)

    public class SpringDemo01 {

    @Test
    public void fun1() {
    // 使用框架 API ClassPathXmlApplicationContext() 來建立應用程式的上下文
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 使用已建立的上下文的 getBean() 方法來獲得所需的 bean
    Object object = applicationContext.getBean("user");
    System.out.println(object);
    }

    @Test
    public void fun2() {
    // 利用框架提供的 XmlBeanFactory() API 去生成工廠 bean 以及利用 ClassPathResource() API 去載入在路徑 CLASSPATH 下可用的 bean 配置檔案
    BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext02.xml"));
    // 利用第一步生成的 bean 工廠物件的 getBean() 方法得到所需要的 bean
    User user = beanFactory.getBean(User.class);
    System.out.println(user);
    }

    @Test
    public void fun3() {
    // 使用框架 API ClassPathXmlApplicationContext() 來建立應用程式的上下文
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext02.xml");
    // 使用已建立的上下文的 getBean() 方法來獲得所需的 bean
    Object user = applicationContext.getBean(User.class);
    System.out.println(user);
    }

    }

四、Spring IOC(控制反轉)

  • Spring 容器是 Spring 框架的核心。容器將建立物件,把它們連線在一起,配置它們,並管理他們的整個生命週期從建立到銷燬。Spring 容器使用依賴注入(DI)來管理組成一個應用程式的元件。這些物件被稱為 Spring Beans。

  • IOC 容器具有依賴注入功能的容器,它可以建立物件,IOC 容器負責例項化、定位、配置應用程式中的物件及建立這些物件間的依賴。通常new一個例項,控制權由程式設計師控制,而"控制反轉"是指new例項工作不由程式設計師來做而是交給Spring容器來做。在Spring中BeanFactory是IOC容器的實際代表者。

  1. Spring 的 BeanFactory 容器

    這是一個最簡單的容器,它主要的功能是為依賴注入 (DI) 提供支援,這個容器介面在 org.springframework.beans.factory.BeanFactor 中被定義。BeanFactory 和相關的介面,比如BeanFactoryAware、DisposableBean、InitializingBean,仍舊保留在 Spring 中,主要目的是向後相容已經存在的和那些 Spring 整合在一起的第三方框架。

  1. Spring ApplicationContext 容器

    Application Context 是 BeanFactory 的子介面,也被成為 Spring 上下文。

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

    ApplicationContext 包含 BeanFactory 所有的功能,一般情況下,相對於 BeanFactory,ApplicationContext 會更加優秀。當然,BeanFactory 仍可以在輕量級應用中使用,比如移動裝置或者基於 applet 的應用程式。

  1. Bean

    被稱作 bean 的物件是構成應用程式的支柱也是由 Spring IoC 容器管理的。bean 是一個被例項化,組裝,並通過 Spring IoC 容器所管理的物件。

  • Bean 的作用域

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

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

五、Spring DI(依賴注入)

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

  • 依賴注入(常用的為建構函式和set方法注入)

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

  1. Spring 基於建構函式的依賴注入

    當容器呼叫帶有一組引數的類建構函式時,基於建構函式的 DI 就完成了,其中每個引數代表一個對其他類的依賴。

  2. Spring 基於設值函式的依賴注入

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

  3. P名稱空間注入

    P名稱空間注入走的也是set方法, 官方目的是簡化set注入的property標籤的寫法。

  4. Spel注入

    Spring Expression Language(簡稱 SpEL)是一種功能強大的表示式語言、用於在執行時查詢和操作物件圖;語法上類似於 Unified EL,但提供了更多的特性,特別是方法呼叫和基本字串模板函式。SpEL 的誕生是為了給 Spring 社群提供一種能夠與 Spring 生態系統所有產品無縫對接,能提供一站式支援的表示式語言。

  5. 注入集合

    你已經看到了如何使用 value 屬性來配置基本資料型別和在你的 bean 配置檔案中使用<property>標籤的 ref 屬性來配置物件引用。

<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--set方法注入-->
<bean name="user" class="cn.edu.dgut.pojo.User">
<property name="id" value="1"></property>
<property name="username" value="房子"></property>
<property name="myPojo" ref="mypojo"></property>

<!--注入陣列-->
<property name="arr">
<array>
<value>張三</value>
<value>李四</value>
<value>王五</value>
</array>
</property>

<!--注入list集合-->
<property name="list">
<list>
<value>張三</value>
<value>李四</value>
<value>王五</value>
<ref bean="mypojo"></ref>
</list>
</property>

<!--注入map集合-->
<property name="map">
<map>
<entry key="name" value="張三"></entry>
<entry key="username" value="李四"></entry>
<entry key="uname" value="王五"></entry>
<entry key="mypojo" value-ref="mypojo"></entry>
</map>
</property>
</bean>

<!--set方法注入-->
<bean name="mypojo" class="cn.edu.dgut.pojo.MyPojo">
<property name="id" value="1"></property>
<property name="name" value="花花"></property>
<property name="status" value="嘩嘩譁"></property>
</bean>

<!--構造方法注入-->
<!--<bean name="user" class="cn.edu.dgut.pojo.User">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="username" value="sss"></constructor-arg>
<constructor-arg name="myPojo" ref="mypojo"></constructor-arg>
</bean>-->

<!--P名稱空間注入-->
<!--<bean name="user" class="cn.edu.dgut.pojo.User" p:id="1" p:username="aa" p:myPojo-ref="mypojo">
</bean>-->

<!--Spel注入-->
<!--<bean name="user" class="cn.edu.dgut.pojo.User">
<property name="id" value="1"></property>
<property name="username" value="#{'fff'}"></property>
<property name="myPojo" ref="mypojo"></property>
</bean>-->

</beans>

六、Spring AOP(面向方面的程式設計)

  • Spring 框架的一個關鍵元件是面向方面的程式設計(AOP)框架。面向方面的程式設計需要把程式邏輯分解成不同的部分稱為所謂的關注點。跨一個應用程式的多個點的功能被稱為橫切關注點,這些橫切關注點在概念上獨立於應用程式的業務邏輯。有各種各樣的常見的很好的方面的例子,如日誌記錄、審計、宣告式事務、安全性和快取等。

  • 在 OOP 中,關鍵單元模組度是類,而在 AOP 中單元模組度是方面。依賴注入幫助你對應用程式物件相互解耦和 AOP 可以幫助你從它們所影響的物件中對橫切關注點解耦。AOP 是像程式語言的觸發物,如 Perl,.NET,Java 或者其他。

  • Spring AOP 模組提供攔截器來攔截一個應用程式,例如,當執行一個方法時,你可以在方法執行之前或之後新增額外的功能。

AOP 術語

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

通知的型別

Spring 方面可以使用下面提到的五種通知工作:

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

Spring 中基於 AOP 的 XML配置(applicationContext.xml)

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

<!--配置IOC 建立 目標類-->
<bean name="userService" class="cn.edu.dgut.target.UserService"></bean>
<!--配置IOC 建立 增強通知 -->
<bean name="myAdvice" class="cn.edu.dgut.advice.MyAdvice"></bean>

<!--配置AOP 織入過程-->
<aop:config>
<!--配置切點
切入點表示式 寫延伸寫法:
1. public void com.shop.target.UserService.addUser()
2. void com.shop.target.UserService.addUser() // 修飾符省略
3. * com.shop.target.UserService.addUser() // 任意返回值
4. * com.shop.target.UserService.*User() // 返回名字首任意
5. * com.shop.target.UserService.*User(..) // 方法中引數 個數 任意 (0~n個)
6. * com.shop.target.*Service.*User(..) // service 目標類的 類名字首任意
UserService
OrderService
....
7. * com.shop.target..*Service.*User(..) // 掃描 父包以及子包下的 類

-->

<!--配置增強(通知)
after 後置通知 (最終通知)

1. 肯定在目標方法之後執行

2.不管程式碼之間發生任何異常,該通知仍然會執行

after-returning 後置通知

1. 肯定在目標方法之後執行

2. 如果程式碼發生了異常 ,該通過將不會再去執行

-->
<aop:pointcut id="pc" expression="execution(public void cn.edu.dgut.target.UserService.addUser())"/>
<aop:aspect ref="myAdvice">
<!--前置通知-->
<aop:before method="before" pointcut-ref="pc"></aop:before>
<!--異常攔截通知-->
<aop:after-throwing method="after_throwing" pointcut-ref="pc"></aop:after-throwing>
<!--後置通知 (目標方法正常執行後通知)-->
<aop:after-returning method="after_returning" pointcut-ref="pc"></aop:after-returning>
<!--環繞通知配置-->
<!--<aop:around method="around" pointcut-ref="pc"></aop:around>-->
<!--後置通知 (最終通知)-->
<aop:after method="after" pointcut-ref="pc"></aop:after>
</aop:aspect>
</aop:config>

</beans>

七、Spring 基於註解的配置

從 Spring 2.5 開始就可以使用註解來配置依賴注入。而不是採用 XML 來描述一個 bean 連線,你可以使用相關類,方法或欄位宣告的註解,將 bean 配置移動到元件類本身。

  • IOC註解配置實現

  1. 實體類(User、MyPojo)

    @Component(value = "user")
    public class User {
    @Value("2")
    private int id;

    @Value(value = "李雲龍")
    private String username;

    // @Autowired
    // @Qualifier("mypojo")
    @Resource(name = "mypojo2")
    private MyPojo myPojo;

    public User() {
    }

    public User(int id, String username, MyPojo myPojo) {
    this.id = id;
    this.username = username;
    this.myPojo = myPojo;
    }

    public int getId() {
    return id;
    }

    public void setId(int id) {
    this.id = id;
    }

    public String getUsername() {
    return username;
    }

    public void setUsername(String username) {
    this.username = username;
    }

    public MyPojo getMyPojo() {
    return myPojo;
    }

    public void setMyPojo(MyPojo myPojo) {
    this.myPojo = myPojo;
    }

    @Override
    public String toString() {
    return "User{" +
    "id=" + id +
    ", username='" + username + '\'' +
    ", myPojo=" + myPojo +
    '}';
    }
    }
    @Component("mypojo")
    public class MyPojo {
    @Value("3")
    private int id;
    @Value("趙剛")
    private String name;
    @Value("政委")
    private String status;

    public int getId() {
    return id;
    }

    public void setId(int id) {
    this.id = id;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String getStatus() {
    return status;
    }

    public void setStatus(String status) {
    this.status = status;
    }

    @Override
    public String toString() {
    return "MyPojo{" +
    "id=" + id +
    ", name='" + name + '\'' +
    ", status='" + status + '\'' +
    '}';
    }
    }
  2. 配置檔案

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

    <bean name="mypojo2" class="cn.edu.dgut.pojo.MyPojo">
    <property name="id" value="3"></property>
    <property name="name" value="孔捷"></property>
    <property name="status" value="團長"></property>
    </bean>

    <!--開啟掃描-->
    <context:component-scan base-package="cn.edu.dgut.pojo"></context:component-scan>

    </beans>
  3. 測試類

    public class SpringDemo01 {

    @Test
    public void fun1() {
    // 使用框架 API ClassPathXmlApplicationContext() 來建立應用程式的上下文
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 使用已建立的上下文的 getBean() 方法來獲得所需的 bean
    Object object = applicationContext.getBean("user");
    System.out.println(object);
    }

    }

  • AOP註解配置實現

  1. 目標類(UserService)

    @Component
    public class UserService {
    public void addUser() {
    //int i = 1 / 0;
    System.out.println("新增使用者");
    }

    public void update() {
    System.out.println("修改使用者");
    }
    }
  2. 增強(通知類MyAdvice)

    @Component
    @Aspect
    public class MyAdvice {
    @Pointcut("execution(* cn.edu.dgut.target.*Service.*User(..))")
    public void selectAll() {
    }

    //@Before(value = "execution(void cn.edu.dgut.target.UserService.addUser())")
    @Before("selectAll()")
    public void before() {
    System.out.println("開啟事務");
    }

    //@AfterThrowing(value = "execution(void cn.edu.dgut.target.UserService.addUser())")
    @AfterThrowing("selectAll()")
    public void after_throwing() {
    System.out.println("出現異常,程式中斷");
    }

    //@AfterReturning(value = "execution(void cn.edu.dgut.target.UserService.addUser())")
    @AfterReturning("selectAll()")
    public void after_returning() {
    System.out.println("目標方法正常執行");
    }

    //@Around(value = "execution(void cn.edu.dgut.target.UserService.addUser())")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("開啟事務");
    //System.out.println("環繞通知");
    Object proceed = pjp.proceed();
    System.out.println("提交事務");
    return proceed;
    }

    //@After(value = "execution(void cn.edu.dgut.target.UserService.addUser())")
    @After("selectAll()")
    public void after() {
    System.out.println("提交事務");
    }

    }
  3. 測試類

    public class SpringDemo01 {

    @Test
    public void fun1() {
    // 使用框架 API ClassPathXmlApplicationContext() 來建立應用程式的上下文
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 使用已建立的上下文的 getBean() 方法來獲得所需的 bean
    UserService userService = (UserService) applicationContext.getBean("userService");
    userService.addUser();
    }

    }
  4. 配置檔案(applicationContext.xml)

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

    <!--開啟IOC 掃描-->
    <context:component-scan base-package="cn.edu.dgut"></context:component-scan>

    <!--開啟AOP 掃描-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    </beans>

八、Spring JDBC

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

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

JdbcTemplate 類

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

  • JdbcTemplate 類的例項是執行緒安全配置的。所以你可以配置 JdbcTemplate 的單個例項,然後將這個共享的引用安全地注入到多個 DAOs 中。

  • 使用 JdbcTemplate 類時常見的做法是在你的 Spring 配置檔案中配置資料來源,然後共享資料來源 bean 依賴注入到 DAO 類中,並在資料來源的設值函式中建立了 JdbcTemplate。

環境搭建(除了前面新增的核心jar包和第三方包,還需加入以下jar包)

  

配置資料來源

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

建立jdbcTemplate

<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>

資料訪問物件(DAO)

  • DAO 代表常用的資料庫互動的資料訪問物件。DAOs 提供一種方法來讀取資料並將資料寫入到資料庫中,它們應該通過一個介面顯示此功能,應用程式的其餘部分將訪問它們。

    <bean name="userDao" class="cn.edu.dgut.dao.impl.UserDaoImpl">
    <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

執行 SQL 語句

  • 使用 SQL 和 jdbcTemplate 物件在資料庫表中執行 CRUD(建立、讀取、更新和刪除)操作。

  1. 查詢一個整數型別

String SQL = "select count(*) from Student";
int rowCount = jdbcTemplateObject.queryForInt( SQL );
  1. 查詢一個 long 型別

String SQL = "select count(*) from Student";
long rowCount = jdbcTemplateObject.queryForLong( SQL );
  1. 一個使用繫結變數的簡單查詢

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

String SQL = "select name from Student where id = ?";
String name = jdbcTemplateObject.queryForObject(SQL, new Object[]{10}, String.class);
  1. 查詢並返回一個物件

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;
}
}
  1. 查詢並返回多個物件

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;
}
}
  1. 在表中插入一行

String SQL = "insert into Student (name, age) values (?, ?)";
jdbcTemplateObject.update( SQL, new Object[]{"Zara", 11} );
  1. 更新表中的一行

String SQL = "update Student set name = ? where id = ?";
jdbcTemplateObject.update( SQL, new Object[]{"Zara", 10} );
  1. 從表中刪除一行

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

九、Spring 事務管理

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

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

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

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

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

  1. 一個真正的 RDBMS 資料庫系統將為每個事務保證所有的四個屬性。使用 SQL 釋出到資料庫中的事務的簡單檢視如下:

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

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

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

  1. Spring 支援兩種型別的事務管理:

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

  • 宣告式事務管理 :這意味著你從業務程式碼中分離事務管理。你僅僅使用註釋或 XML 配置來管理事務。

    宣告式事務管理比程式設計式事務管理更可取,儘管它不如程式設計式事務管理靈活,但它允許你通過程式碼控制事務。但作為一種橫切關注點,宣告式事務管理可以使用 AOP 方法進行模組化。Spring 支援使用 Spring AOP 框架的宣告式事務管理。

  1. Spring 事務抽象

Spring事務管理的五大屬性:隔離級別傳播行為是否只讀事務超時回滾規則

  • 隔離級別的可能值

    序號隔離 & 描述
    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使用預設超時的底層事務系統,或者如果不支援超時則沒有。

  1. 配置事務核心管理者

<bean name="dataSourceTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>

  1. 配置事務通知

<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<tx:method name="transferAccount" isolation="READ_UNCOMMITTED" propagation="REQUIRED" read-only="false"/>
</tx:attributes>
</tx:advice>

  1. 配置AOP 織入

<aop:config>
<!--配置切點表示式-->
<aop:pointcut id="pc"
expression="execution(* cn.edu.dgut.service.impl.AccountServiceImpl.transferAccount(..))"/>
<!-- 配置切面 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"></aop:advisor>
</aop:config>

  1. 註解實現事務

  • 開啟事務掃描

    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation>
  • service

    public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
    this.accountDao = accountDao;
    }

    // 轉賬
    @Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.REQUIRED, readOnly = false)
    @Override
    public void transferAccount(double money, int from_id, int to_id) {
    // 轉賬方減錢
    accountDao.reduceMoney(money, from_id);

    //int i = 1 / 0;

    // 收款方加錢
    accountDao.addMoney(money, to_id);
    }
    }

本文是學習spring的個人總結,僅供參考,歡迎大家批評指正。

參考連結:https://www.w3cschool.cn/wkspring/