字节码技术在动态代理中的实现探讨

谈到动态代理,大家估计都非常熟悉,本文旨在深入探讨java动态代理的实现技术。
先看看一种jdk动态代理的简单实现:

定义一个接口如下:
1.BookOrder

 package com.xxx.dynamicproxy.jdk;
 public interface BookOrder { 

        public void order();

 }

接口的实现类,亦即目标类
2.BookOrderImpl

package com.xxx.dynamicproxy.jdk;
public class BookOrderImpl implements BookOrder { 
            public void order() {
            //todo
            System.out.println("order successfully !!! ");
            }
}

3.实现InvocationHandler接口。

package com.xxx.dynamicproxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class BookOrderProxy implements InvocationHandler {
        private Object target;
        public BookOrderProxy(Object target)
        {
               this.target = target;
        }
public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable
{
    //在调用具体目标对象的方法之前,执行一些处理,
    System.out.println("before order  ......");
    //调用具体目标对象的方法
    Object result = method.invoke(target, args);
    //在调用具体目标对象之后,执行一些处理
    System.out.println("after order  ......");
    return result;
}

}

4.测试类,我们顺便生成代理后字节码文件

 public class DynamicProxy {
    public static void main( String args[] )
   {
    BookOrderImpl bookOrderImpl = new BookOrderImpl();
    BookOrder proxyBookOrder = (BookOrder)Proxy.newProxyInstance(BookOrder.class.getClassLoader(),
            new Class[]{BookOrder.class},
            new BookOrderProxy(bookOrderImpl));
    proxyBookOrder.order();
    try {
        //生成代理后的字节码文件
        doGenerateProxyClassFile();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static void doGenerateProxyClassFile() throws IOException {
    String name = "ProxyBookOrder";
    FileOutputStream out = null;
    byte[] data = ProxyGenerator.generateProxyClass( name, new Class[] { BookOrder.class } );
    try
    {
        out = new FileOutputStream( name + ".class" );
        out.write( data );
        out.close();
    }
    catch( Exception e )
    {
        e.printStackTrace();
    }finally{
        if(out !=null){
            out.close();
        }
    }
}

}

执行后:
before order …
order successfully !!!
after order …

这里我们先睹为快,看看生成的ProxyBookOrder.class到底是怎么实现的,反编译后代码如下:
import com.xxx.dynamicproxy.jdk.BookOrder;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class ProxyBookOrder
extends Proxy
implements BookOrder
{
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;

public ProxyBookOrder(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}

扫描二维码关注公众号,回复: 11380376 查看本文章

public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

public final void order()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

static
{
try
{
m1 = Class.forName(“java.lang.Object”).getMethod(“equals”, new Class[] { Class.forName(“java.lang.Object”) });
m0 = Class.forName(“java.lang.Object”).getMethod(“hashCode”, new Class[0]);
m3 = Class.forName(“com.xxx.dynamicproxy.jdk.BookOrder”).getMethod(“order”, new Class[0]);
m2 = Class.forName(“java.lang.Object”).getMethod(“toString”, new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}

ok,我们主要看jdk动态代理实现的过程,我们首先跟踪Proxy.newProxyInstance方法,笔者跟踪的是jdk1.7的源码 ,如下图所示:

public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
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 {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return newInstance(cons, ih);
}
});
} else {
return newInstance(cons, ih);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}

仅仅有上述代码,我们发现其实Proxy类的newProxyInstance方法主要做了两件事:一个就是通过getProxyClass0方法生成代理的字节码对象,第二个就是通过生成代理字节码对象获取它的Constructor对象,而后通过反射实例化生成的代理对象。
我们看看生成字节码对象的方法getProxyClass0:

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生成代理字节码对象。
我们继续跟进去:

private final BiFunction<K, P, ?> subKeyFactory;

public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
//删除过时的实体
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier stored by that
// subKey from valuesMap
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue instance
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn’t successful in installing the CacheValue)
// lazily construct a Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}

这里面没有贴出来,其实ProxyClassFactory是BiFunction的实现类,我们直接观察其apply方法:

   // 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

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

这里,通过一些相关的校验,动态代理类的名称,包名的确定,通过ProxyGenerator.generateProxyClass生成字节码,然后通过本地方法defineClass0将方法加载到JVM中去,我们更关注
generateProxyClass方法如下:

public static byte[] generateProxyClass(final String var0, Class[] var1) {
ProxyGenerator var2 = new ProxyGenerator(var0, var1);
final byte[] var3 = var2.generateClassFile();
if(saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
try {
FileOutputStream var1 = new FileOutputStream(ProxyGenerator.dotToSlash(var0) + “.class”);
var1.write(var3);
var1.close();
return null;
} catch (IOException var2) {
throw new InternalError("I/O exception saving generated file: " + var2);
}
}
});
}
return var3;
}

private byte[] generateClassFile() {
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
int var1;
int var3;
for(var1 = 0; var1 < this.interfaces.length; ++var1) {
Method[] var2 = this.interfaces[var1].getMethods();
for(var3 = 0; var3 < var2.length; ++var3) {
this.addProxyMethod(var2[var3], this.interfaces[var1]);
}
}
Iterator var7 = this.proxyMethods.values().iterator();
List var8;
while(var7.hasNext()) {
var8 = (List)var7.next();
checkReturnTypes(var8);
}
Iterator var11;
try {
this.methods.add(this.generateConstructor());
var7 = this.proxyMethods.values().iterator();
while(var7.hasNext()) {
var8 = (List)var7.next();
var11 = var8.iterator();
while(var11.hasNext()) {
ProxyGenerator.ProxyMethod var4 = (ProxyGenerator.ProxyMethod)var11.next();
this.fields.add(new ProxyGenerator.FieldInfo(var4.methodFieldName, “Ljava/lang/reflect/Method;”, 10));
this.methods.add(var4.generateMethod());
}
}
this.methods.add(this.generateStaticInitializer());
} catch (IOException var6) {
throw new InternalError(“unexpected I/O Exception”);
}
if(this.methods.size() > ‘\uffff’) {
throw new IllegalArgumentException(“method limit exceeded”);
} else if(this.fields.size() > ‘\uffff’) {
throw new IllegalArgumentException(“field limit exceeded”);
} else {
this.cp.getClass(dotToSlash(this.className));
this.cp.getClass(“java/lang/reflect/Proxy”);
for(var1 = 0; var1 < this.interfaces.length; ++var1) {
this.cp.getClass(dotToSlash(this.interfaces[var1].getName()));
}
this.cp.setReadOnly();
ByteArrayOutputStream var9 = new ByteArrayOutputStream();
DataOutputStream var10 = new DataOutputStream(var9);
try {
var10.writeInt(-889275714); //其实这个有符号的负数转换成十六进制就是Oxcafebabe,java class文件的魔数
var10.writeShort(0);//写入两个字节的次版本号
var10.writeShort(49);//写入两个字节的主版本号,49,说明是1.5版本的class
this.cp.write(var10);//这个cp 其实就是constant pool 常量池对象,此处是将常量池写入
var10.writeShort(49);//
var10.writeShort(this.cp.getClass(dotToSlash(this.className)));
var10.writeShort(this.cp.getClass(“java/lang/reflect/Proxy”));
var10.writeShort(this.interfaces.length);
for(var3 = 0; var3 < this.interfaces.length; ++var3) {
var10.writeShort(this.cp.getClass(dotToSlash(this.interfaces[var3].getName())));
}
var10.writeShort(this.fields.size());
var11 = this.fields.iterator();
while(var11.hasNext()) {
ProxyGenerator.FieldInfo var12 = (ProxyGenerator.FieldInfo)var11.next();
var12.write(var10);
}
var10.writeShort(this.methods.size());
var11 = this.methods.iterator();
while(var11.hasNext()) {
ProxyGenerator.MethodInfo var13 = (ProxyGenerator.MethodInfo)var11.next();
var13.write(var10);
}
var10.writeShort(0);
return var9.toByteArray();
} catch (IOException var5) {
throw new InternalError(“unexpected I/O Exception”);
}
}
}
可见最终,还是通过直接通过字节码流,实现动态代理类。

猜你喜欢

转载自blog.csdn.net/baoxue2008/article/details/103549441
今日推荐