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

一篇文章帶你詳解Spring的AOP

 更新時(shí)間:2022年01月20日 10:31:32   作者:YSOcean  
這篇文章主要為大家介紹了Spring的AOP,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

1、AOP 什么?

AOP(Aspect Oriented Programming),通常稱為面向切面編程。它利用一種稱為"橫切"的技術(shù),剖解開封裝的對(duì)象內(nèi)部,并將那些影響了多個(gè)類的公共行為封裝到一個(gè)可重用模塊,并將其命名為"Aspect",即切面。所謂"切面",簡單說就是那些與業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝起來,便于減少系統(tǒng)的重復(fù)代碼,降低模塊之間的耦合度,并有利于未來的可操作性和可維護(hù)性。

什么是切面,什么是公共模塊,那么我們概念少說,直接通過一個(gè)實(shí)例來看看 AOP 到底是什么。

2、需求

現(xiàn)在有一張表 User,然后我們要在程序中實(shí)現(xiàn)對(duì) User表的增加和刪除操作。

要求:增加和刪除操作都必須要開啟事務(wù),操作完成之后要提交事務(wù)。

User.java

package com.ys.aop.one;
public class User {
    private int uid;
    private String uname;
    public int getUid() {
        return uid;
    }
    public void setUid(int uid) {
        this.uid = uid;
    }
    public String getUname() {
        return uname;
    }
    public void setUname(String uname) {
        this.uname = uname;
    }
}

3、解決辦法1:使用靜態(tài)代理

第一步:創(chuàng)建 UserService 接口

package com.ys.aop.one;
public interface UserService {
    //添加 user
    public void addUser(User user);
    //刪除 user
    public void deleteUser(int uid);
}

第二步:創(chuàng)建 UserService的實(shí)現(xiàn)類

package com.ys.aop.one;
public class UserServiceImpl implements UserService{
    @Override
    public void addUser(User user) {
        System.out.println("增加 User");
    }
    @Override
    public void deleteUser(int uid) {
        System.out.println("刪除 User");
    }
}

第三步:創(chuàng)建事務(wù)類 MyTransaction

package com.ys.aop.one;
public class MyTransaction {
    //開啟事務(wù)
    public void before(){
        System.out.println("開啟事務(wù)");
    }
    //提交事務(wù)
    public void after(){
        System.out.println("提交事務(wù)");
    }
}

第四步:創(chuàng)建代理類 ProxyUser.java

package com.ys.aop.one;
public class ProxyUser implements UserService{
    //真實(shí)類
    private UserService userService;
    //事務(wù)類
    private MyTransaction transaction;
    //使用構(gòu)造函數(shù)實(shí)例化
    public ProxyUser(UserService userService,MyTransaction transaction){
        this.userService = userService;
        this.transaction = transaction;
    }
    @Override
    public void addUser(User user) {
        transaction.before();
        userService.addUser(user);
        transaction.after();
    }
    @Override
    public void deleteUser(int uid) {
        transaction.before();
        userService.deleteUser(uid);
        transaction.after();       
    }
}

測(cè)試:

@Test
    public void testOne(){
        MyTransaction transaction = new MyTransaction();
        UserService userService = new UserServiceImpl();
        //產(chǎn)生靜態(tài)代理對(duì)象
        ProxyUser proxy = new ProxyUser(userService, transaction);
        proxy.addUser(null);
        proxy.deleteUser(0);
    }

結(jié)果:

這是一個(gè)很基礎(chǔ)的靜態(tài)代理,業(yè)務(wù)類UserServiceImpl 只需要關(guān)注業(yè)務(wù)邏輯本身,保證了業(yè)務(wù)的重用性,這也是代理類的優(yōu)點(diǎn),沒什么好說的。我們主要說說這樣寫的缺點(diǎn):

①、代理對(duì)象的一個(gè)接口只服務(wù)于一種類型的對(duì)象,如果要代理的方法很多,勢(shì)必要為每一種方法都進(jìn)行代理,靜態(tài)代理在程序規(guī)模稍大時(shí)就無法勝任了。

②、如果接口增加一個(gè)方法,比如 UserService 增加修改 updateUser()方法,則除了所有實(shí)現(xiàn)類需要實(shí)現(xiàn)這個(gè)方法外,所有代理類也需要實(shí)現(xiàn)此方法。增加了代碼維護(hù)的復(fù)雜度。

4、解決辦法2:使用JDK動(dòng)態(tài)代理

動(dòng)態(tài)代理就不要自己手動(dòng)生成代理類了,我們?nèi)サ?ProxyUser.java 類,增加一個(gè)ObjectInterceptor.java

package com.ys.aop.two;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.ys.aop.one.MyTransaction;
public class ObjectInterceptor implements InvocationHandler{
    //目標(biāo)類
    private Object target;
    //切面類(這里指事務(wù)類)
    private MyTransaction transaction;
    //通過構(gòu)造器賦值
    public ObjectInterceptor(Object target,MyTransaction transaction){
        this.target = target;
        this.transaction = transaction;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //開啟事務(wù)
        this.transaction.before();
        //調(diào)用目標(biāo)類方法
        method.invoke(this.target, args);
        //提交事務(wù)
        this.transaction.after();
        return null;
    }
}

測(cè)試:

@Test
    public void testOne(){
        //目標(biāo)類
        Object target = new UserServiceImpl();
        //事務(wù)類
        MyTransaction transaction = new MyTransaction();
        ObjectInterceptor proxyObject = new ObjectInterceptor(target, transaction);
        /**
         * 三個(gè)參數(shù)的含義:
         * 1、目標(biāo)類的類加載器
         * 2、目標(biāo)類所有實(shí)現(xiàn)的接口
         * 3、攔截器
         */
        UserService userService = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), proxyObject);
        userService.addUser(null);
    }

結(jié)果:

那么使用動(dòng)態(tài)代理來完成這個(gè)需求就很好了,后期在 UserService 中增加業(yè)務(wù)方法,都不用更改代碼就能自動(dòng)給我們生成代理對(duì)象。而且將 UserService 換成別的類也是可以的。

也就是做到了代理對(duì)象能夠代理多個(gè)目標(biāo)類,多個(gè)目標(biāo)方法。

注意:我們這里使用的是 JDK 動(dòng)態(tài)代理,要求是必須要實(shí)現(xiàn)接口。與之對(duì)應(yīng)的另外一種動(dòng)態(tài)代理實(shí)現(xiàn)模式 Cglib,則不需要,我們這里就不講解 cglib 的實(shí)現(xiàn)方式了。

不管是哪種方式實(shí)現(xiàn)動(dòng)態(tài)代理。本章的主角:AOP 實(shí)現(xiàn)原理也是動(dòng)態(tài)代理

5、AOP 關(guān)鍵術(shù)語 

1.target:目標(biāo)類,需要被代理的類。例如:UserService

2.Joinpoint(連接點(diǎn)):所謂連接點(diǎn)是指那些可能被攔截到的方法。例如:所有的方法

3.PointCut 切入點(diǎn):已經(jīng)被增強(qiáng)的連接點(diǎn)。例如:addUser()

4.advice 通知/增強(qiáng),增強(qiáng)代碼。例如:after、before

5. Weaving(織入):是指把增強(qiáng)advice應(yīng)用到目標(biāo)對(duì)象target來創(chuàng)建新的代理對(duì)象proxy的過程.

6.proxy 代理類:通知+切入點(diǎn)

7. Aspect(切面): 是切入點(diǎn)pointcut和通知advice的結(jié)合

具體可以根據(jù)下面這張圖來理解:

6、AOP 的通知類型  

Spring按照通知Advice在目標(biāo)類方法的連接點(diǎn)位置,可以分為5類

  • 前置通知 org.springframework.aop.MethodBeforeAdvice
    • 在目標(biāo)方法執(zhí)行前實(shí)施增強(qiáng),比如上面例子的 before()方法
  • 后置通知 org.springframework.aop.AfterReturningAdvice
    • 在目標(biāo)方法執(zhí)行后實(shí)施增強(qiáng),比如上面例子的 after()方法
  • 環(huán)繞通知org.aopalliance.intercept.MethodInterceptor
    • 在目標(biāo)方法執(zhí)行前后實(shí)施增強(qiáng)
  • 異常拋出通知 org.springframework.aop.ThrowsAdvice
    • 在方法拋出異常后實(shí)施增強(qiáng)
  • 引介通知 org.springframework.aop.IntroductionInterceptor
    • 在目標(biāo)類中添加一些新的方法和屬性

7、使用 Spring AOP 解決上面的需求

我們只需要在Spring 的配置文件 applicationContext.xml 進(jìn)行如下配置:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--1、 創(chuàng)建目標(biāo)類 -->
    <bean id="userService" class="com.ys.aop.UserServiceImpl"></bean>  
    <!--2、創(chuàng)建切面類(通知)  -->
    <bean id="transaction" class="com.ys.aop.one.MyTransaction"></bean>
    <!--3、aop編程 
        3.1 導(dǎo)入命名空間
        3.2 使用 <aop:config>進(jìn)行配置
                proxy-target-class="true" 聲明時(shí)使用cglib代理
                如果不聲明,Spring 會(huì)自動(dòng)選擇cglib代理還是JDK動(dòng)態(tài)代理
            <aop:pointcut> 切入點(diǎn) ,從目標(biāo)對(duì)象獲得具體方法
            <aop:advisor> 特殊的切面,只有一個(gè)通知 和 一個(gè)切入點(diǎn)
                advice-ref 通知引用
                pointcut-ref 切入點(diǎn)引用
        3.3 切入點(diǎn)表達(dá)式
            execution(* com.ys.aop.*.*(..))
            選擇方法         返回值任意   包             類名任意   方法名任意   參數(shù)任意
    -->
    <aop:config>
        <!-- 切入點(diǎn)表達(dá)式 -->
        <aop:pointcut expression="execution(* com.ys.aop.*.*(..))" id="myPointCut"/>
        <aop:aspect ref="transaction">
            <!-- 配置前置通知,注意 method 的值要和 對(duì)應(yīng)切面的類方法名稱相同 -->
            <aop:before method="before" pointcut-ref="myPointCut"></aop:before>
            <aop:after-returning method="after" pointcut-ref="myPointCut"/>
        </aop:aspect>
    </aop:config>
</beans>

測(cè)試:

@Test
    public void testAop(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService useService = (UserService) context.getBean("userService");
        useService.addUser(null);
    }

結(jié)果:

上面的配置我們?cè)谧⑨屩袑懙暮芮宄?。這里我們重點(diǎn)講解一下:

①、切入點(diǎn)表達(dá)式,一個(gè)完整的方法表示如下:

execution(modifiers-pattern? ref-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
             類修飾符           返回值           方法所在的包                  方法名                     方法拋出的異常

那么根據(jù)上面的對(duì)比,我們就很好理解:

execution(* com.ys.aop.*.*(..))
選擇方法         返回值任意   包             類名任意   方法名任意   參數(shù)任意

②、springAOP的具體加載步驟:

1、當(dāng)spring容器啟動(dòng)的時(shí)候,加載了spring的配置文件

2、為配置文件中的所有bean創(chuàng)建對(duì)象

3、spring容器會(huì)解析aop:config的配置

1、解析切入點(diǎn)表達(dá)式,用切入點(diǎn)表達(dá)式和納入spring容器中的bean做匹配,如果匹配成功,則會(huì)為該bean創(chuàng)建代理對(duì)象,代理對(duì)象的方法=目標(biāo)方法+通知,如果匹配不成功,不會(huì)創(chuàng)建代理對(duì)象

4、在客戶端利用context.getBean()獲取對(duì)象時(shí),如果該對(duì)象有代理對(duì)象,則返回代理對(duì)象;如果沒有,則返回目標(biāo)對(duì)象

說明:如果目標(biāo)類沒有實(shí)現(xiàn)接口,則spring容器會(huì)采用cglib的方式產(chǎn)生代理對(duì)象,如果實(shí)現(xiàn)了接口,則會(huì)采用jdk的方式

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • 通過代碼理解java泛型

    通過代碼理解java泛型

    本篇文章通過代碼實(shí)例讓大家充分的理解java泛型的相關(guān)知識(shí)點(diǎn)內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。
    2018-08-08
  • Java中CyclicBarrier的理解與應(yīng)用詳解

    Java中CyclicBarrier的理解與應(yīng)用詳解

    這篇文章主要介紹了Java中CyclicBarrier的理解與應(yīng)用詳解,CyclicBarrier類是JUC框架中的工具類,也是一個(gè)同步輔助裝置:允許多個(gè)線程去等待直到全部線程抵達(dá)了公共的柵欄點(diǎn),需要的朋友可以參考下
    2023-12-12
  • 每日六道java新手入門面試題,通往自由的道路--JVM

    每日六道java新手入門面試題,通往自由的道路--JVM

    這篇文章主要為大家分享了最有價(jià)值的6道JVM面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,對(duì)hashCode方法的設(shè)計(jì)、垃圾收集的堆和代進(jìn)行剖析,感興趣的小伙伴們可以參考一下
    2021-06-06
  • 基于Cookie與Session的Servlet?API會(huì)話管理操作

    基于Cookie與Session的Servlet?API會(huì)話管理操作

    這篇文章主要為大家介紹了基于Cookie與Session的Servlet?API會(huì)話管理操作詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 解決SpringBoot跨域的三種方式

    解決SpringBoot跨域的三種方式

    前后端分離是目前的趨勢(shì),解決跨域問題也是老生常談的話題了,我們了解一下什么是域和跨域。域:協(xié)議 + 域名 + 端口;三者完全相同則為同域,反之有其一不同均為不同域。跨域請(qǐng)求:當(dāng)前【發(fā)起請(qǐng)求】的域和【請(qǐng)求指向】的域?qū)儆诓煌驎r(shí),該次請(qǐng)求稱之為跨域請(qǐng)求
    2021-06-06
  • Spring?Cloud?Gateway編碼實(shí)現(xiàn)任意地址跳轉(zhuǎn)

    Spring?Cloud?Gateway編碼實(shí)現(xiàn)任意地址跳轉(zhuǎn)

    這篇文章主要介紹了Spring?Cloud?Gateway編碼實(shí)現(xiàn)任意地址跳轉(zhuǎn)的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • Java Spring JdbcTemplate基本使用詳解

    Java Spring JdbcTemplate基本使用詳解

    JDBC已經(jīng)能夠滿足大部分用戶最基本的需求,但是在使用JDBC時(shí),必須自己來管理數(shù)據(jù)庫資源如:獲取PreparedStatement,設(shè)置SQL語句參數(shù),關(guān)閉連接等步驟
    2021-10-10
  • 淺談Springboot整合RocketMQ使用心得

    淺談Springboot整合RocketMQ使用心得

    本篇文章主要介紹了Springboot整合RocketMQ使用心得,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • Java中的參數(shù)傳遞詳細(xì)介紹

    Java中的參數(shù)傳遞詳細(xì)介紹

    大家好,本篇文章主要講的是Java中的參數(shù)傳遞詳解,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • Java數(shù)據(jù)結(jié)構(gòu)之優(yōu)先級(jí)隊(duì)列(PriorityQueue)用法詳解

    Java數(shù)據(jù)結(jié)構(gòu)之優(yōu)先級(jí)隊(duì)列(PriorityQueue)用法詳解

    優(yōu)先級(jí)隊(duì)列是一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu),操作的數(shù)據(jù)帶有優(yōu)先級(jí),這種數(shù)據(jù)結(jié)構(gòu)就是優(yōu)先級(jí)隊(duì)列(PriorityQueue)。本文將詳細(xì)講講Java優(yōu)先級(jí)隊(duì)列的用法,感興趣的可以了解一下
    2022-07-07

最新評(píng)論