Spring Aop初認識(04)

Spring AOP編程

一,概述:

Aop识颊,  aspect object programming  面向切面編程
    功能: 讓關注點代碼與業(yè)務代碼分離苍碟!
關注點,
    重復代碼就叫做關注點;
切面寻狂,
     關注點形成的類,就叫切面(類)萝映!
     面向切面編程檩小,就是指 對很多功能都有的重復的代碼抽取,再在運行的時候網(wǎng)業(yè)務方法上動態(tài)植入“切面類代碼”杜耙。
切入點搜骡,
    執(zhí)行目標對象方法,動態(tài)植入切面代碼佑女。
    可以通過切入點表達式记靡,指定攔截哪些類的哪些方法; 給指定的類在運行的時候植入切面類代碼团驱。

1.1 手動實現(xiàn)aop編程

UserDao.java

// 保存一個用戶
public void add(User user) { 
        Session session = null; 
        Transaction trans = null; 
        try { 
            session = HibernateSessionFactoryUtils.getSession();   // 【關注點代碼】
            trans = session.beginTransaction();    // 【關注點代碼】
             
            session.save(user);     // 核心業(yè)務代碼
             
            trans.commit();     //…【關注點代碼】

        } catch (Exception e) {     
            e.printStackTrace(); 
            if(trans != null){ 
                trans.rollback();   //..【關注點代碼】
            } 
        } finally{ 
            HibernateSessionFactoryUtils.closeSession(session);   ////..【關注點代碼】

        } 
   } 

分析總結:

*關注點代碼摸吠,就是指重復執(zhí)行的代碼。
*業(yè)務代碼與關注點代碼分離嚎花,好處寸痢?
   --→ 關注點代碼寫一次即可;
    -→開發(fā)者只需要關注核心業(yè)務紊选;
    -→運行時期啼止,執(zhí)行核心業(yè)務代碼時候動態(tài)植入關注點代碼; 【代理】

如何分離兵罢?
過程式/對象式/代理模式分離

所以,aop編程,可以理解為面向重復代碼編程.

1.2 xml方式實現(xiàn)aop編程

Xml實現(xiàn)aop編程:
    1) 引入jar文件  【aop 相關jar族壳, 4個】
    先引入aop相關jar文件       (aspectj  aop優(yōu)秀組件)  spring-beans-4.1.6.jar
    spring-context-4.1.6.jar
    spring-core-4.1.6.jar
    spring-expression-4.1.6                 
    spring-aop-4.1.6.RELEASE.jar   【spring4源碼】
    aopalliance-1.0.jar               【spring2.5源碼/lib/aopalliance】
    aspectjweaver.jar             【spring2.5源碼/lib/aspectj】或【aspectj-1.8.2\lib】
    aspectjrt-1.8.1.jar             【spring2.5源碼/lib/aspectj】或【aspectj-1.8.2\lib】
    commons-logging-1.1.3

    2) 引入aop名稱空間
    3)aop 配置
        * 配置切面類 (重復執(zhí)行代碼形成的類)
        * aop配置
            攔截哪些方法 / 攔截到方法后應用通知代碼

1.3 創(chuàng)建工程,項目結構

其中的bean.xml就是applicationContext.xml文件

01aop項目.png

主要類的代碼:

IUserDao.java

package com.it.a_aop;

public interface IUserDao {
    public void save();
}

UserDao.java,實現(xiàn)接口IUSerDao

package com.it.a_aop;

public class UserDao implements IUserDao{

/*
 * AOP核心業(yè)務代碼和關注點代碼(重復代碼)分離
 * */   
    @Override
    public void save() {
        System.out.println("---已經(jīng)保存數(shù)據(jù)----");//核心業(yè)務代碼
    }
}

Admin.java,不實現(xiàn)接口IUserDao

package com.it.a_aop;

public class AdminDao {

    public void save(){
        
        System.out.println("---admin-save");
    }

}

Aop.java,切面類(重點)

package com.it.a_aop;

import org.aspectj.lang.ProceedingJoinPoint;

public class Aop {

    /*
     * 切面類
     * 
     * 面向切面:面向重復代碼,把重復代碼放到一個類
     * */
    //重復執(zhí)行的代碼
    
    //前置通知 : 在執(zhí)行目標方法之前執(zhí)行
    public void begin() {
        System.out.println("開始事務");
    }
    
    //后置/最終通知:在執(zhí)行目標方法之后執(zhí)行  【無論是否出現(xiàn)異常最終都會執(zhí)行】
    public void after() {
        System.out.println("提交事務/關閉");
    }
    
    //返回通知:在調用目標方法結束后執(zhí)行
    public void afterReturning() {
        System.out.println("afterReturning");
    }
    
    
    //異常通知,當目標方法執(zhí)行異常時候執(zhí)行此關注點代碼
    public void afterThrowing() {
        System.out.println("afterThrowing");
    }
    
    
    //環(huán)繞通知:環(huán)繞目標方法執(zhí)行
    public void around(ProceedingJoinPoint pjd) throws Throwable{
        System.out.println("環(huán)繞前");
        pjd.proceed();//執(zhí)行目標方法
        System.out.println("環(huán)繞后");
    }

}

bean.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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
        
        
        <!-- dao實例 -->
    
    <bean id="userDao" class="com.it.a_aop.UserDao"></bean>
    <bean id="adminDao" class="com.it.a_aop.AdminDao"></bean>
    
    <!-- 切面類 -->
    <bean id="aop" class="com.it.a_aop.Aop"></bean>
    
    
    <!-- aop配置 -->
    <aop:config>
        <!-- 定義一個切入點表達式,攔截哪些方法 -->
        <aop:pointcut expression="execution(* com.it.a_aop.*.*(..))" id="pt"/>
        
                
        <!-- 切面類 -->
        <aop:aspect ref="aop">
            <!-- 環(huán)繞通知 -->
            <aop:around method="around" pointcut-ref="pt"/>
            <!-- 前置通知 -->
            <aop:before method="begin" pointcut-ref="pt"/>
            <!-- 后置通知 -->
            <aop:after method="after" pointcut-ref="pt"/>
            <!-- 返回通知 -->
            <aop:after-returning method="afterReturning" pointcut-ref="pt"/>
            <!-- 異常通知 -->
            <aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
        </aop:aspect>
        
    </aop:config>
    
</beans> 

App.java測試


package com.it.a_aop;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    
    @Test
    public void dynamicProxyAop() {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/it/a_aop/bean.xml");

        IUserDao userDao = (IUserDao) ac.getBean("userDao");
        System.out.println(userDao.getClass());
        userDao.save();
    }
    
    @Test
    public void cglibProxyAop() {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/it/a_aop/bean.xml");
    
        AdminDao adminDao = (AdminDao) ac.getBean("adminDao");
        System.out.println(adminDao.getClass());
        adminDao.save();
    }

}

運行測試方法:dynamicProxyAop()的結果

class com.sun.proxy.$Proxy6
環(huán)繞前
開始事務
---已經(jīng)保存數(shù)據(jù)----
環(huán)繞后
提交事務/關閉
afterReturning

根據(jù)打印的class信息,可以知道這是JDK的動態(tài)代理,UserDao實現(xiàn)了接口IUserDao;

運行測試方法cglibProxyAop()的結果

class com.it.a_aop.AdminDao$$EnhancerBySpringCGLIB$$871fa5a8
環(huán)繞前
開始事務
---admin-save
環(huán)繞后
提交事務/關閉
afterReturning

可以知道,這是cglib代理,AdminDao沒有實現(xiàn)接口.

1.3 注解方式實現(xiàn)aop

新建項目,目錄如下

02aop.png

IUserDao.java接口類不變

UserDao.java

package com.it.b_aop_anno;

import org.springframework.stereotype.Component;

@Component(value="userDao")
public class UserDao implements IUserDao{

/*
 * AOP核心業(yè)務代碼和關注點代碼(重復代碼)分離
 * */   
    @Override
    public void save() {
        System.out.println("---已經(jīng)保存數(shù)據(jù)----");//核心業(yè)務代碼
    }
}

AdminDao.java

package com.it.b_aop_anno;

import org.springframework.stereotype.Component;

@Component(value="adminDao")
public class AdminDao {

    public void save(){
        
        System.out.println("---admin-save");
    }

}

Aop.java(重點)

package com.it.b_aop_anno;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component(value="aop")
@Aspect //指定當前類為切面類
public class Aop {

    /*
     * 切面類
     * 
     * 面向切面:面向重復代碼,把重復代碼放到一個類
     * */
    //重復執(zhí)行的代碼
    
    //指定切入點表達式,攔截哪些方法:即為哪些類生產(chǎn)代理對象
    @Pointcut("execution(* com.it.b_aop_anno.*.*(..))")
    public void pointcut() {
        
    }
    
    //前置通知 : 在執(zhí)行目標方法之前執(zhí)行
    @Before("pointcut()")
    public void begin() {
        System.out.println("開始事務");
    }
    
    //后置/最終通知:在執(zhí)行目標方法之后執(zhí)行  【無論是否出現(xiàn)異常最終都會執(zhí)行】
    @After("pointcut()")
    public void after() {
        System.out.println("提交事務/關閉");
    }
    
    //返回通知:在調用目標方法結束后執(zhí)行
    @AfterReturning("pointcut()")
    public void afterReturning() {
        System.out.println("afterReturning");
    }
    
    
    //異常通知,當目標方法執(zhí)行異常時候執(zhí)行此關注點代碼
    @AfterThrowing("pointcut()")
    public void afterThrowing() {
        System.out.println("afterThrowing");
    }
    
    
    //環(huán)繞通知:環(huán)繞目標方法執(zhí)行
    @Around("pointcut()")
    public void around(ProceedingJoinPoint pjd) throws Throwable{
        System.out.println("環(huán)繞前");
        pjd.proceed();//執(zhí)行目標方法
        System.out.println("環(huán)繞后");
    }

}

bean.xml:開啟注冊掃描和開啟aop注解方式

<?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"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
        
        <!--掃描該包com.it.b_aop_anno的注解-->
        <context:component-scan base-package="com.it.b_aop_anno"></context:component-scan>
        <!-- 開啟aop注解方式 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
        
</beans> 

測試類代碼App.java

package com.it.b_aop_anno;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    
    @Test
    public void dynamicProxyAop() {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/it/b_aop_anno/bean.xml");

        IUserDao userDao = (IUserDao) ac.getBean("userDao");
        System.out.println(userDao.getClass());
        userDao.save();
    }
    
    @Test
    public void cglibProxyAop() {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/it/b_aop_anno/bean.xml");
    
        AdminDao adminDao = (AdminDao) ac.getBean("adminDao");
        System.out.println(adminDao.getClass());
        adminDao.save();
    }
}


運行測試方法:dynamicProxyAop()的結果

class com.sun.proxy.$Proxy14
環(huán)繞前
開始事務
---已經(jīng)保存數(shù)據(jù)----
環(huán)繞后
提交事務/關閉
afterReturning

根據(jù)打印的class信息,可以知道這是JDK的動態(tài)代理,UserDao實現(xiàn)了接口IUserDao;

運行測試方法cglibProxyAop()的結果

class com.it.b_aop_anno.AdminDao$$EnhancerBySpringCGLIB$$5e3ea260
環(huán)繞前
開始事務
---admin-save
環(huán)繞后
提交事務/關閉
afterReturning

可以知道,這是cglib代理,AdminDao沒有實現(xiàn)接口.

1.5 常見的切入點表達式:

切入點表達式,
可以對指定的“方法”進行攔截; 從而給指定的方法所在的類生層代理對象趣些。

<!-- 定義一個切入點表達式,攔截哪些方法 -->
        <aop:pointcut expression="execution(* com.it.a_aop.*.*(..))" id="pt"/>
        <!-- 攔截所有public方法 -->
         
        <aop:pointcut expression="execution(public * *(..))" id="pt"/>
        攔截所有save開頭方法
        <aop:pointcut expression="execution(* save*(..))" id="pt"/>
        攔截指定類的指定方法 ,要定位到方法
        <aop:pointcut expression="execution(public * com.it.a_aop.UserDao.save(..))" id="pt"/>
        攔截指定類所有方法 
        <aop:pointcut expression="execution(* com.it.a_aop.UserDao.*(..))" id=""/>
        攔截指定包,以及其子包下的所有類的所有方法
        <aop:pointcut expression="execution(* com..*.*(..))" id="pt"/>
        
        多個表達式
        <aop:pointcut expression="execution(* com.it.a_aop.UserDao.save() or execution(* com.it.a_aop.AdminDao.save()))" id="pt"/>
        <aop:pointcut expression="execution(* com.it.a_aop.UserDao.save() || execution(* com.it.a_aop.AdminDao.save()))" id="pt"/>
        
        以下的兩個且表達式?jīng)]有意義
        <aop:pointcut expression="execution(* com.it.a_aop.UserDao.save() and execution(* com.it.a_aop.AdminDao.save()))" id="pt"/>
        <aop:pointcut expression="execution(* com.it.a_aop.UserDao.save() &amp;&amp; execution(* com.it.a_aop.AdminDao.save()))" id="pt"/>
        
        非
        <aop:pointcut expression="!execution(* com.it.a_aop.UserDao.save()" id="pt"/>
        <aop:pointcut expression=" not execution(* com.it.a_aop.UserDao.save()" id="pt"/>

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末仿荆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拢操,老刑警劉巖锦亦,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異令境,居然都是意外死亡杠园,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門舔庶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抛蚁,“玉大人,你說我怎么就攤上這事惕橙∏扑Γ” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵弥鹦,是天一觀的道長肚逸。 經(jīng)常有香客問我,道長彬坏,這世上最難降的妖魔是什么朦促? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮栓始,結果婚禮上务冕,老公的妹妹穿的比我還像新娘。我一直安慰自己幻赚,他們只是感情好禀忆,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坯屿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪巍扛。 梳的紋絲不亂的頭發(fā)上领跛,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音撤奸,去河邊找鬼吠昭。 笑死,一個胖子當著我的面吹牛胧瓜,可吹牛的內(nèi)容都是我干的矢棚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼府喳,長吁一口氣:“原來是場噩夢啊……” “哼蒲肋!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤兜粘,失蹤者是張志新(化名)和其女友劉穎申窘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孔轴,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡剃法,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了路鹰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贷洲。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖晋柱,靈堂內(nèi)的尸體忽然破棺而出优构,到底是詐尸還是另有隱情,我是刑警寧澤趣斤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布俩块,位于F島的核電站,受9級特大地震影響浓领,放射性物質發(fā)生泄漏玉凯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一联贩、第九天 我趴在偏房一處隱蔽的房頂上張望漫仆。 院中可真熱鬧,春花似錦泪幌、人聲如沸盲厌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吗浩。三九已至,卻和暖如春没隘,著一層夾襖步出監(jiān)牢的瞬間懂扼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工右蒲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留阀湿,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓瑰妄,卻偏偏與公主長得像陷嘴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子间坐,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一> 代理模式 概述 代理(Proxy)是一種設計模式灾挨, 提供了對目標對象另外的訪問方式邑退;即通過代理訪問目標對象。...
    奮斗的老王閱讀 1,117評論 0 50
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理涨醋,服務發(fā)現(xiàn)瓜饥,斷路器,智...
    卡卡羅2017閱讀 134,661評論 18 139
  • **** AOP 面向切面編程 底層原理 代理T÷睢E彝痢! 今天AOP課程1溯警、 Spring 傳統(tǒng) AOP2趣苏、 Spri...
    luweicheng24閱讀 1,369評論 0 1
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法梯轻,內(nèi)部類的語法食磕,繼承相關的語法,異常的語法喳挑,線程的語...
    子非魚_t_閱讀 31,639評論 18 399
  • 什么是Spring Spring是一個開源的Java EE開發(fā)框架彬伦。Spring框架的核心功能可以應用在任何Jav...
    jemmm閱讀 16,464評論 1 133