java 動(dòng)態(tài)字節(jié)碼技術(shù)

aop在java中有幾種實(shí)現(xiàn)方式?

  • java proxy
    基于接口的實(shí)現(xiàn),構(gòu)建目標(biāo)類(lèi)的實(shí)現(xiàn)類(lèi)(全新的類(lèi)),初始化的時(shí)候
  • cglib
    基于繼承實(shí)現(xiàn),構(gòu)建目標(biāo)類(lèi)的子類(lèi)(全新的類(lèi)),初始化的時(shí)候
  • Aspectj
    aspectJ的使用是在編譯期,通過(guò)特殊的編譯器可以在不改變代碼的前提下織入代碼
    修改目標(biāo)類(lèi)的字節(jié),織入代理的字節(jié),在程序編譯的時(shí)候,不會(huì)生成全新的class,
  • java agent
    修改目標(biāo)類(lèi)的字節(jié)碼,在類(lèi)裝載的時(shí)候,插入動(dòng)態(tài)代理的字節(jié)碼,不會(huì)生成全新的class
    是通過(guò)java.lang.instrument實(shí)現(xiàn),用來(lái)在 ClassLoader 加載字節(jié)碼之前完成對(duì)操作字節(jié)碼的目的
    java -javaagent:G:\myagent.jar=Hello1 -jar myapp.jar

字節(jié)碼 bytecode: .java => .class(16進(jìn)制) => jvm指令碼(數(shù)字)=>機(jī)器碼 idea view show bytecode

共同點(diǎn)

都是對(duì)jvm class字節(jié)碼進(jìn)行操作

不同點(diǎn)

操作方式不一樣,第一個(gè)和第二個(gè)是基于對(duì)字節(jié)碼的新增(新增一個(gè)完整的字節(jié)碼,但是要等到需要被操作的類(lèi)被加載之后才會(huì)在系統(tǒng)運(yùn)行期動(dòng)態(tài)生成代理類(lèi),新增類(lèi)必須用到代理(對(duì)性能有一定的影響),第三種和第四種是基于對(duì)字節(jié)碼的修改(修改現(xiàn)有的類(lèi)的字節(jié)碼)也就是說(shuō)被代理的類(lèi)的class字節(jié)碼 在裝載入jvm的時(shí)候,已經(jīng)被修改了所以性能會(huì)很高
修改不需要用到代理

  • 反射
    是java代碼層面的概念,字節(jié)碼是jvm層面的概念

jdk 動(dòng)態(tài)代理實(shí)現(xiàn)

  • 會(huì)生成一個(gè)字節(jié)數(shù)組(一個(gè)全新的類(lèi)),繼承了實(shí)現(xiàn)了service接口并且繼承了Proxy,如下圖在運(yùn)行期動(dòng)態(tài)生成出類(lèi)的字節(jié)碼,并且加載,這也就是為什么Proxy.newProxyInstance需要傳入classLoader的原因
    注意:在Proxy生成動(dòng)態(tài)代理類(lèi)的時(shí)候,會(huì)驗(yàn)證接口類(lèi)能否被指定classloader加載,不能會(huì)報(bào) is not visible from class loader異常
    Class.forName(String className)使用裝載當(dāng)前類(lèi)的類(lèi)裝載器來(lái)裝載制定的類(lèi)
public interface ServiceGetName {
    String getName(String name);
}
public class ServiceGetNameImpl implements ServiceGetName {
    @Override
    public String getName(String name) {
        return name;
    }
}
 public static void main(String[] args)  throws Exception{
        //java proxy 接口動(dòng)態(tài)代理
        ServiceGetNameImpl serviceGetNameImpl = new ServiceGetNameImpl();
        ServiceGetName serviceGetName;
        /**
         * 1. 在內(nèi)存里面生成一個(gè)class字節(jié)碼,得到class類(lèi)的字節(jié)碼數(shù)組
         *  a. 生成一個(gè)代理類(lèi)數(shù)組
         * 2. class 在jvm的裝載,這也是為什么要傳一個(gè)classloader的原因
         * 3. 通過(guò)反射來(lái)new一個(gè)代理實(shí)例
         */
        Object proxy = Proxy.newProxyInstance(ProxyDemo.class.getClassLoader(),new Class[]{ServiceGetName.class}
                , new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("前置邏輯");
                try {
                    return method.invoke(serviceGetNameImpl,args);
                } finally {
                    System.out.println("后置邏輯");
                }

            }
        });
        serviceGetName = (ServiceGetName)proxy;
        String r = serviceGetName.getName("zhangsan");
        System.out.println(r);
        buildProxyClass();
    }
 public static void  buildProxyClass() throws Exception{
        //代理的proxy 源碼
        //生成一個(gè)代理字節(jié)碼數(shù)組
        byte[] bytes= ProxyGenerator.generateProxyClass("ServiceGetName$proxy",new Class[]{ServiceGetName.class});
        String fileName = System.getProperty("user.dir")+"/target/ServiceGetName$proxy.class";
        File f = new File(fileName);
        FileOutputStream out = new FileOutputStream(f);
        out.write(bytes);
        out.flush();
        out.close();
    }

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import com.xcar.designpattern.bytecode.ServiceGetName;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class ServiceGetName$proxy extends Proxy implements ServiceGetName {
    private static Method m1;
    private static Method m2;
    private static Method m0;
    private static Method m3;

    public ServiceGetName$proxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String getName(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m3 = Class.forName("com.xcar.designpattern.bytecode.ServiceGetName").getMethod("getName", Class.forName("java.lang.String"));
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

參考
https://www.cnblogs.com/aspirant/p/8796974.html
https://blog.csdn.net/ljz2016/article/details/83309599
https://www.cnblogs.com/lilei94/p/9744331.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容