欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring超詳細(xì)講解面向?qū)ο蟮矫嫦蚯忻?/h1>
 更新時間:2022年08月03日 15:49:57   作者:懶羊羊.java  
面向?qū)ο缶幊淌且环N編程方式,此編程方式的落地需要使用“類”和 “對象”來實現(xiàn),所以,面向?qū)ο缶幊唐鋵嵕褪菍?nbsp;“類”和“對象” 的使用,面向切面編程,簡單的說,就是動態(tài)地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程

前言

Object object = new Object();

世間萬物的本質(zhì)都可看作類的對象,面向?qū)ο?OOP)的模式讓程序易維護(hù)、易復(fù)用、易擴(kuò)展,而面向切面(AOP)則是面向?qū)ο蟮难a充,讓對象的功能更加強大

對比前面的日志框架技術(shù)二者非常相似,他的特點就是在不影響業(yè)務(wù)的前提下將程序的運行情況輸出到控制臺,總體來看是起一個輔助的作用,所謂的AOP亦是如此——是在不改原有代碼的前提下對其進(jìn)行增強

一.OOP&AOP

OOP將組件視為對象,AOP將對象的切面視為“對象”

OOP&AOP讓程序通過極其簡單的方式變得更加全面、強大

AOP(Aspect Oriented Programming)面向切面編程、OOP(Object Oriented Programming)面向?qū)ο缶幊?/p>

OOP是一種編程思想,AOP也是一種編程思想,編程思想主要的內(nèi)容就是指導(dǎo)程序員該如何編寫程序,兩者都是不同的編程范式各有特色

二.AOP核心

通過以下一個計算程序運行時間的功能,引出AOP相關(guān)概念

@Repository
public class AImpl implements A {
    public void save() {
        //記錄程序當(dāng)前執(zhí)行執(zhí)行(開始時間)
        Long startTime = System.currentTimeMillis();
        //業(yè)務(wù)執(zhí)行萬次
        for (int i = 0;i<10000;i++) {
            System.out.println("START ...");
        }
        //記錄程序當(dāng)前執(zhí)行時間(結(jié)束時間)
        Long endTime = System.currentTimeMillis();
        //計算時間差
        Long totalTime = endTime-startTime;
        //輸出信息
        System.out.println("執(zhí)行萬次程序消耗時間:" + totalTime + "ms");
    }
    public void m1(){ System.out.println(" m1 ..."); }
    public void m2(){ System.out.println(" m2 ..."); }
}

(1)save,m1m2方法,這些方法我們給起了一個名字叫連接點

(2)對于需要增強的方法我們給起了一個名字叫切入點

(3)將功能抽取到一個方法中,換句話說就是存放共性功能的方法,我們給起了個名字叫通知

(4)通知是要增強的內(nèi)容,會有多個,切入點是需要被增強的方法,也會有多個,那哪個切入點需要添加哪個通知,就需要提前將它們之間的關(guān)系描述清楚,那么對于通知和切入點之間的關(guān)系描述,我們給起了個名字叫切面

(5)通知是一個方法,方法不能獨立存在需要被寫在一個類中,這個類我們也給起了個名字叫通知類

三.第一個AOP案例

1.環(huán)境準(zhǔn)備

  • 創(chuàng)建一個Maven項目
  • pom.xml添加Spring依賴spring-context
  • 添加A和AImpl類
public interface A {
    public void save();
    public void m1();
}
@Repository
public class AImpl implements A {
    public void save() {
        System.out.println(System.currentTimeMillis());
        System.out.println("book dao save ...");
    }
    public void m1(){
        System.out.println("book dao m1 ...");
    }
}

創(chuàng)建Spring的配置類

@Configuration
@ComponentScan("yu7daily")
public class Config {
}

編寫Show運行類

public class Show {
    public static void main(String[] args) {
        ShowlicationContext ctx = new AnnotationConfigShowlicationContext(Config.class);
        A A = ctx.getBean(A.class);
        A.save();
    }
}

2.AOP實現(xiàn)步驟

1.@EnableAspectJAutoProxy 開啟注解格式AOP功能

2.@Aspect設(shè)置當(dāng)前類為AOP切面類

3.@Pointcut 設(shè)置切入點方法

4.@Before設(shè)置當(dāng)前通知方法與切入點之間的綁定關(guān)系,當(dāng)前通知方法在原始切入點方法前運行

**1.添加依賴

pom.xml

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

因為spring-context中已經(jīng)導(dǎo)入了spring-aop,所以不需要再單獨導(dǎo)入spring-aop.

導(dǎo)入AspectJ的jar包,AspectJ是AOP思想的一個具體實現(xiàn),Spring有自己的AOP實現(xiàn),但是相比于AspectJ來說比較麻煩,所以我們直接采用Spring整合ApsectJ的方式進(jìn)行AOP開發(fā)。

2.定義接口與實現(xiàn)類:環(huán)境準(zhǔn)備的時候,AImpl已經(jīng)準(zhǔn)備好,不需要做任何修改

3.定義通知類和通知

通知就是將共性功能抽取出來后形成的方法,共性功能指的就是當(dāng)前系統(tǒng)時間的打印

public class Test {
    public void method(){
        System.out.println(System.currentTimeMillis());
    }
}

類名和方法名沒有要求,可以任意。

4.定義切入點

AImpl中有兩個方法,分別是save和m1,我們要增強的是m1方法,該如何定義呢?

public class Test {
    @Pointcut("execution(void yu7daily.dao.A.m1())")
    private void po1(){}
    public void method(){
        System.out.println(System.currentTimeMillis());
    }
}

說明:

切入點定義依托一個不具有實際意義的方法進(jìn)行,即無參數(shù)、無返回值、方法體無實際邏輯。

execution及后面編寫的內(nèi)容

5.制作切面

切面是用來描述通知和切入點之間的關(guān)系,如何進(jìn)行關(guān)系的綁定?

public class Test {
    @Pointcut("execution(void yu7daily.dao.A.m1())")
    private void po1(){}
    @Before("po1()")
    public void method(){
        System.out.println(System.currentTimeMillis());
    }
}

綁定切入點與通知關(guān)系,并指定通知添加到原始連接點的具體執(zhí)行位置

說明:@Before翻譯過來是之前,也就是說通知會在切入點方法執(zhí)行之前執(zhí)行,除此之前還有其他四種類型

6.將通知類配給容器并標(biāo)識其為切面類

@Component
@Aspect
public class Test {
    @Pointcut("execution(void yu7daily.dao.A.m1())")
    private void po1(){}
    @Before("po1()")
    public void method(){
        System.out.println(System.currentTimeMillis());
    }
}

7.開啟注解格式AOP功能

@Configuration
@ComponentScan("yu7daily")
@EnableAspectJAutoProxy
public class Config {
}

8.運行程序

public class Show {
    public static void main(String[] args) {
        ShowlicationContext ctx = new AnnotationConfigShowlicationContext(Config.class);
        A A = ctx.getBean(A.class);
        A.m1();
    }
}

看到在執(zhí)行m1方法之前打印了系統(tǒng)時間戳,說明對原始方法進(jìn)行了增強,AOP編程成功!!!

四.切入點表達(dá)式

前面的案例中,有涉及到如下內(nèi)容:

對于AOP中切入點表達(dá)式,我們總共會學(xué)習(xí)三個內(nèi)容,分別是語法格式、通配符和書寫技巧。

1.語法格式

首先我們先要明確兩個概念:

切入點:要進(jìn)行增強的方法

切入點表達(dá)式:要進(jìn)行增強的方法的描述方式

描述方式一:執(zhí)行yu7daily.dao包下的A接口中的無參數(shù)m1方法

execution(void yu7daily.dao.A.m1())

描述方式二:執(zhí)行yu7daily.dao.impl包下的AImpl類中的無參數(shù)m1方法

execution(void yu7daily.dao.impl.AImpl.m1())

因為調(diào)用接口方法的時候最終運行的還是其實現(xiàn)類的方法,所以上面兩種描述方式都是可以的。

對于切入點表達(dá)式的語法為:

切入點表達(dá)式標(biāo)準(zhǔn)格式:動作關(guān)鍵字(訪問修飾符 返回值 包名.類/接口名.方法名(參數(shù)) 異常名)

execution(public User yu7daily.service.UserService.findById(int))

切入點表達(dá)式就是要找到需要增強的方法,所以它就是對一個具體方法的描述,但是方法的定義會有很多,所以如果每一個方法對應(yīng)一個切入點表達(dá)式,極其復(fù)雜可以通過以下方式進(jìn)行簡化

2.通配符

使用通配符描述切入點,主要的目的就是簡化之前的配置

*:單個獨立的任意符號,可以獨立出現(xiàn),也可以作為前綴或者后綴的匹配符出現(xiàn)

execution(public * yu7daily.*.UserService.find*(*))

匹配yu7daily包下的任意包中的UserService類或接口中所有find開頭的帶有一個參數(shù)的方法

..:多個連續(xù)的任意符號,可以獨立出現(xiàn),常用于簡化包名與參數(shù)的書寫

execution(public User com..UserService.findById(..))

匹配com包下的任意包中的UserService類或接口中所有名稱為findById的方法

+:專用于匹配子類類型

execution(* *..*Service+.*(..))

使用切入點表達(dá)式來分析下:

execution(void yu7daily.dao.A.m1())
匹配接口,能匹配到
execution(void yu7daily.dao.impl.AImpl.m1())
匹配實現(xiàn)類,能匹配到
execution(* yu7daily.dao.impl.AImpl.m1())
返回值任意,能匹配到
execution(* yu7daily.dao.impl.AImpl.m1(*))
返回值任意,但是m1方法必須要有一個參數(shù),無法匹配,要想匹配需要在m1接口和實現(xiàn)類添加參數(shù)
execution(void com.*.*.*.*.m1())
返回值為void,com包下的任意包三層包下的任意類的m1方法,匹配到的是實現(xiàn)類,能匹配
execution(void com.*.*.*.m1())
返回值為void,com包下的任意兩層包下的任意類的m1方法,匹配到的是接口,能匹配
execution(void *..m1())
返回值為void,方法名是m1的任意包下的任意類,能匹配
execution(* *..*(..))
匹配項目中任意類的任意方法,能匹配,但是不建議使用這種方式,影響范圍廣
execution(* *..u*(..))
匹配項目中任意包任意類下只要以u開頭的方法,m1方法能滿足,能匹配
execution(* *..*e(..))
匹配項目中任意包任意類下只要以e結(jié)尾的方法,m1和save方法能滿足,能匹配
execution(void com..*())
返回值為void,com包下的任意包任意類任意方法,能匹配,*代表的是方法
execution(* yu7daily.*.*Service.find*(..))
將項目中所有業(yè)務(wù)層方法的以find開頭的方法匹配
execution(* yu7daily.*.*Service.save*(..))
將項目中所有業(yè)務(wù)層方法的以save開頭的方法匹配

五.AOP通知類型

它所代表的含義是將通知添加到切入點方法執(zhí)行的前面。

除了這個注解外,還有沒有其他的注解,換個問題就是除了可以在前面加,能不能在其他的地方加?

(1)前置通知,追加功能到方法執(zhí)行前,類似于在代碼1或者代碼2添加內(nèi)容

(2)后置通知,追加功能到方法執(zhí)行后,不管方法執(zhí)行的過程中有沒有拋出異常都會執(zhí)行,類似于在代碼5添加內(nèi)容

(3)返回后通知,追加功能到方法執(zhí)行后,只有方法正常執(zhí)行結(jié)束后才進(jìn)行,類似于在代碼3添加內(nèi)容,如果方法執(zhí)行拋出異常,返回后通知將不會被添加

(4)拋出異常后通知,追加功能到方法拋出異常后,只有方法執(zhí)行出異常才進(jìn)行,類似于在代碼4添加內(nèi)容,只有方法拋出異常后才會被添加

(5)環(huán)繞通知,環(huán)繞通知功能比較強大,它可以追加功能到方法執(zhí)行的前后,這也是比較常用的方式,它可以實現(xiàn)其他四種通知類型的功能

環(huán)境準(zhǔn)備

1.pom.xml添加Spring依賴spring-context、aspectjweaver

2.添加A和AImpl類

public interface A {
    public void m1();
    public int m2();
}
@Repository
public class AImpl implements A {
    public void m1(){
        System.out.println(" m1 ...");
    }
    public int m2() {
        System.out.println(" m2 is running ...");
        return 1;
    }
}

創(chuàng)建Spring的配置類

@Configuration
@ComponentScan("yu7daily")
@EnableAspectJAutoProxy
public class Config {
}

創(chuàng)建通知類

@Component
@Aspect
public class Test {
    @Pointcut("execution(void yu7daily.dao.A.m1())")
    private void po1(){}
    public void around(){
        System.out.println("around before advice ...");
        System.out.println("around after advice ...");
    }
}

編寫Show運行類

public class Show {
    public static void main(String[] args) {
        ShowlicationContext ctx = new AnnotationConfigShowlicationContext(Config.class);
        A A = ctx.getBean(A.class);
        A.m1();
    }
}

環(huán)繞通知

(1)原始方法有返回值的處理

修改Test,對A中的m2方法添加環(huán)繞通知,

@Component
@Aspect
public class Test {
    @Pointcut("execution(void yu7daily.dao.A.m1())")
    private void po1(){}
    @Pointcut("execution(int yu7daily.dao.A.m2())")
    private void po2(){}
    @Around("po2()")
    public void aroundM2(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before advice ...");
        //表示對原始操作的調(diào)用
        pjp.proceed();
        System.out.println("around after advice ...");
    }
}

修改Show類,調(diào)用m2方法

@Component
@Aspect
public class Test {
    @Pointcut("execution(void yu7daily.dao.A.m1())")
    private void po1(){}
    @Pointcut("execution(int yu7daily.dao.A.m2())")
    private void po2(){}
    @Around("po2()")
    public Object aroundM2(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before advice ...");
        //表示對原始操作的調(diào)用
        Object ret = pjp.proceed();
        System.out.println("around after advice ...");
        return ret;
    }
}

說明:

返回的是Object而不是int的主要原因是Object類型更通用隨時可以轉(zhuǎn)型

在環(huán)繞通知中是可以對原始方法返回值就行修改的

1.返回后通知

@Component
@Aspect
public class Test {
    @Pointcut("execution(void yu7daily.dao.A.m1())")
    private void po1(){}
    @Pointcut("execution(int yu7daily.dao.A.m2())")
    private void po2(){}
    @AfterReturning("po2()")
    public void afterReturning() {
        System.out.println("afterReturning advice ...");
    }
}

注意:返回后通知是需要在原始方法m2正常執(zhí)行后才會被執(zhí)行,如果m2()方法執(zhí)行的過程中出現(xiàn)了異常,那么返回后通知是不會被執(zhí)行。后置通知則是不管原始方法有沒有拋出異常都會被執(zhí)行

2.異常后通知

@Component
@Aspect
public class Test {
    @Pointcut("execution(void yu7daily.dao.A.m1())")
    private void po1(){}
    @Pointcut("execution(int yu7daily.dao.A.m2())")
    private void po2(){}
    @AfterReturning("po2()")
    public void afterThrowing() {
        System.out.println("afterThrowing advice ...");
    }
}

環(huán)繞通知注意事項

1. 環(huán)繞通知必須依賴形參ProceedingJoinPoint才能實現(xiàn)對原始方法的調(diào)用,進(jìn)而實現(xiàn)原始方法調(diào)用前后同時添加通知

2. 通知中如果未使用ProceedingJoinPoint對原始方法進(jìn)行調(diào)用將跳過原始方法的執(zhí)行

3. 對原始方法的調(diào)用可以不接收返回值,通知方法設(shè)置成void即可,如果接收返回值,最好設(shè)定為Object類型

4. 原始方法的返回值如果是void類型,通知方法的返回值類型可以設(shè)置成void,也可以設(shè)置成Object

5. 由于無法預(yù)知原始方法運行后是否會拋出異常,因此環(huán)繞通知方法必須要處理Throwable異常

到此這篇關(guān)于Spring超詳細(xì)講解面向?qū)ο蟮矫嫦蚯忻娴奈恼戮徒榻B到這了,更多相關(guān)Spring面向?qū)ο髢?nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • spring boot 加載web容器tomcat流程源碼分析

    spring boot 加載web容器tomcat流程源碼分析

    本文章主要描述spring boot加載web容器 tomcat的部分,為了避免文章知識點過于分散,其他相關(guān)的如bean的加載,tomcat內(nèi)部流程等不做深入討論,具體內(nèi)容詳情跟隨小編一起看看吧
    2021-06-06
  • 源碼分析ConcurrentHashMap如何保證線程安全

    源碼分析ConcurrentHashMap如何保證線程安全

    這篇文章將結(jié)合底層源碼為大家詳細(xì)介紹一下ConcurrentHashMap是如何保證線程安全的,文中是示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-06-06
  • C/C++和Java的交互詳解

    C/C++和Java的交互詳解

    本文旨在簡單的介紹一下如何讓java層和C/C++層相互調(diào)用,這里主要是使用了JNI技術(shù),并沒有深究其原理,只是做了個實現(xiàn),其目的是為后面的學(xué)習(xí)打開一扇窗。
    2016-01-01
  • springboot2整合redis使用lettuce連接池的方法(解決lettuce連接池?zé)o效問題)

    springboot2整合redis使用lettuce連接池的方法(解決lettuce連接池?zé)o效問題)

    這篇文章主要介紹了springboot2整合redis使用lettuce連接池(解決lettuce連接池?zé)o效問題),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • Java-Java5.0注解全面解讀

    Java-Java5.0注解全面解讀

    這篇文章主要介紹了Java-Java5.0注解全面解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java Agents代理是什么

    Java Agents代理是什么

    Java代理Agents通過提供使我們能夠侵入JVM中正在運行的Java程序的服務(wù),在最底層工作。Java的這一強大但不可思議的部分具有在錯誤操作時使JVM崩潰的能力。本文簡要介紹了這個概念,并介紹了它的工作原理。需要的朋友可以參考下面文章的具體內(nèi)容
    2021-09-09
  • Java經(jīng)典排序算法之插入排序

    Java經(jīng)典排序算法之插入排序

    這篇文章主要為大家詳細(xì)介紹了Java經(jīng)典排序算法之插入排序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • java  多線程的三種構(gòu)建方法

    java 多線程的三種構(gòu)建方法

    這篇文章主要介紹了java 多線程的三種構(gòu)建方法的相關(guān)資料,這里提供三種實現(xiàn)方法,希望大家能夠掌握,很重要的基礎(chǔ)知識,需要的朋友可以參考下
    2017-09-09
  • Java設(shè)計模式七大原則之里氏替換原則詳解

    Java設(shè)計模式七大原則之里氏替換原則詳解

    在面向?qū)ο蟮某绦蛟O(shè)計中,里氏替換原則(Liskov Substitution principle)是對子類型的特別定義。本文將為大家詳細(xì)介紹Java設(shè)計模式七大原則之一的里氏替換原則,需要的可以參考一下
    2022-02-02
  • SpringBoot中整合消息服務(wù)組件的方法

    SpringBoot中整合消息服務(wù)組件的方法

    本文介紹了消息服務(wù)組件的基本概念,以及如何在SpringBoot中整合常見的消息服務(wù)組件,如ActiveMQ、RabbitMQ和Kafka,我們探討整合消息服務(wù)組件在實際應(yīng)用場景中的優(yōu)勢,感興趣的朋友跟隨小編一起看看吧
    2023-07-07

最新評論