最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一篇文章帶你詳解Spring的AOP

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

1、AOP 什么?

AOP(Aspect Oriented Programming),通常稱為面向切面編程。它利用一種稱為"橫切"的技術(shù),剖解開封裝的對象內(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)對 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();       
    }
}

測試:

@Test
    public void testOne(){
        MyTransaction transaction = new MyTransaction();
        UserService userService = new UserServiceImpl();
        //產(chǎn)生靜態(tài)代理對象
        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):

①、代理對象的一個(gè)接口只服務(wù)于一種類型的對象,如果要代理的方法很多,勢必要為每一種方法都進(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;
    }
}

測試:

@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)給我們生成代理對象。而且將 UserService 換成別的類也是可以的。

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

注意:我們這里使用的是 JDK 動(dòng)態(tài)代理,要求是必須要實(shí)現(xiàn)接口。與之對應(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)對象target來創(chuàng)建新的代理對象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)對象獲得具體方法
            <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 的值要和 對應(yīng)切面的類方法名稱相同 -->
            <aop:before method="before" pointcut-ref="myPointCut"></aop:before>
            <aop:after-returning method="after" pointcut-ref="myPointCut"/>
        </aop:aspect>
    </aop:config>
</beans>

測試:

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

結(jié)果:

上面的配置我們在注釋中寫的很清楚了。這里我們重點(diǎn)講解一下:

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

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

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

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

②、springAOP的具體加載步驟:

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

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

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

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

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

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

總結(jié)

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

相關(guān)文章

  • springmvc 分頁查詢的簡單實(shí)現(xiàn)示例代碼

    springmvc 分頁查詢的簡單實(shí)現(xiàn)示例代碼

    我們在開發(fā)項(xiàng)目中很多項(xiàng)目都用到列表分頁功能,本篇介紹了springmvc 分頁查詢的簡單實(shí)現(xiàn)示例代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。
    2017-01-01
  • 利用java實(shí)現(xiàn)中獎(jiǎng)概率詳情

    利用java實(shí)現(xiàn)中獎(jiǎng)概率詳情

    這篇文章主要介紹了利用java實(shí)現(xiàn)中獎(jiǎng)概率詳情,根據(jù)概率將獎(jiǎng)品劃分區(qū)間,每個(gè)區(qū)間代表一個(gè)獎(jiǎng)品,然后抽取???隨機(jī)數(shù)??,反查落在那個(gè)區(qū)間上,即為所抽取的獎(jiǎng)品,需要的朋友可以參考一下
    2022-07-07
  • java微信紅包實(shí)現(xiàn)算法

    java微信紅包實(shí)現(xiàn)算法

    這篇文章主要為大家詳細(xì)介紹了java微信紅包實(shí)現(xiàn)算法,列出紅包的核心算法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • SpringBoot如何使用MyBatis-Plus實(shí)現(xiàn)高效的數(shù)據(jù)訪問層

    SpringBoot如何使用MyBatis-Plus實(shí)現(xiàn)高效的數(shù)據(jù)訪問層

    在開發(fā) Spring Boot 應(yīng)用時(shí),數(shù)據(jù)訪問是不可或缺的部分,本文將詳細(xì)介紹如何在 Spring Boot 中使用 MyBatis-Plus,并結(jié)合具體代碼示例來講解它的使用方法和常見配置,希望對大家有一定的幫助
    2025-04-04
  • 改變JAVA窗體屬性的操作方法

    改變JAVA窗體屬性的操作方法

    在本篇內(nèi)容里小編給大家詳細(xì)分析了關(guān)于改變JAVA窗體屬性的操作方法和步驟,需要的朋友們學(xué)習(xí)下。
    2018-12-12
  • 淺談使用setBounds()方法需要注意的地方

    淺談使用setBounds()方法需要注意的地方

    下面小編就為大家?guī)硪黄獪\談使用setBounds()方法需要注意的地方。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • VS?Code中運(yùn)行Java?SpringBoot的項(xiàng)目詳細(xì)步驟

    VS?Code中運(yùn)行Java?SpringBoot的項(xiàng)目詳細(xì)步驟

    這篇文章主要介紹了VS?Code中運(yùn)行Java?SpringBoot項(xiàng)目的相關(guān)資料,文中涵蓋了安裝必要的擴(kuò)展、配置環(huán)境、創(chuàng)建或?qū)腠?xiàng)目、配置調(diào)試環(huán)境、運(yùn)行和調(diào)試項(xiàng)目、使用Spring?Boot?Actuator以及配置任務(wù)自動(dòng)化等步驟,需要的朋友可以參考下
    2024-12-12
  • 介紹下Java Spring的核心接口,容器中Bean的實(shí)例化

    介紹下Java Spring的核心接口,容器中Bean的實(shí)例化

    這篇文章主要介紹了Spring核心接口,容器中bean的實(shí)例化過程解析及完整代碼示例,簡單分析實(shí)例化bean過程并且分享了相關(guān)實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • springsecurity輕松實(shí)現(xiàn)角色權(quán)限的示例代碼

    springsecurity輕松實(shí)現(xiàn)角色權(quán)限的示例代碼

    這篇文章主要介紹了springsecurity輕松實(shí)現(xiàn)角色權(quán)限的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Lombok 的@StandardException注解解析

    Lombok 的@StandardException注解解析

    @StandardException 是一個(gè)實(shí)驗(yàn)性的注解,添加到 Project Lombok 的 v__1.18.22 版本中,在本教程中,我們將使用 Lombok 的 @StandardException 注解自動(dòng)生成異常類型類的構(gòu)造函數(shù),需要的朋友可以參考下
    2023-05-05

最新評論

合江县| 隆子县| 定州市| 龙南县| 隆安县| 花莲市| 固始县| 璧山县| 谢通门县| 美姑县| 织金县| 松潘县| 娄底市| 讷河市| 泽库县| 南江县| 黄山市| 客服| 乐至县| 枞阳县| 斗六市| 永顺县| 扎鲁特旗| 应用必备| 岑巩县| 利辛县| 融水| 惠州市| 江北区| 柳江县| 阿合奇县| 鄯善县| 津市市| 绥棱县| 安丘市| 武威市| 安溪县| 长宁县| 宜兰市| 稷山县| 定远县|