Java字节码深入解析(二)

  1. 针对于方法调用动态分派的过程,虚拟机会在类的方法区建立一个虚方法表的数据结构(virtual method table)
  2. 针对于invokeinterface指令来说,虚拟机会建立一个叫做接口方法表的数据结构(interface method table)
  3. 虚方法表中的每一个方法都被描述出来一个方法调用的入口地址,如果子类没有重写(没有从父类继承的一些方法),子类中的虚方法表会直接指向父类(对象)当中的方法入口地址(如Object中的n多个方法子类没有重写)。对于子类重写的一些方法(相同方法描述符),他们的索引一样(子类找完找父类特定索引当中的位置,提高了查找的效率)。
  4. 现代JVM在执行JAVA代码都会结合两种执行:编译执行(通过即时编译器将字节码转成本地机器码来执行,会根据代码热点来生成相应的本地机器码)和解释执行(解释器读取字节码,遇到相应指令就执行指令)
  5. 基于栈的指令集与基于寄存器的指令集之间的关系:
    1JVM执行指令时所采取的方式是基于栈的指令集
    2基于栈的指令集主要的操作有入栈和出栈两种
    3基于栈的指令集的优势在于它可以在不同平台之间移植,而基于寄存器的指令集是与硬件架构紧密关联的,无法做到可移植
    4基于栈的指令集的缺点在于完成相同的操作,指令数量通常要比基于寄存器的指令集数量多;
    5基于栈的指令集是在内存中完成操作的,而基于寄存器的指令集是直接由CPU来执行的,它是在高速缓冲区中进行执行的,速度要   比基于栈的指令集快的多。
  6. 通过字节码理解动态代理实现机制:
    1)subject接口
    2)实现subject接口的realSubject类
    3)实现InvocationHandler接口的代理类DanamicSubject
    4)主方法
  7. public interface Subject {
        void request();
    }
    public class RealSubject implements Subject {
        public void request(){
            System.out.println("From real subject");
        }
    }
    public class DanamicSubject implements InvocationHandler {
        private Object object;
        public DanamicSubject(Object object) {
            this.object = object;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Method before" + method);
            method.invoke(object,args);
            System.out.println("After calling" + method);
            return null;
        }
    }

    创建一个代理对象

  8. public class TestProxyByte {
        public static void main(String[] args) {
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
            RealSubject real = new RealSubject();
    //        InvocationHandler invo = new DanamicSubject(real);
            Subject ds = (Subject) Proxy.newProxyInstance(real.getClass().getClassLoader(),
                    real.getClass().getInterfaces(), new DanamicSubject(real));
    //       调用Proxy类的newProxyInstance静态方法实际上:
    //       內含兩個操作:1动态生成代理类本身2创建所生成的代理类的实例(对象)
            ds.request();
            System.out.println(ds.getClass());
        }
    }
    
    结果:
    Method beforepublic abstract void TestProxyByteCode.Subject.request()
    From real subject
    After callingpublic abstract void TestProxyByteCode.Subject.request()
    class com.sun.proxy.$Proxy0

     
  9. 主方法中可以通过设置 : sun.misc.ProxyGenerator.saveGeneratedFiles 配置文件的属性为true来保存 生成的动态代理类的.class字节码文件;生成的代理类的名称为$Proxy0.class
  10. 可以在idea中打开生成的文件(显示字节码的反编译结果):
    1)动态代理中重写生成了Object类的equals,toString,hashCode方法,而Object类中的其他方法没有被生成。
    2)实现了给定接口中的方法,其中都会调用super.h.invoke....的返回值(返回一个代理对象),super即Proxy类,h为InvocationHandler(由主程序传入的是DanamicSubject);即代理方法都会去调用InvocationHandler的invoke()方法,因此我们需要重写InvocationHandler的invoke()方法。
    public final class $Proxy0 extends Proxy implements Subject {
        private static Method m1;
        private static Method m2;
        private static Method m3;
        private static Method m0;
    
        public $Proxy0(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 void request() throws  {
            try {
                super.h.invoke(this, m3, (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);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("TestProxyByteCode.Subject").getMethod("request");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
  11. 调用Proxy类的newProxyInstance静态方法创建代理对象源码解析:
        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
    
            final Class<?>[] intfs = interfaces.clone();
            final SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
            }
    
            /*
             * Look up or generate the designated proxy class.
             */
            Class<?> cl = getProxyClass0(loader, intfs);
    
            /*
             * Invoke its constructor with the designated invocation handler.
             */
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
    
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            cons.setAccessible(true);
                            return null;
                        }
                    });
                }
    //Constructor.newInstance(.....) 可以根据传入的参数,调用相应的构造函数
    //此处为代理类的构造函数,所有代理类都继承自Proxy, 因此这里会调用Proxy的构造器
    //将InvocationHandler引用传入
                return cons.newInstance(new Object[]{h});
            } catch (IllegalAccessException|InstantiationException e) {
                throw new InternalError(e.toString(), e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getCause();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                } else {
                    throw new InternalError(t.toString(), t);
                }
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
        }

    其中getProxyClass0方法生成了代理类的类对象

  12.     /**
         * Generate a proxy class.  Must call the checkProxyAccess method
         * to perform permission checks before calling this.
         */
        private static Class<?> getProxyClass0(ClassLoader loader,
                                               Class<?>... interfaces) {
            if (interfaces.length > 65535) {
                throw new IllegalArgumentException("interface limit exceeded");
            }
    
            // If the proxy class defined by the given loader implementing
            // the given interfaces exists, this will simply return the cached copy;
            // otherwise, it will create the proxy class via the ProxyClassFactory
            return proxyClassCache.get(loader, interfaces);
        }
    通过类加载器和接口集合去缓存里面获取(待补充其源码分析),如果能找到代理类就直接返回;否则就会调用ProxyClassFactory这个工厂去生成一个代理类
  13. ProxyClassFactory源码分析:
         //* A factory function that generates, defines and returns the proxy class given
         // the ClassLoader and array of interfaces.
         //
        private static final class ProxyClassFactory
            implements BiFunction<ClassLoader, Class<?>[], Class<?>>
        {
            // prefix for all proxy class names
            private static final String proxyClassNamePrefix = "$Proxy";
    
            // next number to use for generation of unique proxy class names
            private static final AtomicLong nextUniqueNumber = new AtomicLong();
    
            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
                Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
                for (Class<?> intf : interfaces) {
                    /*
                     * Verify that the class loader resolves the name of this
                     * interface to the same Class object.
                     */
                    Class<?> interfaceClass = null;
                    try {
                        interfaceClass = Class.forName(intf.getName(), false, loader);
                    } catch (ClassNotFoundException e) {
                    }
                    if (interfaceClass != intf) {
                        throw new IllegalArgumentException(
                            intf + " is not visible from class loader");
                    }
                    /*
                     * Verify that the Class object actually represents an
                     * interface.
                     */
                    if (!interfaceClass.isInterface()) {
                        throw new IllegalArgumentException(
                            interfaceClass.getName() + " is not an interface");
                    }
                    /*
                     * Verify that this interface is not a duplicate.
                     */
                    if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                        throw new IllegalArgumentException(
                            "repeated interface: " + interfaceClass.getName());
                    }
                }
    
                String proxyPkg = null;     // package to define proxy class in
                int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
    
                /*
                 * Record the package of a non-public proxy interface so that the
                 * proxy class will be defined in the same package.  Verify that
                 * all non-public proxy interfaces are in the same package.
                 */
                for (Class<?> intf : interfaces) {
                    int flags = intf.getModifiers();
                    if (!Modifier.isPublic(flags)) {
                        accessFlags = Modifier.FINAL;
                        String name = intf.getName();
                        int n = name.lastIndexOf('.');
                        String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                        if (proxyPkg == null) {
                            proxyPkg = pkg;
                        } else if (!pkg.equals(proxyPkg)) {
                            throw new IllegalArgumentException(
                                "non-public interfaces from different packages");
                        }
                    }
                }
    
                if (proxyPkg == null) {
                    // if no non-public proxy interfaces, use com.sun.proxy package
                    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
                }
    
                /*
                 * Choose a name for the proxy class to generate.
                 */
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                /*核心
                 * Generate the specified proxy class.
                 */
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
                try {
                    return defineClass0(loader, proxyName,
                                        proxyClassFile, 0, proxyClassFile.length);
                } catch (ClassFormatError e) {
                    /*
                     * A ClassFormatError here means that (barring bugs in the
                     * proxy class generation code) there was some other
                     * invalid aspect of the arguments supplied to the proxy
                     * class creation (such as virtual machine limitations
                     * exceeded).
                     */
                    throw new IllegalArgumentException(e.toString());
                }
            }
        }

     
  14. GenerateClassFile()分析:可参考https://www.cnblogs.com/liuyun1995/p/8144706.html
        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);
                }
            }
        }

 

 

 

 

任重而道远
思考与想法都可以时刻记录下来

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值