1. 程式人生 > >02 整合IDEA+Maven+SSM框架的高並發的商品秒殺項目之Service層

02 整合IDEA+Maven+SSM框架的高並發的商品秒殺項目之Service層

狀態 enum枚舉類 post note 序號 設計 發的 連接數據庫 解釋

作者:nnngu
項目源代碼:https://github.com/nnngu/nguSeckill


首先在編寫Service層代碼前,我們應該首先要知道這一層到底是幹什麽的。

Service層主要負責業務模塊的邏輯應用設計。同樣是首先設計接口,再設計其實現的類,接著在Spring的配置文件中配置其實現的關聯。這樣我們就可以在應用中調用Service接口來進行業務處理。Service層的業務實現,具體要調用到已定義的dao層的接口,封裝Service層的業務邏輯有利於通用的業務邏輯的獨立性和重復利用性,程序顯得非常簡潔。

在項目中要降低耦合的話,分層是一種很好的概念,就是各層各司其職,盡量不做不相幹的事,所以Service

層的話顧名思義就是業務邏輯,處理程序中的一些業務邏輯,以及調用dao層的代碼,這裏我們的dao層就是連接數據庫的那一層,調用關系可以這樣表達:

View(頁面) > Controller(控制層) > Service(業務邏輯) > Dao(數據訪問) > Database(數據庫)

首先還是接口的設計,設計秒殺商品的接口,在com.nnngu.service.interfaces包下建立SeckillService.java接口文件,如下圖:

技術分享圖片

SeckillService.java文件裏面的內容請參照項目的源代碼。

建立好接口之後我們要寫實現類了,在寫實現類的時候我們肯定會碰到一個這樣的問題,你要向前端返回json數據的話,你是返回什麽樣的數據好?直接返回一個數字狀態碼或者文字?這樣設計肯定是不好的,所以我們應該向前端返回一個實體信息json,裏面包含了一系列的信息,無論是哪種狀態都應該可以應對,既然是與數據庫字段無關的類,那就不是PO了,所以我們建立一個DTO數據傳輸類。關於常見的幾種對象我的解釋如下:

  • PO:也就是我們為每一張數據庫表寫一個實體類

  • VO:對某個頁面或者展現層所需要的數據,封裝成一個實體類

  • BO:業務對象

  • DTO:跟VO的概念有點混淆,也是相當於頁面需要的數據封裝成一個實體類

  • POJO:簡單的無規則java對象

在com.nnngu下建立dto包,然後建立Exposer類,這個類是秒殺時數據庫那邊處理的結果的對象

Exposer.java文件裏面的內容請參照項目的源代碼。

定義秒殺中可能會出現的異常

定義一個基礎的異常,所有的子異常繼承這個異常SeckillException

package com.nnngu.exception;

/**
 *  秒殺基礎的異常
 * Created by nnngu
*/ public class SeckillException extends RuntimeException { // 代碼省略,請參照項目的源代碼 ... ... }

可能會出現秒殺關閉後被秒殺情況,所以建立秒殺關閉異常SeckillCloseException,需要繼承我們前面寫的基礎異常

package com.nnngu.exception;

/**
 * 秒殺已經關閉異常,當秒殺結束就會出現這個異常
 * Created by nnngu
 */
public class SeckillCloseException extends SeckillException{
    // 代碼省略,請參照項目的源代碼
    ... ...
}

定義重復秒殺異常RepeatKillException

package com.nnngu.exception;

/**
 * 重復秒殺異常,不需要我們手動去try catch
 * Created by nnngu
 */
public class RepeatKillException extends SeckillException{
    // 代碼省略,請參照項目的源代碼
    ... ...
}

實現Service接口

com.nnngu.service包下創建SeckillServiceImpl.java類,具體代碼請參照項目的源代碼。

在這裏我們捕獲了運行時異常,這樣做的原因就是Spring的事務默認發生了RuntimeException才會回滾,可以檢測出來的異常是不會導致事務的回滾的,這樣的目的就是你明知道這裏會發生異常,所以你一定要進行處理。如果只是為了讓編譯通過的話,那捕獲異常也沒意思,所以這裏要註意事務的回滾。

然後我們還發現這裏存在硬編碼的現象,就是返回各種字符常量,例如秒殺成功,秒殺失敗等等,這些字符串是可以被重復使用的,而且這樣維護起來也不方便,要到處去類裏面尋找這樣的字符串,所有我們使用枚舉類來管理這樣狀態,在con.nnngu包下建立enums包,專門放置枚舉類,然後再建立SeckillStatEnum枚舉類。

枚舉類SeckillStatEnum.java的代碼請參照項目的源代碼。

註入Service

resources/spring下建立applicationContext-service.xml文件,用來配置Service

applicationContext-service.xml的代碼請參照項目的源代碼。

在這裏開啟了基於註解的事務,常見的事務操作有以下幾種方法:

  • 在Spring早期版本中是使用ProxyFactoryBean+XMl方式來配置事務。

  • 在Spring配置文件使用tx:advice+aop命名空間,好處就是一次配置永久生效,你無須去關心中間出的問題,不過出錯了你很難找出在哪裏出了問題。

  • 註解@Transactional的方式,註解可以在方法定義,接口定義,類定義。可以在public方法上,但是不能註解在private、final、static等方法上,因為Spring的事務管理默認是使用cglib動態代理的:
  • private方法因為訪問權限限制,無法被子類覆蓋
  • final方法無法被子類覆蓋
  • static時類級別的方法,無法被子類覆蓋
  • protected方法可以被子類覆蓋,因此可以被動態字節碼增強

不能被Spring AOP事務增強的方法

序號 動態代理策略 不能被事務增強的方法
1 基於JDK的動態代理 除了public以外的所有方法,並且 public static 的方法也不能被增強
2 基於cglib的動態代理 privatestaticfinal 的方法

Service層的測試

添加測試類SeckillServiceImplTest.java,如下圖:

技術分享圖片

SeckillServiceImplTest.java的代碼請參照項目的源代碼。

測試結果:

測試的方法:public void getSeckillList()

測試結果如下圖:

技術分享圖片

到此,我們成功完成了Service層開發及測試。

下一篇:03 Java高並發秒殺項目之web層

02 整合IDEA+Maven+SSM框架的高並發的商品秒殺項目之Service層