栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计模式之代理模式静态代理,动态代理以及源码分析,CGLIB

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式之代理模式静态代理,动态代理以及源码分析,CGLIB

最近在系统的啃一啃设计模式相关的东西, 其中对代理模式尤为感兴趣(主要也觉得它很神奇),而且代理模式的用途实在是太广泛了
说代理之前,从一个需求入手:
有一个tank类,作为一个坦克,肯定可以移动,也就是肯定会有一个移动的方法,我想记录一下它的move方法的执行时间,该怎么做?

interface Movable {
    void move();
}
public class Tank implements Movable {

    
    @Override
    public void move() {
        System.out.println("Tank moving claclacla...");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

最low的可能想到是手动在move方法前后手动添加执行代码。。。

@Override
public void move() {
    long start = System.currentTimeMillis();

    System.out.println("Tank moving claclacla...");
    try {
        Thread.sleep(new Random().nextInt(10000));
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    long end = System.currentTimeMillis();
    System.out.println(end - start);
}

但这种方式,总是要修改源代码,那我要是之后不想要了,是不是还得手动删除这段代码呢?
而且,如果是无法修改源码的情况下呢? 例如引入的是第三方的类。
代理就是用来解决这种方式的。

代理大致分为两种:
1、静态代理
2、动态代理
我们一个一个说。

1、静态代理

引入一个代理类,通过持有原对象

class TankTimeProxy implements Movable {
    Movable m;

    public TankTimeProxy(Movable m) {
        this.m = m;
    }

    @Override
    public void move() {
        long start = System.currentTimeMillis();
        m.move();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}    
}

此时可以:

public static void main(String[] args) {
    new TankTimeProxy(new Tank()).move();
}

好像到此已经实现了需求,也比较优雅的实现了,但想一想,如果我不光想记录执行时间,还想在前后做些其他事情呢?简单嘛,再来个代理类。
如果这样的各式需求比较多的话,那么将产生许多的代理对象,好像事情变得比较麻烦了。。。
所以,静态代理的缺点可以总结下:
代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

2、动态代理

静态代理的问题就是每一个代理都只能针对一个类型的事务。
那如果我们将代理行为与被代理对象进行分离呢?

JDK动态代理
public class Tank implements Movable {

    
    @Override
    public void move() {
        System.out.println("Tank moving claclacla...");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Tank tank = new Tank();

        //reflection 通过二进制字节码分析类的属性和方法

        Movable m = (Movable)Proxy.newProxyInstance(Tank.class.getClassLoader(),
                new Class[]{Movable.class}, //tank.class.getInterfaces()
                new LogHander(tank)
        );

        m.move();
    }
}

class LogHander implements InvocationHandler {

    Tank tank;

    public LogHander(Tank tank) {
        this.tank = tank;
    }
    //getClass.getMethods[]
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("method " + method.getName() + " start..");
        Object o = method.invoke(tank, args);
        System.out.println("method " + method.getName() + " end!");
        return o;
    }
}
interface Movable {
    void move();
}

JDK的动态代理需要被代理类必须是有实现接口的,因为它的动态代理是基于接口进行代理的。

调用原理

为了看清这个过程,我们以上面代码为例,直接来看一下它生成的代理类是长什么样子的

先要开启一个设置:

public static void main(String[] args) {
    Tank tank = new Tank();

    //这个参数名称可能会根据版本有所不同
    //可以在java.lang.reflect.ProxyGenerator类中找到字段saveGeneratedFiles进行查看
    System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");//在使用代理的时候,生成文件

    Movable m = (Movable)Proxy.newProxyInstance(Tank.class.getClassLoader(),
            new Class[]{Movable.class}, //tank.class.getInterfaces()
            new TimeProxy(tank)
    );

    m.move();

}

运行程序,发现项目根目录生成了一个文件夹,打开,看到Proxy类:

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

package com.peng.dp.proxy.v10;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

final class $Proxy0 extends Proxy implements Movable {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    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);
        }
    }
    
    //发现果然这个代理类有个move方法
    public final void move() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);  //调用指定的代理处理类的invoke方法(也就是我们先前写入逻辑的那个方法)
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

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

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.peng.dp.proxy.v10.Movable").getMethod("move"); //得到被代理对象指定接口的方法
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

关注代理类的move方法

 public final void move() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);  //调用指定的代理处理类的invoke方法(也就是我们先前写入逻辑的那个方法)
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

h就是我们之前传入的InvocationHandler ,调用它的invoke方法。
m3是谁?
观察代理类的静态代码块:

  m3 = Class.forName("com.peng.dp.proxy.v10.Movable").getMethod("move"); //得到被代理对象指定接口的方法

可以看到,就是被代理对象的那个move方法。。

是不是看到代理类,一切就都串起来了呢?

源码分析

这里以JDK8为基础,进行源码分析。

首先从生成代理对象的这个方法作为入口:

Movable m = (Movable)Proxy.newProxyInstance(Tank.class.getClassLoader(),
        new Class[]{Movable.class}, //tank.class.getInterfaces()
        new TimeProxy(tank)

进入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);
    }

    
     //根据注释,我们可以看到,这里就是生成代理的方法了
    Class cl = getProxyClass0(loader, intfs);

    
    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() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
         //对代理类进行实例化,并传入我们指定的handler
        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就是生成代理的方法。

进入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);
}

这里发现没几行代码,最终是使用了proxyClassCache类,我们来看下这个类是个啥:

private static final WeakCache[], Class>
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

可以发现,它是一个WeakCache类,它的构造方法分别传入了KeyFactory和ProxyClassFactory,这里埋一笔,其实它最终要使用ProxyClassFactory进行对代理类的生成。

我们继续。。。
进入proxyClassCache的get方法:

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> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap> 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
            //这里的supplier也就是下面代码的new Factory(key, parameter, subKey, valuesMap);
            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 = new Factory(key, parameter, subKey, valuesMap);
                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);
            }
        }
    }
}

继续的入口点是这里,调用了Factory类的get方法:

  V value = supplier.get();

我们继续深入:
进入get方法:

@Override
public synchronized V get() { // serialize access
    // re-check
    Supplier supplier = valuesMap.get(subKey);
    if (supplier != this) {
        // something changed while we were waiting:
        // might be that we were replaced by a Cachevalue
        // or were removed because of failure ->
        // return null to signal WeakCache.get() to retry
        // the loop
        return null;
    }
    // else still us (supplier == this)

    // create new value
    V value = null;
    try {
        //划重点,这里用到了valueFactory,也就是我们先前看到的那个ProxyClassFactory类,用于生成代理类的
        //所以这里就是我们的入口
        value = Objects.requireNonNull(valueFactory.apply(key, parameter));
    } finally {
        if (value == null) { // remove us on failure
            valuesMap.remove(subKey, this);
        }
    }
    // the only path to reach here is with non-null value
    assert value != null;

    // wrap value with Cachevalue (WeakReference)
    Cachevalue cachevalue = new Cachevalue<>(value);

    // try replacing us with Cachevalue (this should always succeed)
    if (valuesMap.replace(subKey, this, cachevalue)) {
        // put also in reverseMap
        reverseMap.put(cachevalue, Boolean.TRUE);
    } else {
        throw new AssertionError("Should not reach here");
    }

    // successfully replaced us with new Cachevalue -> return the value
    // wrapped by it
    return value;
}

看到了valueFactory,我们的代理对象的生成就是它操控的:

   value = Objects.requireNonNull(valueFactory.apply(key, parameter));

继续深入,进入它的apply方法:

@Override
public Class apply(ClassLoader loader, Class[] interfaces) {

    Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
    for (Class intf : interfaces) {
        
        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");
        }
        
        if (!interfaceClass.isInterface()) {
            throw new IllegalArgumentException(
                interfaceClass.getName() + " is not an interface");
        }
        
        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;

    
    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 + ".";
    }

    
    long num = nextUniqueNumber.getAndIncrement();
    String proxyName = proxyPkg + proxyClassNamePrefix + num;

    
     //根据注释,我们就知道,这里就是生成代理类的核心方法了。。
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
        proxyName, interfaces, accessFlags);
    try {
        //通过生成的代理类的字节数组内容,生成Class对象
        return defineClass0(loader, proxyName,
                            proxyClassFile, 0, proxyClassFile.length);
    } catch (ClassFormatError e) {
        
        throw new IllegalArgumentException(e.toString());
    }
}

可以看到我们的生成代理类的核心方法了:

  byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
        proxyName, interfaces, accessFlags);

继续进入:

public static byte[] generateProxyClass(final String var0, Class[] var1, int var2) {
    //注意这个类,是不是就是我们先前为了显示代理类文件的生成,设置参数名找寻的那个类呢?
    ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
    //向字节数组写入我们要生成的代理类的class内容
    final byte[] var4 = var3.generateClassFile();
    //如果开启了我们那个设置
    if (saveGeneratedFiles) {
        AccessController.doPrivileged(new PrivilegedAction() {
            public Void run() {
                try {
                    int var1 = var0.lastIndexOf(46);
                    Path var2;
                    if (var1 > 0) {
                        Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
                        Files.createDirectories(var3);
                        var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                    } else {
                        var2 = Paths.get(var0 + ".class");
                    }
                    //写入文件
                    Files.write(var2, var4, new OpenOption[0]);
                    return null;
                } catch (IOException var4x) {
                    throw new InternalError("I/O exception saving generated file: " + var4x);
                }
            }
        });
    }

    return var4;
}
final byte[] var4 = var3.generateClassFile();

继续进入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);
        }
    }
}

这个方法其实就涵盖了整个代理类的生成过程,对字段,方法的填充。。。
但我们抱着深入到底的心态,看看到底是咋实现的,继续再深入一步。。
进入addProxyMethod方法:

private void addProxyMethod(Method var1, Class var2) {
    String var3 = var1.getName();
    Class[] var4 = var1.getParameterTypes();
    Class var5 = var1.getReturnType();
    Class[] var6 = var1.getExceptionTypes();
    String var7 = var3 + getParameterDescriptors(var4);
    Object var8 = (List)this.proxyMethods.get(var7);
    if (var8 != null) {
        Iterator var9 = ((List)var8).iterator();

        while(var9.hasNext()) {
            ProxyGenerator.ProxyMethod var10 = (ProxyGenerator.ProxyMethod)var9.next();
            if (var5 == var10.returnType) {
                ArrayList var11 = new ArrayList();
                collectCompatibleTypes(var6, var10.exceptionTypes, var11);
                collectCompatibleTypes(var10.exceptionTypes, var6, var11);
                var10.exceptionTypes = new Class[var11.size()];
                var10.exceptionTypes = (Class[])var11.toArray(var10.exceptionTypes);
                return;
            }
        }
    } else {
        var8 = new ArrayList(3);
        this.proxyMethods.put(var7, var8);
    }
    //包装好方法,调用add。 重点是这个add方法  这是谁的add方法?
    ((List)var8).add(new ProxyGenerator.ProxyMethod(var3, var4, var5, var6, var2));
}

实际上,它是MethodNode的add方法:

再向里面点,发现不能定位到对应方法了,只能定位到类里面,但是没关系,因为我们已经知道,到底幕后主使是谁了:

package jdk.internal.org.objectweb.asm.tree;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.TypePath;

public class MethodNode extends MethodVisitor {
    public int access;
    public String name;
    public String desc;
    public String signature;
    public List exceptions;
    public List parameters;
    public List visibleAnnotations;
    public List invisibleAnnotations;
    public List visibleTypeAnnotations;
    public List invisibleTypeAnnotations;
    public List attrs;
    public Object annotationDefault;

没错,从包名,就知道了,代理类生成的底层调用其实是ASM!
ASM是一款强大的操纵二进制class文件的工具包。
如果你了解设计模式,应该知道里面有一种模式叫访问者模式。
ASM内部就是运用了这种模式,暴露一个类的各个部分(比如说参数,方法体等等)来给调用者操作。
上面的类继承了MethodVisitor,我们来看看MethodVisitor的部分方法:
如图:

整体大致流程

CGLIB

JDK的动态代理需要被代理类必须是有实现接口的。
而我们的类没有实现接口的时候怎么办呢?
可以使用cglib

引入pom:


    cglib
    cglib
    3.3.0

public class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Tank.class);
        enhancer.setCallback(new TimeMethodInterceptor());
        Tank tank = (Tank)enhancer.create();
        tank.move();
    }
}

class TimeMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println(o.getClass().getSuperclass().getName());
        System.out.println("before");
        Object result = null;
        result = methodProxy.invokeSuper(o, objects);//调用代理类实例上的proxy方法的父类方法(即实体类TargetObject中对应的方法)
        System.out.println("after");
        return result;
    }
}

class Tank {
    public void move() {
        System.out.println("Tank moving claclacla...");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

cglib产生的动态对象是被代理对象的子类,因此final修饰的class是无法生成的。

扩展

不管是jdk的动态代理还是cglib,其实底层调用都是基于ASM。。。
基于ASM的使用其实都是基于API的,还有更强大的一种:instrument ,它是JDK自带的,可以在class被装载前进行拦截,对其进行字节码修改。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/351414.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号