亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring支持對靜態方法進行Aop增強嗎

發布時間:2021-12-24 09:28:37 來源:億速云 閱讀:148 作者:iii 欄目:開發技術

本篇內容主要講解“Spring支持對靜態方法進行Aop增強嗎”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Spring支持對靜態方法進行Aop增強嗎”吧!

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實現代理類比較重要的類sun.misc.ProxyGenerator,生成代理類的方法為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];
             //重點:代理那些方法?實例方法
            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截圖:

Spring支持對靜態方法進行Aop增強嗎

到此處,已經清楚JDK底層生成代理類時代理哪些方法,其中反射getMethods是可以獲取到Class中所有public方法,包括靜態方法。

由于JDK代理是基于接口的,而接口里面又不允許有靜態方法,所以是無法代理靜態方法的。換個角度:基于接口的Jdk代理與基于繼承Class的代理本質都是基于繼承之后重寫指定方法實現的代理,而static方法是屬于class的,而不是類實例的,無法被重寫所以static方法無法代理。除此之外,JDK代理類是基于接口實現生成的,因此對于子類的final方法是可以代理的。

需要注意:Jdk8中的default方式是實例方法,而靜態方法。

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();
    } 
}

小結一下:基于JDK代理與基于CGLIB代理的代理類生成本質都是基于繼承重寫實現的(實現接口可以認為是一種特殊的繼承);對于static成員方法是無法子類重寫的,static是歸屬于class所屬。

至此:由于Spring使用的是JDK與CGLIB這兩種方式實現AOP,因此結論就是Spring無法支持static方法的代理增強。

Spring AOP靜態代理

對于AOP 我們應該拿OOP來對比學習,它們之間的區別如下:

Spring支持對靜態方法進行Aop增強嗎

AOP中不得不提的就是代理

Spring支持對靜態方法進行Aop增強嗎

通俗理解就是:茅臺公司生產出酒,而代理商拿出來銷售并推出各種銷售活動。這時茅臺公司就是真實主題,也就是目標對象。而代理商就是代理。茅臺酒就是目標對象中的方法。各種銷售活動就是給目標對象中的方法的增強補充,比如對方法添加日志等等操作。

代理又分為靜態代理和動態代理兩種:像這樣已知目標對象就是為茅臺公司 就為靜態代理,這時目標對象已確定

下面為一個靜態代理的例子

先定義一個PersonBiz的接口:

Spring支持對靜態方法進行Aop增強嗎

再對這個接口進行實現

Spring支持對靜態方法進行Aop增強嗎

這是我們使用靜態代理給這兩個方法加上一個操作時間的功能,我就直接上代碼了:

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

最后就是測試類:

Spring支持對靜態方法進行Aop增強嗎

代理的優勢很明顯:當你不需要新增的操作時間的功能時,就將PersonBizProxy pbp=new PersonBizProxy(pb);去掉即可,后面改用pb調用方法,讓代碼很好的實現了可擴展性,也不用在原來已有的代碼上修改。

靜態代理的缺點:只能針對一個接口進行代理

到此,相信大家對“Spring支持對靜態方法進行Aop增強嗎”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

德清县| 秦安县| 小金县| 河间市| 繁昌县| 广州市| 凌云县| 肃北| 辽阳县| 新蔡县| 葵青区| 昆明市| 淅川县| 陈巴尔虎旗| 荔波县| 封丘县| 丹寨县| 长泰县| 滨州市| 张家川| 弥勒县| 吉隆县| 行唐县| 安多县| 远安县| 安阳市| 新田县| 花莲县| 孟连| 新绛县| 涟水县| 恩施市| 濮阳市| 汝南县| 亳州市| 崇义县| 绥中县| 阿克陶县| 屯留县| 三河市| 武清区|