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

詳談Spring是否支持對(duì)靜態(tài)方法進(jìn)行Aop增強(qiáng)

 更新時(shí)間:2021年12月23日 17:27:44   作者:javartisan  
這篇文章主要介紹了Spring是否支持對(duì)靜態(tài)方法進(jìn)行Aop增強(qiáng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Spring Aop是否對(duì)靜態(tài)方法進(jìn)行代理?不著急看結(jié)論,看完實(shí)現(xiàn)也就明白了細(xì)節(jié)。

1、JDK代理

JDK代理代碼:

 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Echor {
    public void echo();
} 
 
class EchorImpl implements Echor { 
    @Override
    public void echo() {
        System.out.println("echo ~");
    }
}
 
class MethodInvoker<T> implements InvocationHandler { 
    private T invoker; 
    public MethodInvoker(T invoker) {
        this.invoker = invoker;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 
        System.out.println("start ~");
        Object result = method.invoke(invoker, args);
        System.out.println("end ~");
        return result;
    }
}
 
public class DebugJdkProxy { 
    public static void main(String[] args) {
        Echor proxy = (Echor) Proxy.newProxyInstance(DebugJdkProxy.class.getClassLoader(), new Class[]{Echor.class}, new MethodInvoker<Echor>(new EchorImpl()));
        proxy.echo();
    } 
}

JVM實(shí)現(xiàn)代理類(lèi)比較重要的類(lèi)sun.misc.ProxyGenerator,生成代理類(lèi)的方法為generateClassFile源碼:

private byte[] generateClassFile() {
        this.addProxyMethod(hashCodeMethod, Object.class);
        this.addProxyMethod(equalsMethod, Object.class);
        this.addProxyMethod(toStringMethod, Object.class);
        Class[] var1 = this.interfaces;
        int var2 = var1.length;
 
        int var3;
        Class var4;
        for(var3 = 0; var3 < var2; ++var3) {
            var4 = var1[var3];
             //重點(diǎn):代理那些方法?實(shí)例方法
            Method[] var5 = var4.getMethods();
            int var6 = var5.length;
            
            for(int var7 = 0; var7 < var6; ++var7) {
                Method var8 = var5[var7];
                this.addProxyMethod(var8, var4);
            }
        }
 
        Iterator var11 = this.proxyMethods.values().iterator();
 
        List var12;
        while(var11.hasNext()) {
            var12 = (List)var11.next();
            checkReturnTypes(var12);
        }
 
        Iterator var15;
        try {
            this.methods.add(this.generateConstructor());
            var11 = this.proxyMethods.values().iterator();
 
            while(var11.hasNext()) {
                var12 = (List)var11.next();
                var15 = var12.iterator();
 
                while(var15.hasNext()) {
                    ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
                    this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                    this.methods.add(var16.generateMethod());
                }
            }
 
            this.methods.add(this.generateStaticInitializer());
        } catch (IOException var10) {
            throw new InternalError("unexpected I/O Exception", var10);
        }
 
        if (this.methods.size() > 65535) {
            throw new IllegalArgumentException("method limit exceeded");
        } else if (this.fields.size() > 65535) {
            throw new IllegalArgumentException("field limit exceeded");
        } else {
            this.cp.getClass(dotToSlash(this.className));
            this.cp.getClass("java/lang/reflect/Proxy");
            var1 = this.interfaces;
            var2 = var1.length;
 
            for(var3 = 0; var3 < var2; ++var3) {
                var4 = var1[var3];
                this.cp.getClass(dotToSlash(var4.getName()));
            }
 
            this.cp.setReadOnly();
            ByteArrayOutputStream var13 = new ByteArrayOutputStream();
            DataOutputStream var14 = new DataOutputStream(var13);
 
            try {
                var14.writeInt(-889275714);
                var14.writeShort(0);
                var14.writeShort(49);
                this.cp.write(var14);
                var14.writeShort(this.accessFlags);
                var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
                var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
                var14.writeShort(this.interfaces.length);
                Class[] var17 = this.interfaces;
                int var18 = var17.length;
 
                for(int var19 = 0; var19 < var18; ++var19) {
                    Class var22 = var17[var19];
                    var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
                }
 
                var14.writeShort(this.fields.size());
                var15 = this.fields.iterator();
 
                while(var15.hasNext()) {
                    ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                    var20.write(var14);
                }
 
                var14.writeShort(this.methods.size());
                var15 = this.methods.iterator();
 
                while(var15.hasNext()) {
                    ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                    var21.write(var14);
                }
 
                var14.writeShort(0);
                return var13.toByteArray();
            } catch (IOException var9) {
                throw new InternalError("unexpected I/O Exception", var9);
            }
        }
    }

上DEBUG截圖:

到此處,已經(jīng)清楚JDK底層生成代理類(lèi)時(shí)代理哪些方法,其中反射getMethods是可以獲取到Class中所有public方法,包括靜態(tài)方法。

由于JDK代理是基于接口的,而接口里面又不允許有靜態(tài)方法,所以是無(wú)法代理靜態(tài)方法的。換個(gè)角度:基于接口的Jdk代理與基于繼承Class的代理本質(zhì)都是基于繼承之后重寫(xiě)指定方法實(shí)現(xiàn)的代理,而static方法是屬于class的,而不是類(lèi)實(shí)例的,無(wú)法被重寫(xiě)所以static方法無(wú)法代理。除此之外,JDK代理類(lèi)是基于接口實(shí)現(xiàn)生成的,因此對(duì)于子類(lèi)的final方法是可以代理的。

需要注意:Jdk8中的default方式是實(shí)例方法,而靜態(tài)方法。

2、CGLIB代理

 
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; 
interface Echor {
    public void echo(); 
    public static void hello() {
        System.out.println("hello world!");
    }
} 
 
abstract class AbsEchor implements Echor { 
    public static void abs() {
        System.out.println("abs~~");
    } 
 
    public static void hello() {
        System.out.println("hello world!");
    }
}
 
class EchorImpl implements Echor { 
    public static void hello2() {
        System.out.println("hello world!");
    } 
    @Override
    public void echo() {
        System.out.println("echo ~");
    }
}  
 
class EchorMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("start ~");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("end ~"); 
        return result; 
    }
}
 
class DebugCGlibProxy { 
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(AbsEchor.class);
        enhancer.setCallback(new EchorMethodInterceptor()); 
        AbsEchor hello = (AbsEchor) enhancer.create();
        hello.abs();
    } 
}

小結(jié)一下:基于JDK代理與基于CGLIB代理的代理類(lèi)生成本質(zhì)都是基于繼承重寫(xiě)實(shí)現(xiàn)的(實(shí)現(xiàn)接口可以認(rèn)為是一種特殊的繼承);對(duì)于static成員方法是無(wú)法子類(lèi)重寫(xiě)的,static是歸屬于class所屬。

至此:由于Spring使用的是JDK與CGLIB這兩種方式實(shí)現(xiàn)AOP,因此結(jié)論就是Spring無(wú)法支持static方法的代理增強(qiáng)。

Spring AOP靜態(tài)代理

對(duì)于AOP 我們應(yīng)該拿OOP來(lái)對(duì)比學(xué)習(xí),它們之間的區(qū)別如下:

AOP中不得不提的就是代理

通俗理解就是:茅臺(tái)公司生產(chǎn)出酒,而代理商拿出來(lái)銷(xiāo)售并推出各種銷(xiāo)售活動(dòng)。這時(shí)茅臺(tái)公司就是真實(shí)主題,也就是目標(biāo)對(duì)象。而代理商就是代理。茅臺(tái)酒就是目標(biāo)對(duì)象中的方法。各種銷(xiāo)售活動(dòng)就是給目標(biāo)對(duì)象中的方法的增強(qiáng)補(bǔ)充,比如對(duì)方法添加日志等等操作。

代理又分為靜態(tài)代理和動(dòng)態(tài)代理兩種:像這樣已知目標(biāo)對(duì)象就是為茅臺(tái)公司 就為靜態(tài)代理,這時(shí)目標(biāo)對(duì)象已確定

下面為一個(gè)靜態(tài)代理的例子

先定義一個(gè)PersonBiz的接口:

再對(duì)這個(gè)接口進(jìn)行實(shí)現(xiàn)

這是我們使用靜態(tài)代理給這兩個(gè)方法加上一個(gè)操作時(shí)間的功能,我就直接上代碼了:

package com.yc.dao.impl;
import java.util.Date;
import com.yc.dao.PersonBiz;
//代理對(duì)象
public class PersonBizProxy implements PersonBiz {
    private PersonBiz personBiz;// 對(duì)真實(shí)主題的引用
    public PersonBizProxy(PersonBiz personBiz) {
        this.personBiz = personBiz;
    }
    @Override
    public void add(String name) {
        // 加入關(guān)注點(diǎn)-》增強(qiáng)的功能
        showLog();// 前置增強(qiáng)
        // 再調(diào)用真實(shí)主題的方法
        this.personBiz.add(name);
    }
    @Override
    public String find() {
        // 調(diào)用真實(shí)主題的方法
        personBiz.find();
        // 加入關(guān)注點(diǎn)-》增強(qiáng)的功能
        showLog();// 后置增強(qiáng)
        return null;
    }
    private void showLog() {
        Date d = new Date();
        System.out.println("-----------------");
        System.out.println("操作時(shí)間" + d);
        System.out.println("-----------------");
    }
}

最后就是測(cè)試類(lèi):

代理的優(yōu)勢(shì)很明顯:當(dāng)你不需要新增的操作時(shí)間的功能時(shí),就將PersonBizProxy pbp=new PersonBizProxy(pb);去掉即可,后面改用pb調(diào)用方法,讓代碼很好的實(shí)現(xiàn)了可擴(kuò)展性,也不用在原來(lái)已有的代碼上修改。

靜態(tài)代理的缺點(diǎn):只能針對(duì)一個(gè)接口進(jìn)行代理

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java實(shí)現(xiàn)斗地主發(fā)牌系統(tǒng)

    java實(shí)現(xiàn)斗地主發(fā)牌系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)斗地主發(fā)牌系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • Java Lambda表達(dá)式原理及多線程實(shí)現(xiàn)

    Java Lambda表達(dá)式原理及多線程實(shí)現(xiàn)

    這篇文章主要介紹了Java Lambda表達(dá)式原理及多線程實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • shiro編碼和加密代碼詳解

    shiro編碼和加密代碼詳解

    Shiro提供了base64和16進(jìn)制字符串編碼/解碼的API支持,方便一些編碼解碼操作。下面通過(guò)實(shí)例代碼給大家詳解shiro編碼和加密知識(shí),感興趣的朋友一起看看吧
    2017-09-09
  • mybatis-plus多表關(guān)聯(lián)查詢(xún)功能的實(shí)現(xiàn)

    mybatis-plus多表關(guān)聯(lián)查詢(xún)功能的實(shí)現(xiàn)

    本文給大家介紹mybatis-plus多表關(guān)聯(lián)查詢(xún)功能的實(shí)現(xiàn)代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-11-11
  • Spring MVC多種情況下進(jìn)行文件上傳的實(shí)例

    Spring MVC多種情況下進(jìn)行文件上傳的實(shí)例

    上傳是Web工程中很常見(jiàn)的功能,SpringMVC框架簡(jiǎn)化了文件上傳的代碼,本文給大家總結(jié)了Spring MVC多種情況下進(jìn)行文件上傳的實(shí)例,并通過(guò)代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2024-02-02
  • Java之哈夫曼壓縮原理案例講解

    Java之哈夫曼壓縮原理案例講解

    這篇文章主要介紹了Java之哈夫曼壓縮原理案例講解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Spring中的事務(wù)隔離級(jí)別和傳播行為

    Spring中的事務(wù)隔離級(jí)別和傳播行為

    這篇文章主要介紹了Spring中的事務(wù)隔離級(jí)別和傳播行為,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 手把手帶你用java搞定漢諾塔

    手把手帶你用java搞定漢諾塔

    這篇文章主要給大家介紹了關(guān)于Java青蛙跳臺(tái)階問(wèn)題的解決思路與代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08
  • java抓取鼠標(biāo)事件和鼠標(biāo)滾輪事件示例

    java抓取鼠標(biāo)事件和鼠標(biāo)滾輪事件示例

    這篇文章主要介紹了java抓取鼠標(biāo)事件和鼠標(biāo)滾輪事件示例,需要的朋友可以參考下
    2014-05-05
  • Springboot使用influxDB時(shí)序數(shù)據(jù)庫(kù)的實(shí)現(xiàn)

    Springboot使用influxDB時(shí)序數(shù)據(jù)庫(kù)的實(shí)現(xiàn)

    項(xiàng)目中需要存放大量設(shè)備日志,且需要對(duì)其進(jìn)行簡(jiǎn)單的數(shù)據(jù)分析,信息提取工作,所以本文就介紹一下Springboot使用influxDB時(shí)序數(shù)據(jù)庫(kù),感興趣的可以了解一下
    2021-08-08

最新評(píng)論

大庆市| 南溪县| 鄄城县| 兴安盟| 东辽县| 革吉县| 庄浪县| 鄂托克旗| 泰安市| 石阡县| 沾化县| 东兰县| 阜新| 裕民县| 中西区| 宽城| 湄潭县| 镇远县| 大埔县| 北流市| 孙吴县| 新竹县| 错那县| 徐汇区| 城固县| 光泽县| 唐山市| 红原县| 武邑县| 建阳市| 黔西县| 太仆寺旗| 安岳县| 乐清市| 青神县| 中西区| 右玉县| 固阳县| 博野县| 丰镇市| 临泽县|