中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

東莞網(wǎng)站建設(shè)公司 網(wǎng)絡(luò)服務(wù)杭州推廣公司

東莞網(wǎng)站建設(shè)公司 網(wǎng)絡(luò)服務(wù),杭州推廣公司,推廣一般去哪發(fā)帖,網(wǎng)站建設(shè)結(jié)算系統(tǒng)spring5(五):AOP操作前言一、代理模式1、場(chǎng)景模擬2、代理模式2.1 概念2.2 靜態(tài)代理2.3 動(dòng)態(tài)代理二、AOP概述1、什么是 AOP?2、相關(guān)術(shù)語3、作用三、AOP底層原理1、AOP 底層使用動(dòng)態(tài)代理2、AOP(JDK 動(dòng)態(tài)代理)2.1 編寫 J…

spring5(五):AOP操作

  • 前言
  • 一、代理模式
    • 1、場(chǎng)景模擬
    • 2、代理模式
      • 2.1 概念
      • 2.2 靜態(tài)代理
      • 2.3 動(dòng)態(tài)代理
  • 二、AOP概述
    • 1、什么是 AOP?
    • 2、相關(guān)術(shù)語
    • 3、作用
  • 三、AOP底層原理
    • 1、AOP 底層使用動(dòng)態(tài)代理
    • 2、AOP(JDK 動(dòng)態(tài)代理)
      • 2.1 編寫 JDK 動(dòng)態(tài)代理代碼
  • 四、AOP 操作的準(zhǔn)備工作
    • 1、AspectJ概述
    • 2、依賴的引入
  • 五、AOP操作(注解版)
    • 1、添加依賴
    • 2、準(zhǔn)備被代理的目標(biāo)資源
    • 3、在Spring的配置文件中配置
    • 4、創(chuàng)建切面類并配置
    • 5、測(cè)試
  • 六、重點(diǎn)
    • 1、 切入點(diǎn)表達(dá)式
    • 2、重用切入點(diǎn)表達(dá)式
    • 3、獲取通知的相關(guān)信息
    • 4、環(huán)繞通知
    • 5、切面的優(yōu)先級(jí)
    • 6、完全使用注解開發(fā)
  • 七、AOP 操作(AspectJ 配置文件)
    • 1、創(chuàng)建兩個(gè)類,增強(qiáng)類和被增強(qiáng)類,創(chuàng)建方法
    • 2、在 spring 配置文件中創(chuàng)建兩個(gè)類對(duì)象
    • 3、在 spring 配置文件中配置切入點(diǎn)



前言

本博主將用CSDN記錄軟件開發(fā)求學(xué)之路上親身所得與所學(xué)的心得與知識(shí),有興趣的小伙伴可以關(guān)注博主!也許一個(gè)人獨(dú)行,可以走的很快,但是一群人結(jié)伴而行,才能走的更遠(yuǎn)!讓我們?cè)诔砷L(zhǎng)的道路上互相學(xué)習(xí),歡迎關(guān)注!

一、代理模式

1、場(chǎng)景模擬

(1)聲明計(jì)算器接口Calculator,包含加減乘除的抽象方法

public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j);
}

(2)創(chuàng)建實(shí)現(xiàn)類
在這里插入圖片描述

public class CalculatorPureImpl implements Calculator {@Overridepublic int add(int i, int j) {int result = i + j;System.out.println("方法內(nèi)部 result = " + result);return result;}@Overridepublic int sub(int i, int j) {int result = i - j;System.out.println("方法內(nèi)部 result = " + result);return result;}@Overridepublic int mul(int i, int j) {int result = i * j;System.out.println("方法內(nèi)部 result = " + result);return result;}@Overridepublic int div(int i, int j) {int result = i / j;System.out.println("方法內(nèi)部 result = " + result);return result;}
}

(3)創(chuàng)建帶日志功能的實(shí)現(xiàn)類
在這里插入圖片描述

public class CalculatorLogImpl implements Calculator {@Overridepublic int add(int i, int j) {System.out.println("[日志] add 方法開始了,參數(shù)是:" + i + "," + j);int result = i + j;System.out.println("方法內(nèi)部 result = " + result);System.out.println("[日志] add 方法結(jié)束了,結(jié)果是:" + result);return result;}@Overridepublic int sub(int i, int j) {System.out.println("[日志] sub 方法開始了,參數(shù)是:" + i + "," + j);int result = i - j;System.out.println("方法內(nèi)部 result = " + result);System.out.println("[日志] sub 方法結(jié)束了,結(jié)果是:" + result);return result;}@Overridepublic int mul(int i, int j) {System.out.println("[日志] mul 方法開始了,參數(shù)是:" + i + "," + j);int result = i * j;System.out.println("方法內(nèi)部 result = " + result);System.out.println("[日志] mul 方法結(jié)束了,結(jié)果是:" + result);return result;}@Overridepublic int div(int i, int j) {System.out.println("[日志] div 方法開始了,參數(shù)是:" + i + "," + j);int result = i / j;System.out.println("方法內(nèi)部 result = " + result);System.out.println("[日志] div 方法結(jié)束了,結(jié)果是:" + result);return result;}
}

(4)提出問題

? 現(xiàn)有代碼缺陷:
針對(duì)帶日志功能的實(shí)現(xiàn)類,我們發(fā)現(xiàn)有如下缺陷: 對(duì)核心業(yè)務(wù)功能有干擾,導(dǎo)致程序員在開發(fā)核心業(yè)務(wù)功能時(shí)分散了精力
附加功能分散在各個(gè)業(yè)務(wù)功能方法中,不利于統(tǒng)一維護(hù)
? 解決思路:
解決這兩個(gè)問題,核心就是:解耦。我們需要把附加功能從業(yè)務(wù)功能代碼中抽取出來。
? 困難:
解決問題的困難:要抽取的代碼在方法內(nèi)部,靠以前把子類中的重復(fù)代碼抽取到父類的方式?jīng)]法解決。 所以需要引入新的技術(shù)。

2、代理模式

2.1 概念

①介紹

二十三種設(shè)計(jì)模式中的一種,屬于結(jié)構(gòu)型模式。它的作用就是通過提供一個(gè)代理類,讓我們?cè)谡{(diào)用目標(biāo)方法的時(shí)候,不再是直接對(duì)目標(biāo)方法進(jìn)行調(diào)用,而是通過代理類間接調(diào)用。讓不屬于目標(biāo)方法核心邏輯的代碼從目標(biāo)方法中剝離出來——解耦。調(diào)用目標(biāo)方法時(shí)先調(diào)用代理對(duì)象的方法,減少對(duì)目標(biāo)方法的調(diào)用和打擾,同時(shí)讓附加功能能夠集中在一起也有利于統(tǒng)一維護(hù)。

? 使用代理前:
在這里插入圖片描述

? 使用代理后:
在這里插入圖片描述

②生活中的代理

● 廣告商找大明星拍廣告需要經(jīng)過經(jīng)紀(jì)人
● 合作伙伴找大老板談合作要約見面時(shí)間需要經(jīng)過秘書
● 房產(chǎn)中介是買賣雙方的代理

③相關(guān)術(shù)語

● 代理:將非核心邏輯剝離出來以后,封裝這些非核心邏輯的類、對(duì)象、方法。
● 目標(biāo):被代理“套用”了非核心邏輯代碼的類、對(duì)象、方法。

2.2 靜態(tài)代理

public class CalculatorStaticProxy implements Calculator {// 將被代理的目標(biāo)對(duì)象聲明為成員變量private Calculator target;public CalculatorStaticProxy(Calculator target) {this.target = target;}@Overridepublic int add(int i, int j) {// 附加功能由代理類中的代理方法來實(shí)現(xiàn)System.out.println("[日志] add 方法開始了,參數(shù)是:" + i + "," + j);// 通過目標(biāo)對(duì)象來實(shí)現(xiàn)核心業(yè)務(wù)邏輯int addResult = target.add(i, j);System.out.println("[日志] add 方法結(jié)束了,結(jié)果是:" + addResult);return addResult;}
}

靜態(tài)代理確實(shí)實(shí)現(xiàn)了解耦,但是由于代碼都寫死了,完全不具備任何的靈活性。就拿日志功能來
說,將來其他地方也需要附加日志,那還得再聲明更多個(gè)靜態(tài)代理類,那就產(chǎn)生了大量重復(fù)的代
碼,日志功能還是分散的,沒有統(tǒng)一管理。
提出進(jìn)一步的需求:將日志功能集中到一個(gè)代理類中,將來有任何日志需求,都通過這一個(gè)代理
類來實(shí)現(xiàn)。這就需要使用動(dòng)態(tài)代理技術(shù)了

2.3 動(dòng)態(tài)代理

在這里插入圖片描述
生產(chǎn)代理對(duì)象的工廠類:

public class ProxyFactory {private Object target;public ProxyFactory(Object target) {this.target = target;}public Object getProxy(){/*** newProxyInstance():創(chuàng)建一個(gè)代理實(shí)例* 其中有三個(gè)參數(shù):* 1、classLoader:加載動(dòng)態(tài)生成的代理類的類加載器* 2、interfaces:目標(biāo)對(duì)象實(shí)現(xiàn)的所有接口的class對(duì)象所組成的數(shù)組* 3、invocationHandler:設(shè)置代理對(duì)象實(shí)現(xiàn)目標(biāo)對(duì)象方法的過程,即代理類中如何重寫接口中的抽象方法*/ClassLoader classLoader = target.getClass().getClassLoader();Class<?>[] interfaces = target.getClass().getInterfaces();InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/*** proxy:代理對(duì)象* method:代理對(duì)象需要實(shí)現(xiàn)的方法,即其中需要重寫的方法* args:method所對(duì)應(yīng)方法的參數(shù)*/Object result = null;try {System.out.println("[動(dòng)態(tài)代理][日志] "+method.getName()+",參數(shù):"+ Arrays.toString(args));result = method.invoke(target, args);System.out.println("[動(dòng)態(tài)代理][日志] "+method.getName()+",結(jié)果:"+ result);} catch (Exception e) {e.printStackTrace();System.out.println("[動(dòng)態(tài)代理][日志] "+method.getName()+",異常:"+e.getMessage());} finally {System.out.println("[動(dòng)態(tài)代理][日志] "+method.getName()+",方法執(zhí)行完畢");}return result;}};return Proxy.newProxyInstance(classLoader, interfaces,invocationHandler);}
}

測(cè)試

@Test
public void testDynamicProxy(){ProxyFactory factory = new ProxyFactory(new CalculatorLogImpl());Calculator proxy = (Calculator) factory.getProxy();proxy.div(1,0);//proxy.div(1,1);
}

二、AOP概述

1、什么是 AOP?

?AOP(Aspect Oriented Programming)是一種設(shè)計(jì)思想,是軟件設(shè)計(jì)領(lǐng)域中的面向切面編程,它是面向?qū)ο缶幊痰囊环N補(bǔ)充和完善,它以通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理方式實(shí)現(xiàn)在不修改源代碼的情況下給程序動(dòng)態(tài)統(tǒng)一添加額外功能的一種技術(shù)。

? 通俗描述:不通過修改源代碼方式,在主干功能里面添加新功能

2、相關(guān)術(shù)語

? 橫切關(guān)注點(diǎn)

從每個(gè)方法中抽取出來的同一類非核心業(yè)務(wù)。在同一個(gè)項(xiàng)目中,我們可以使用多個(gè)橫切關(guān)注點(diǎn)對(duì)相關(guān)方法進(jìn)行多個(gè)不同方面的增強(qiáng)。
這個(gè)概念不是語法層面天然存在的,而是根據(jù)附加功能的邏輯上的需要:有十個(gè)附加功能,就有十個(gè)橫切關(guān)注點(diǎn),比如上例中CalculatorImpl類中的日志代碼是非核心代碼,我們把這些非核心代碼抽取出來,作為一些附加功能,即橫切關(guān)注點(diǎn)。
附加功能相對(duì)于目標(biāo)類來說是橫切關(guān)注點(diǎn),相對(duì)于目標(biāo)類來說是通知。

在這里插入圖片描述
? 通知

每一個(gè)橫切關(guān)注點(diǎn)上要做的事情都需要寫一個(gè)方法來實(shí)現(xiàn),這樣的方法就叫通知方法。

  1. 前置通知:在被代理的目標(biāo)方法前執(zhí)行
  2. 返回通知:在被代理的目標(biāo)方法成功結(jié)束后執(zhí)行(壽終正寢)
  3. 異常通知:在被代理的目標(biāo)方法異常結(jié)束后執(zhí)行(死于非命)
  4. 后置通知:在被代理的目標(biāo)方法最終結(jié)束后執(zhí)行(蓋棺定論)
  5. 環(huán)繞通知:使用try…catch…finally結(jié)構(gòu)圍繞整個(gè)被代理的目標(biāo)方法,包括上面四種通知對(duì)應(yīng)的所有位置

在這里插入圖片描述

? 切面

封裝通知方法的類。

在這里插入圖片描述
?目標(biāo)

被代理的目標(biāo)對(duì)象。

?代理

向目標(biāo)對(duì)象應(yīng)用通知之后創(chuàng)建的代理對(duì)象。

?連接點(diǎn)

這也是一個(gè)純邏輯概念,不是語法定義的。
把方法排成一排,每一個(gè)橫切位置看成x軸方向,把方法從上到下執(zhí)行的順序看成y軸,x軸和y軸的交叉點(diǎn)就是連接點(diǎn)。

在這里插入圖片描述
?切入點(diǎn)

定位連接點(diǎn)的方式。
每個(gè)類的方法中都包含多個(gè)連接點(diǎn),所以連接點(diǎn)是類中客觀存在的事物(從邏輯上來說)。
如果把連接點(diǎn)看作數(shù)據(jù)庫(kù)中的記錄,那么切入點(diǎn)就是查詢記錄的 SQL 語句。
SpringAOP 技術(shù)可以通過切入點(diǎn)定位到特定的連接點(diǎn)。
切點(diǎn)通過 org.springframework.aop.Pointcut 接口進(jìn)行描述,它使用類和方法作為連接點(diǎn)的查詢條件。

3、作用

  1. 簡(jiǎn)化代碼:把方法中固定位置的重復(fù)的代碼抽取出來,讓被抽取的方法更專注于自己的核心功能,提高內(nèi)聚性。
  2. 代碼增強(qiáng):把特定的功能封裝到切面類中,看哪里有需要,就往上套,被套用了切面邏輯的方法就被切面給增強(qiáng)了。

三、AOP底層原理

1、AOP 底層使用動(dòng)態(tài)代理

有兩種情況動(dòng)態(tài)代理:

? 第一種 有接口情況,使用 JDK 動(dòng)態(tài)代理

創(chuàng)建接口實(shí)現(xiàn)類代理對(duì)象,增強(qiáng)類的方法

在這里插入圖片描述

? 第二種 沒有接口情況,使用 cglib 動(dòng)態(tài)代理
創(chuàng)建子類的代理對(duì)象,增強(qiáng)類的方法

在這里插入圖片描述

2、AOP(JDK 動(dòng)態(tài)代理)

① 使用 JDK 動(dòng)態(tài)代理,使用 Proxy 類里面的方法創(chuàng)建代理對(duì)象

在這里插入圖片描述

② 調(diào)用 newProxyInstance() 方法
方法有三個(gè)參數(shù):

  1. 第一參數(shù),類加載器
  2. 第二參數(shù),增強(qiáng)方法所在的類,這個(gè)類實(shí)現(xiàn)的接口,支持多個(gè)接口
  3. 第三參數(shù),實(shí)現(xiàn)這個(gè)接口InvocationHandler,創(chuàng)建代理對(duì)象,寫增強(qiáng)的部分

在這里插入圖片描述

2.1 編寫 JDK 動(dòng)態(tài)代理代碼

① 創(chuàng)建接口,定義方法


public interface UserDao {public int add(int a,int b);public String update(String id);
}

② 創(chuàng)建接口實(shí)現(xiàn)類,實(shí)現(xiàn)方法

public class UserDaoImpl implements UserDao {@Overridepublic int add(int a, int b) {System.out.println("add方法執(zhí)行了.....");return a+b;}@Overridepublic String update(String id) {System.out.println("update方法執(zhí)行了.....");return id;}
}

③ 使用 Proxy 類創(chuàng)建接口代理對(duì)象

public class JDKProxy {public static void main(String[] args) {//創(chuàng)建接口實(shí)現(xiàn)類代理對(duì)象Class[] interfaces = {UserDao.class};
//        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
//            @Override
//            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                return null;
//            }
//        });UserDaoImpl userDao = new UserDaoImpl();UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));int result = dao.add(1, 2);System.out.println("result:"+result);}
}//創(chuàng)建代理對(duì)象代碼
class UserDaoProxy implements InvocationHandler {//1 把創(chuàng)建的是誰的代理對(duì)象,把誰傳遞過來//有參數(shù)構(gòu)造傳遞private Object obj;public UserDaoProxy(Object obj) {this.obj = obj;}//增強(qiáng)的邏輯@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//方法之前System.out.println("方法之前執(zhí)行...."+method.getName()+" :傳遞的參數(shù)..."+ Arrays.toString(args));//被增強(qiáng)的方法執(zhí)行Object res = method.invoke(obj, args);//方法之后System.out.println("方法之后執(zhí)行...."+obj);return res;}
}

四、AOP 操作的準(zhǔn)備工作

1、AspectJ概述

? Spring 框架一般都是基于 AspectJ 實(shí)現(xiàn) AOP 操作
AspectJ 不是 Spring 組成部分,獨(dú)立 AOP 框架,一般把 AspectJSpirng 框架一起使用,進(jìn)行 AOP操作

? 基于 AspectJ 實(shí)現(xiàn) AOP 操作

  1. 基于 xml 配置文件實(shí)現(xiàn)
  2. 基于注解方式實(shí)現(xiàn)

? 在項(xiàng)目工程里面引入 AOP 相關(guān)依賴

2、依賴的引入

五、AOP操作(注解版)

1、添加依賴

IOC所需依賴基礎(chǔ)上再加入下面依賴即可:

<!-- spring-aspects會(huì)幫我們傳遞過來aspectjweaver -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.1</version>
</dependency>

2、準(zhǔn)備被代理的目標(biāo)資源

接口:

public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j);
}

實(shí)現(xiàn)類:

@Component
public class CalculatorPureImpl implements Calculator {@Overridepublic int add(int i, int j) {int result = i + j;System.out.println("方法內(nèi)部 result = " + result);return result;}@Overridepublic int sub(int i, int j) {int result = i - j;System.out.println("方法內(nèi)部 result = " + result);return result;}@Overridepublic int mul(int i, int j) {int result = i * j;System.out.println("方法內(nèi)部 result = " + result);return result;}@Overridepublic int div(int i, int j) {int result = i / j;System.out.println("方法內(nèi)部 result = " + result);return result;}
}

3、在Spring的配置文件中配置

<!--
基于注解的AOP的實(shí)現(xiàn):
1、將目標(biāo)對(duì)象和切面交給IOC容器管理(注解+掃描)
2、開啟AspectJ的自動(dòng)代理,為目標(biāo)對(duì)象自動(dòng)生成代理
3、將切面類通過注解@Aspect標(biāo)識(shí)
-->
<context:component-scan base-package="com.atguigu.aop.annotation">
</context:component-scan>
<aop:aspectj-autoproxy />

4、創(chuàng)建切面類并配置

package com.reds.AOPTest;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;import java.util.Arrays;/*** Date:2022/7/4* Author:ybc* Description:* 1、在切面中,需要通過指定的注解將方法標(biāo)識(shí)為通知方法* @Before:前置通知,在目標(biāo)對(duì)象方法執(zhí)行之前執(zhí)行* @After:后置通知,在目標(biāo)對(duì)象方法的finally字句中執(zhí)行* @AfterReturning:返回通知,在目標(biāo)對(duì)象方法返回值之后執(zhí)行* @AfterThrowing:異常通知,在目標(biāo)對(duì)象方法的catch字句中執(zhí)行*** 2、切入點(diǎn)表達(dá)式:設(shè)置在標(biāo)識(shí)通知的注解的value屬性中* execution(public int com.atguigu.spring.aop.annotation.CalculatorImpl.add(int, int)* execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..)* 第一個(gè)*表示任意的訪問修飾符和返回值類型* 第二個(gè)*表示類中任意的方法* ..表示任意的參數(shù)列表* 類的地方也可以使用*,表示包下所有的類* 3、重用切入點(diǎn)表達(dá)式* //@Pointcut聲明一個(gè)公共的切入點(diǎn)表達(dá)式* @Pointcut("execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..))")* public void pointCut(){}* 使用方式:@Before("pointCut()")** 4、獲取連接點(diǎn)的信息* 在通知方法的參數(shù)位置,設(shè)置JoinPoint類型的參數(shù),就可以獲取連接點(diǎn)所對(duì)應(yīng)方法的信息* //獲取連接點(diǎn)所對(duì)應(yīng)方法的簽名信息* Signature signature = joinPoint.getSignature();* //獲取連接點(diǎn)所對(duì)應(yīng)方法的參數(shù)* Object[] args = joinPoint.getArgs();** 5、切面的優(yōu)先級(jí)* 可以通過@Order注解的value屬性設(shè)置優(yōu)先級(jí),默認(rèn)值Integer的最大值* @Order注解的value屬性值越小,優(yōu)先級(jí)越高**/
@Component
@Aspect //將當(dāng)前組件標(biāo)識(shí)為切面
public class LoggerAspect {@Pointcut("execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..))")public void pointCut(){}//@Before("execution(public int com.atguigu.spring.aop.annotation.CalculatorImpl.add(int, int))")//@Before("execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..))")@Before("pointCut()")public void beforeAdviceMethod(JoinPoint joinPoint) {//獲取連接點(diǎn)所對(duì)應(yīng)方法的簽名信息Signature signature = joinPoint.getSignature();//獲取連接點(diǎn)所對(duì)應(yīng)方法的參數(shù)Object[] args = joinPoint.getArgs();System.out.println("LoggerAspect,方法:"+signature.getName()+",參數(shù):"+ Arrays.toString(args));}@After("pointCut()")public void afterAdviceMethod(JoinPoint joinPoint){//獲取連接點(diǎn)所對(duì)應(yīng)方法的簽名信息Signature signature = joinPoint.getSignature();System.out.println("LoggerAspect,方法:"+signature.getName()+",執(zhí)行完畢");}/*** 在返回通知中若要獲取目標(biāo)對(duì)象方法的返回值* 只需要通過@AfterReturning注解的returning屬性* 就可以將通知方法的某個(gè)參數(shù)指定為接收目標(biāo)對(duì)象方法的返回值的參數(shù)*/@AfterReturning(value = "pointCut()", returning = "result")public void afterReturningAdviceMethod(JoinPoint joinPoint, Object result){//獲取連接點(diǎn)所對(duì)應(yīng)方法的簽名信息Signature signature = joinPoint.getSignature();System.out.println("LoggerAspect,方法:"+signature.getName()+",結(jié)果:"+result);}/*** 在異常通知中若要獲取目標(biāo)對(duì)象方法的異常* 只需要通過AfterThrowing注解的throwing屬性* 就可以將通知方法的某個(gè)參數(shù)指定為接收目標(biāo)對(duì)象方法出現(xiàn)的異常的參數(shù)*/@AfterThrowing(value = "pointCut()", throwing = "ex")public void afterThrowingAdviceMethod(JoinPoint joinPoint, Throwable ex){//獲取連接點(diǎn)所對(duì)應(yīng)方法的簽名信息Signature signature = joinPoint.getSignature();System.out.println("LoggerAspect,方法:"+signature.getName()+",異常:"+ex);}@Around("pointCut()")//環(huán)繞通知的方法的返回值一定要和目標(biāo)對(duì)象方法的返回值一致public Object aroundAdviceMethod(ProceedingJoinPoint joinPoint){Object result = null;try {System.out.println("環(huán)繞通知-->前置通知");//表示目標(biāo)對(duì)象方法的執(zhí)行result = joinPoint.proceed();System.out.println("環(huán)繞通知-->返回通知");} catch (Throwable throwable) {throwable.printStackTrace();System.out.println("環(huán)繞通知-->異常通知");} finally {System.out.println("環(huán)繞通知-->后置通知");}return result;}}

5、測(cè)試

public class AOPByAnnotationTest {@Test
public void testAOPByAnnotation(){ApplicationContext ioc = new ClassPathXmlApplicationContext("aop-annotation.xml");//Calculator :代理對(duì)象和目標(biāo)對(duì)象共同實(shí)現(xiàn)的接口Calculator calculator = ioc.getBean(Calculator.class);calculator.div(10, 1);
}

如果直接獲取目標(biāo)類,此時(shí)會(huì)報(bào)無法找到實(shí)例的錯(cuò)誤。
原因是:
我們?yōu)槟繕?biāo)對(duì)象創(chuàng)建了代理對(duì)象,因此我們每次想訪問目標(biāo)對(duì)象中的方法時(shí)都不能直接通過目標(biāo)對(duì)象去訪問,必須通過代理對(duì)象來間接訪問目標(biāo)對(duì)象,進(jìn)而去訪問目標(biāo)對(duì)象中的方法,所以我們下一步應(yīng)該是去獲取代理對(duì)象,可是我們并不知道代理對(duì)象是什么,但是我們知道代理對(duì)象跟我們的目標(biāo)對(duì)象實(shí)現(xiàn)的是相同的接口,我們之前通過IOC獲取某個(gè)bean的時(shí)候,我們不需要通過某個(gè)具體的類型來獲取,我們可以用它所繼承的父類或者所實(shí)現(xiàn)的接口,都可以獲取到bean。

六、重點(diǎn)

1、 切入點(diǎn)表達(dá)式

作用

知道對(duì)哪個(gè)類里面的哪個(gè)方法進(jìn)行增強(qiáng)

在這里插入圖片描述

語法結(jié)構(gòu)

execution([權(quán)限修飾符] [返回類型] [類全路徑] [方法名稱]([參數(shù)列表]) )

為了方便,權(quán)限修飾符一般使用* 代替 ,返回類型一般省略不寫

? 用*號(hào)代替“權(quán)限修飾符”和“返回值”部分表示“權(quán)限修飾符”和“返回值”不限在包名的部分,一個(gè)“*”號(hào)只能代表包的層次結(jié)構(gòu)中的一層,表示這一層是任意的。
例如:*.Hello匹配com.Hello,不匹配com.atguigu.Hello

? 在包名的部分,使用“*..”表示包名任意、包的層次深度任意

? 在類名的部分,類名部分整體用*號(hào)代替,表示類名任意

? 在類名的部分,可以使用*號(hào)代替類名的一部分
例如:*Service匹配所有名稱以Service結(jié)尾的類或接口

? 在方法名部分,可以使用*號(hào)表示方法名任意

? 在方法名部分,可以使用*號(hào)代替方法名的一部分
例如:*Operation匹配所有方法名以Operation結(jié)尾的方法

? 在方法參數(shù)列表部分,使用(..)表示參數(shù)列表任意

? 在方法參數(shù)列表部分,使用(int,..)表示參數(shù)列表以一個(gè)int類型的參數(shù)開頭

? 在方法參數(shù)列表部分,基本數(shù)據(jù)類型和對(duì)應(yīng)的包裝類型是不一樣的 切入點(diǎn)表達(dá)式中使用 int 和實(shí)際方法中 Integer 是不匹配的

? 在方法返回值部分,如果想要明確指定一個(gè)返回值類型,那么必須同時(shí)寫明權(quán)限修飾符
例如:execution(public int ..Service.*(.., int)) 正確
例如:execution(* int ..Service.*(.., int)) 錯(cuò)誤

?
舉例 1:對(duì) com.atguigu.dao.BookDao 類里面的 add 進(jìn)行增強(qiáng)
execution(*com.atguigu.dao.BookDao.add(..))
舉例 2:對(duì) com.atguigu.dao.BookDao類里面的所有的方法進(jìn)行增強(qiáng) execution(* com.atguigu.dao.BookDao.* (..))
舉例 3:對(duì)com.atguigu.dao 包里面所有類,類里面所有方法進(jìn)行增強(qiáng) execution(* com.atguigu.dao.*.* (..))

在這里插入圖片描述

2、重用切入點(diǎn)表達(dá)式

①聲明

@Pointcut("execution(* com.atguigu.aop.annotation.*.*(..))")
public void pointCut(){}

②在同一個(gè)切面中使用

@Before("pointCut()")
public void beforeMethod(JoinPoint joinPoint){String methodName = joinPoint.getSignature().getName();String args = Arrays.toString(joinPoint.getArgs());System.out.println("Logger-->前置通知,方法名:"+methodName+",參數(shù):"+args);
}

③在不同切面中使用

@Before("com.atguigu.aop.CommonPointCut.pointCut()")
public void beforeMethod(JoinPoint joinPoint){String methodName = joinPoint.getSignature().getName();String args = Arrays.toString(joinPoint.getArgs());System.out.println("Logger-->前置通知,方法名:"+methodName+",參數(shù):"+args);
}

3、獲取通知的相關(guān)信息

①獲取連接點(diǎn)信息

獲取連接點(diǎn)信息可以在通知方法的參數(shù)位置設(shè)置JoinPoint類型的形參

@Before("execution(public int com.atguigu.aop.annotation.CalculatorImpl.*(..))")
public void beforeMethod(JoinPoint joinPoint){//獲取連接點(diǎn)的簽名信息String methodName = joinPoint.getSignature().getName();//獲取目標(biāo)方法到的實(shí)參信息String args = Arrays.toString(joinPoint.getArgs());System.out.println("Logger-->前置通知,方法名:"+methodName+",參數(shù):"+args);
}

②獲取目標(biāo)方法的返回值

@AfterReturning中的屬性returning,用來將通知方法的某個(gè)形參,接收目標(biāo)方法的返回值

@AfterReturning(value = "execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))", returning = "result")
public void afterReturningMethod(JoinPoint joinPoint, Object result){String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->返回通知,方法名:"+methodName+",結(jié)果:"+result);
}

③獲取目標(biāo)方法的異常

@AfterThrowing中的屬性throwing,用來將通知方法的某個(gè)形參,接收目標(biāo)方法的異常

@AfterThrowing(value = "execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))", throwing = "ex")
public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex){String methodName = joinPoint.getSignature().getName();System.out.println("Logger-->異常通知,方法名:"+methodName+",異常:"+ex);
}

4、環(huán)繞通知

@Around("execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))")
public Object aroundMethod(ProceedingJoinPoint joinPoint){String methodName = joinPoint.getSignature().getName();String args = Arrays.toString(joinPoint.getArgs());Object result = null;try {System.out.println("環(huán)繞通知-->目標(biāo)對(duì)象方法執(zhí)行之前");//目標(biāo)方法的執(zhí)行,目標(biāo)方法的返回值一定要返回給外界調(diào)用者result = joinPoint.proceed();System.out.println("環(huán)繞通知-->目標(biāo)對(duì)象方法返回值之后");} catch (Throwable throwable) {throwable.printStackTrace();System.out.println("環(huán)繞通知-->目標(biāo)對(duì)象方法出現(xiàn)異常時(shí)");} finally {System.out.println("環(huán)繞通知-->目標(biāo)對(duì)象方法執(zhí)行完畢");}return result;
}

5、切面的優(yōu)先級(jí)

? 相同目標(biāo)方法上同時(shí)存在多個(gè)切面時(shí),切面的優(yōu)先級(jí)控制切面的內(nèi)外嵌套順序。

  1. 優(yōu)先級(jí)高的切面:外面
  2. 優(yōu)先級(jí)低的切面:里面

? 使用@Order注解可以控制切面的優(yōu)先級(jí):

  1. @Order(較小的數(shù)):優(yōu)先級(jí)高
  2. @Order(較大的數(shù)):優(yōu)先級(jí)低

在這里插入圖片描述

6、完全使用注解開發(fā)

創(chuàng)建配置類,不需要?jiǎng)?chuàng)建 xml 配置文件

@Configuration
@ComponentScan(basePackages = {"aopanno"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {}

七、AOP 操作(AspectJ 配置文件)

1、創(chuàng)建兩個(gè)類,增強(qiáng)類和被增強(qiáng)類,創(chuàng)建方法

Book類

public class Book {public void buy() {System.out.println("buy.............");}
}

BookProxy類

public class BookProxy {public void before() {System.out.println("before.........");}
}

2、在 spring 配置文件中創(chuàng)建兩個(gè)類對(duì)象

 <!--創(chuàng)建對(duì)象--><bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean><bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>

3、在 spring 配置文件中配置切入點(diǎn)

<!--配置aop增強(qiáng)--><aop:config><!--切入點(diǎn)--><aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/><!--配置切面--><aop:aspect ref="bookProxy"><!--增強(qiáng)作用在具體的方法上--><aop:before method="before" pointcut-ref="p"/></aop:aspect></aop:config>
http://www.risenshineclean.com/news/22074.html

相關(guān)文章:

  • 58同城鹽城網(wǎng)站建設(shè)東莞網(wǎng)站排名提升
  • 怎樣給網(wǎng)站做軟件測(cè)試營(yíng)銷型網(wǎng)站建設(shè)哪家好
  • 企業(yè)網(wǎng)站管理系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)網(wǎng)絡(luò)營(yíng)銷與直播電商專業(yè)學(xué)什么
  • 蕪湖網(wǎng)站開發(fā)小程序怎么引流推廣
  • 武漢眼前一亮科技內(nèi)蒙古seo
  • wordpress 全站不刷新百度識(shí)圖入口
  • 賣建材的網(wǎng)站找seo外包公司需要注意什么
  • 前端手機(jī)網(wǎng)站seo定義
  • 凡科網(wǎng)的網(wǎng)站建設(shè)怎么做百度百家自媒體平臺(tái)注冊(cè)
  • 新媒體seo培訓(xùn)seo研究中心南寧線下
  • 昆明快速做網(wǎng)站海南網(wǎng)站制作
  • 網(wǎng)站服務(wù)器租用價(jià)格表怎么從網(wǎng)上找國(guó)外客戶
  • 藍(lán)色網(wǎng)站素材搜索引擎推廣案例
  • 企業(yè)logo設(shè)計(jì)app搜狗seo怎么做
  • 做淘寶要用到哪些網(wǎng)站中國(guó)優(yōu)化網(wǎng)
  • asp網(wǎng)站圖片怎樣建立自己網(wǎng)站
  • 神州順利辦深一做網(wǎng)站百度搜索排行seo
  • 網(wǎng)絡(luò)營(yíng)銷資訊網(wǎng)站重慶網(wǎng)站推廣聯(lián)系方式
  • 網(wǎng)站怎么做白色字蘇州吳中區(qū)seo關(guān)鍵詞優(yōu)化排名
  • 網(wǎng)站怎樣做seo成功營(yíng)銷案例分享
  • 昆明網(wǎng)站做項(xiàng)目推廣平臺(tái)有哪些
  • 新手站長(zhǎng)如何購(gòu)買虛擬主機(jī)做網(wǎng)站seo對(duì)各類網(wǎng)站的作用
  • 哪個(gè)網(wǎng)站可以懸賞做圖宣傳推廣的十種方式
  • 國(guó)內(nèi)環(huán)保行業(yè)網(wǎng)站開發(fā)seo獨(dú)立站
  • 自己做的網(wǎng)站主頁(yè)打開速度上海百度分公司電話
  • 裝飾裝修網(wǎng)站建設(shè)方案做網(wǎng)絡(luò)銷售如何找客戶
  • crm辦公系統(tǒng)武漢關(guān)鍵詞seo
  • 建設(shè)網(wǎng)站學(xué)什么條件網(wǎng)站運(yùn)營(yíng)和維護(hù)
  • 無法訪問WordPress二級(jí)馮耀宗seo
  • 那家專門做特賣的網(wǎng)站權(quán)威seo技術(shù)