SSM整合-AOP介紹,以及登陸認證的使用

SSM整合-AOP介紹,以及登陸認證的使用

IOC 和 AOP是Spring的兩大核心概念。也是面試的一個高頻點
我看很多描述AOP都把其和動態代理結合在一起。讓人一臉矇蔽的進去,再一臉矇蔽的出來(AOP的是用動態代理實現,但不代表就不能用了。我用個電冰箱也不代表我得知道製冷原理啊)

這篇文章不講動態代理,僅描述AOP本身,以及如何使用。這篇文章比較淺,如果你想要更深入的知識,下面的可以不用看了

AOP面向切面編程,其主要功能就是將重複代碼提取出來,進行復用

其主要功能是:將重複代碼提取出來,進行復用

提取重複代碼,進行復用

網上找的圖,日誌切面,權限切面就是各個不同模塊(組件)裏面的重複代碼,我們僅寫一次,三個都可以用
AOP
那其實:如果我把這些重複代碼封裝到一個類裏面,再在各個模塊裏面調用這個類的對象進行復用,是否可以?
答:完全可以, 但是除了【將重複代碼提取出來,進行復用】,使用AOP還有一些其他好處,這種方式就是OOP了,就是我們一般說的面向對象編程

我們將AOP和 通過類(面向對象編程)來封裝代碼來實現分複用效果進行對比。來解釋AOP的一些概念
我的業務邏輯:查詢用戶賬戶信息的時候判斷用戶身份, 這裏【判斷用戶身份】是重複邏輯,
最下面的示例代碼分別是

  • 切面類 VerifyUserAop 就是用來封裝[判斷用戶身份]邏輯的類
  • service類UserAccountServiceImpl 實現查詢用戶賬戶
  • Controller類,調用UserAccountServiceImpl 的類,AOP裏面管這叫目標對象 target

用Java描述一遍:Controller調用service之前,先用VerifyUserAop 的方法判斷是有有權限調用。

  • Aspect(切面):Aspect 聲明類似於 Java 中的類聲明,在 Aspect 中會包含着一些 Pointcut 以及相應的 Advice。 就是我的那VerifyUserAop ,用來封裝重複代碼的類
  • Joint point(連接點):表示在程序中明確定義的點,典型的包括方法調用,對類成員的訪問以及異常處理程序塊的執行等等,它自身還可以嵌套其它 joint point。 這個東西我的例子裏面沒用到,也不知道怎麼描述
  • Pointcut(切點):表示一組 joint point,這些 joint point 或是通過邏輯關係組合起來,或是通過通配、正則表達式等方式集中起來,它定義了相應的 Advice 將要發生的地方。 就是VerifyUserAop 對象插入的地方
  • Advice(增強):Advice 定義了在 Pointcut 裏面定義的程序點具體要做的操作,它通過 before、after 和 around 來區別是在每個 joint point 之前、之後還是代替執行的代碼。 就是VerifyUserAop裏面的verifyLoginByCookie方法
  • Target(目標對象):織入 Advice 的目標對象.。 就是我要做身份驗證的地方UserAccountController類
  • Weaving(織入):將 Aspect 和其他對象連接起來, 並創建 Adviced object 的過程 我把VerifyUserAop.verifyLoginByCookie 放到controller的過程

這樣是不是好理解多了

我這裏使用AOP實現的,實現的邏輯是每次調用UserAccountServiceImpl.listUserAccount方法之前,先執行我的重複代碼,也就是執行我切面裏面的增強
通過OOP也能實現【重複代碼複用】的操作

但是AOP還有其他好處:

  1. 假如說我有10處Controller都要調用這個Service方法,難道我要在10處不同controller裏面 寫上 VerifyUserAop 對象。
  2. 如果我不想要這些驗證呢,那我又要一個個去刪除
  3. 如果我不只是UserAccountServiceImpl 裏面的某個方法要用這個重複代碼,那我需要 調用VerifyUserAop對象的地方是不是更多了。然後如果我後面又要去掉呢?

AOP的另外一個好處就體現出來:配置方便
將當與我想知道你再做什麼,OOP就像是在你家裏裝攝像頭,AOP就是外掛,上帝視角。
當我不想看的時候,OOP還得去拆攝像頭,外掛玩家表示,我不看就是了

那AOP怎麼實現這些額外好處的,這得去看動態代理了,這篇博客只介紹AOP的概念(因爲我的理解也不深刻,怕誤導人)。

AOP的使用:

  1. 首先要再POM裏面加入包的依賴
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.9.5</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.5</version>
    </dependency>
  1. applicationContext裏面加入,開啓AOP註解
    aop:aspectj-autoproxy/
  2. 編寫提取出來的重複邏輯類,也就是切面,用@Aspect聲明
  3. 寫封裝重複邏輯的方法,也就是增強,
  4. 在增強上 用@Before(“切入點表達式”),@After等表示位置
  5. 然後其他的Spring都會替你完成(我們之所以這麼好用,是因爲大佬把邏輯都封裝好了,我們只需要專注業務開發)

完結;

底部:
切面類,也就是封裝重複代碼的類

package com.code.aop;
// 這裏有一大堆導入包,但是我覺得太佔屏幕了,給去掉了
/**
 * 切面類,用來驗證用戶是否登錄
 * @author dengtiantian
 * Component 是加入IOC容器
 * Aspect是 聲明爲切面類
 */
@Component
@Aspect
public class VerifyUserAop {

    @Pointcut("execution(* com.code.service.impl.UserAccountServiceImpl.listUserAccount())")
    public void pointCut(){}

    @Before("pointCut()")
    public void verifyLoginByCookie(){
        System.out.println("AOP前置通知");
        /** 因爲代碼太長了。而且這裏還不能將代碼收起來,太佔屏幕了**/
        // 下面的代碼邏輯是 通過cookie來對登陸的身份進行驗證,如果驗證不通過,重定向到首頁
    }

}

service類

package com.code.service.impl;
// 一堆import 我給去掉了
/**
 * @author dengtiantian
 * Service註解 意思是將對象加入IOC容器,在service層使用
 */
@Service("userAccountService")
public class UserAccountServiceImpl implements IUserAccountService {

    /**
     * Resource 是指定依賴關係。如果沒有指定值,更具類型來找
     * 指定了值,更具名字來找
     * 我指定了值,與 com.code.dao.IUserAccountDao裏的Repository匹配
     */
    @Resource(name = "userAccountDao")
    private IUserAccountDao userAccountDao;

    @Override
    public List<UserAccount> listUserAccount() {
        System.out.println("這裏是UserAccountServiceImpl");
        System.out.println("測試實現接口:listUserAccount()");
        return this.userAccountDao.listUserAccount();
    }
    // 下面本來有一大批service方法,但是我覺得無關,給去掉了
}

Controller類

package com.code.controller;
// 這裏有一大批import
/**
 * @author dengtiantian
 */
@Controller("userAccountController")
public class UserAccountController {
    /**
     * Resource 註解表示依賴哪個,如果沒寫自動的更具類型匹配,那肯定匹配到了IUserAccountService
     * 但是我要的是UserAccountServiceImpl 所以弄name準確匹配
     * 對應的com.code.service.impl.UserAccountServiceImpl裏的service
     *
     */
    @Resource(name = "userAccountService")
    private IUserAccountService userAccountService;
    
    @RequestMapping(value = "/useraccount/listuseraccount",produces = {"application/json;charset=UTF-8"})
    @ResponseBody
    public String listUserAccount(HttpServletRequest request, HttpServletResponse response) throws IOException {
    
    	// 假如如果用OOP方式,這裏就是我例子裏面的切點 重複邏輯插入的地方
    	
        List<UserAccount> list = userAccountService.listUserAccount();
        String strJson = JSON.toJSONString(list);
        return strJson; 
    }
}

源碼地址:https://gitee.com/dengtiantian/javaee_study.git

已收錄

總目錄:Java進階之路-目錄

                欲窮千里目,更上一層樓
                《登黃鶴樓》李白
                博主:五更依舊朝花落
                首次發佈時間:2020年5月18日22:05:07
                末次更新時間:2020年5月19日10:55:50(修改錯別字)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章