cglib常用api

reference:https://blog.csdn.net/weixin_41427129/article/details/113561980

一、概述

  本文主要讲解的是 CGLIB 的常用 API 及其使用方式。使用的 CGLIB 依赖如下所示:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
View Code

  首先创建接口 CglibSampleInterface 和类 CglibSampleClass,如下所示:

1 public interface CglibSampleInterface {
2     String show(String name);
3 }
4 
5 public class CglibSampleClass {
6     public String show(String name) {
7         return String.format("%s show love to you!", name);
8     }
9 }
View Code

二、API 详解

2.1 Enhancer

  Enhancer 即字节码增强器,它和 JDK 动态代理中的 Proxy 类似,是 CGLIB 中最常用的一个类,既能代理普通的 Java 类,也能代理接口。Enhancer 通过创建一个被代理类的子类来拦截所有的方法调用(包括 Object#toString()Object#hashCode()),但是它不能拦截 final 修饰的方法(如 Object#getClass()),也不能代理 final 修饰的类。示例如下所示:

 1 public class EnhancerClass {
 2     public static void main(String[] args) throws Exception {
 3         // 字节码增强器
 4         Enhancer enhancer = new Enhancer();
 5         // 设置代理类的父类
 6         enhancer.setSuperclass(CglibSampleClass.class);
 7         // 使用 FixedValue,拦截返回值,每次返回固定值 "Robin walk to you!"
 8         enhancer.setCallback((FixedValue) () -> "Robin walk to you!");
 9 
10         // 创建代理对象
11         CglibSampleClass sampleClass = (CglibSampleClass) enhancer.create();
12 
13         System.out.println(sampleClass.show("Robin"));
14         System.out.println(sampleClass.show("Nami"));
15         System.out.println(sampleClass.toString());
16 
17         // 无法对 final 修饰的 getClass() 方法进行拦截
18         System.out.println(sampleClass.getClass());
19         // 因为 hashCode() 需要返回的是 Number 类型,但是 FixedValue 返回值是 String 类型,无法实现类型转换,故会抛出异常
20         System.out.println(sampleClass.hashCode());
21     }
22 }
View Code

  上述示例使用 FixedValue() 拦截所有的方法调用(包括非 final 修饰的 show()toString()hashCode() 方法)并返回相同的值,但是,由于 hashCode() 方法的返回值类型是 int 型,而我们返回的是一个 String,所以才会抛出 ClassCastException 异常。

  此外,create(Class[] argumentTypes, Object[] arguments) 也可创建代理对象,用来匹配被增强类的不同构造方法,第一参数表示构造方法的参数类型,第二个参数表示构造方法的参数值,这两个参数都是数组类型。也可以使用 Enhancer#createClass() 来创建类的字节码,然后使用字节码加载完成后的类动态生成代理对象。

  结果如下所示:

public class EnhancerClass {
    public static void main(String[] args) throws Exception {
        // 字节码增强器
        Enhancer enhancer = new Enhancer();
        // 设置代理类的父类
        enhancer.setSuperclass(CglibSampleClass.class);
        // 使用 FixedValue,拦截返回值,每次返回固定值 "Robin walk to you!"
        enhancer.setCallback((FixedValue) () -> "Robin walk to you!");

        // 创建代理对象
        CglibSampleClass sampleClass = (CglibSampleClass) enhancer.create();

        System.out.println(sampleClass.show("Robin"));
        System.out.println(sampleClass.show("Nami"));
        System.out.println(sampleClass.toString());

        // 无法对 final 修饰的 getClass() 方法进行拦截
        System.out.println(sampleClass.getClass());
        // 因为 hashCode() 需要返回的是 Number 类型,但是 FixedValue 返回值是 String 类型,无法实现类型转换,故会抛出异常
        System.out.println(sampleClass.hashCode());
    }
}
View Code

  代理接口的示例如下所示,结果与上面的相同。

 1 public class EnhancerInterface {
 2     public static void main(String[] args) throws Exception {
 3         Enhancer enhancer = new Enhancer();
 4 
 5         // 设置被代理的接口
 6         enhancer.setInterfaces(new Class[]{CglibSampleInterface.class});
 7 
 8         enhancer.setCallback((FixedValue) () -> "Robin walk to you!");
 9 
10         CglibSampleInterface cglibSampleInterface = (CglibSampleInterface) enhancer.create();
11 
12         System.out.println(cglibSampleInterface.show("Robin"));
13         System.out.println(cglibSampleInterface.show("Nami"));
14         System.out.println(cglibSampleInterface.toString());
15         System.out.println(cglibSampleInterface.getClass());
16         System.out.println(cglibSampleInterface.hashCode());
17     }
18 }

2.2 Callback

  Callback 即回调,其接口如下所示,是一个标识接口(不含任何方法)。它的回调时机是被代理类的方法被调用的时候,即被代理类的方法被调用时,Callback 的实现逻辑就会被调用。此外,可通过 Enhancer#setCallback()Enhancer#setCallbacks() 设置 Callback若设置了多个 Callback,则会按照设置的顺序进行回调。CGLIB 提供了以下几种 Callback 的子类:

1 package net.sf.cglib.proxy;
2 
3 public interface Callback {
4 }
  • NoOp
  • FixedValue
  • InvocationHandler
  • MethodInterceptor
  • Dispatcher
  • LazyLoader
2.2.1 NoOp

  NoOp 即 No Operation,不做任何操作,该回调实现只是简单地将方法调用委托给被代理类的原始方法,即不加任何操作地调用原始类的原始方法,因此,该回调实现也不能做接口代理。实例如下所示:

public class NoOpDemo {
    public static void main(String[] args) throws Exception {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CglibSampleClass.class);

        // 设置 Callback 回调为 NoOp
        enhancer.setCallback(NoOp.INSTANCE);

        CglibSampleClass sampleClass = (CglibSampleClass) enhancer.create();
        System.out.println(sampleClass.show("Robin"));
    }
}

// 结果如下所示:
Robin show love to you!
 
2.2.2 FixedValue

  FixedValue 即固定值。它提供了一个 loadObject() 方法并返回一个原方法调用想要的固定结果。此外,该 Callback 中看不到任何原方法的信息,也就没有调用原方法的逻辑。需要注意的是,loadObject() 方法的返回值并不能转换成原方法的返回值类型,则会抛出类型转换异常 (ClassCastException)。示例即前面两个 Enhancer 的 Demo。

2.2.3 InvocationHandler

  InvocationHandlernet.sf.cglib.proxy.InvocationHandler,它和 JDK 动态代理中 java.lang.reflect.InvocationHandler 的功能类似,同样也提供了如下的一个方法:

Object invoke(Object proxy, Method method, Object[] objects)
 
  • 1

  不过需要注意的是,所有对 proxy 对象的方法调用都会被委托给同一个 InvocationHandler,所以可能会导致无限循环 (因为 invoke 中调用的任何被代理类的方法,均会重新代理到 invoke() 中)

public class InvocationHandlerDeadLoopDemo {
    public static void main(String[] args) throws Exception {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CglibSampleClass.class);

        // 设置 Callback 的子类 InvocationHandler
        enhancer.setCallback(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
            	// 错误做法,会重新调用 InvocationHandler 的 invoke()
                // return method.invoke(proxy, objects); 
                
                if (!Objects.equals(method.getDeclaringClass(), Object.class) && Objects.equals(String.class, method.getReturnType())) {
                    return "Nami fall in love!";
                }
                return "No one fall in love with you!";
            }
        });

        CglibSampleClass sampleClass = (CglibSampleClass) enhancer.create();
        System.out.println(sampleClass.show("Robin"));
    }
}

// 结果如下所示:
Nami fall in love!
 
2.2.4 MethodInterceptor

  MethodInterceptor,即方法拦截器,它可以实现类似于 AOP 编程中的环绕增强(Around Advice)。它只有一个方法:

public Object intercept(Object proxy, // 代理对象
						java.lang.reflect.Method method, // 方法
						Object[] args, // 方法参数
						MethodProxy methodProxy // 方法代理
						) throws Throwable
 

  设置了 MethodInterceptor 后,代理类的所有方法调用都会转而执行这个接口中的 intercept 方法而不是原方法。若需要在 intercept 方法中执行原方法,有以下两种方式:

  • 使用参数method 基于代理对象 proxy 进行反射调用,但是使用方法代理 methodProxy 效率会更高(methodProxy 基于整数数字的索引来直接调用方法)。
  • 使用 MethodProxy 调用 invokeSuper() 执行原方法,这种方式效率更好,推荐使用这种方式。

  需要注意的是,使用 MethodProxy#invokeSuper() 相当于通过方法代理直接调用原类的对应方法,若调用 MethodProxy#invoke() 会进入死循环导致爆栈,原因跟 InvocationHandler 差不多。

2.2.5 Dispatcher

  Dispatcher 即分发器,提供了一个 Object loadObject() throws Exception 方法,每次对增强对象进行方法调用都会回调 Dispatcher#loadObject() 方法并返回一个被代理类的对象来调用原方法。Dispatcher 可以类比为 Spring 中的 Prototype 类型。示例如下所示:

public class DispatcherDemo {
    private static final AtomicInteger COUNTER = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {
        // 被代理接口的对象
        CglibSampleInterfaceImpl impl = new CglibSampleInterfaceImpl();

        Enhancer enhancer = new Enhancer();
        enhancer.setInterfaces(new Class[]{CglibSampleInterface.class});
        enhancer.setCallback(new Dispatcher() {
            @Override
            public Object loadObject() throws Exception {
                COUNTER.incrementAndGet();
                // 返回的被代理接口的对象
                return impl;
            }
        });
        CglibSampleInterface cglibSampleInterface = (CglibSampleInterface) enhancer.create();

        System.out.println(cglibSampleInterface.show("Robin"));
        System.out.println(cglibSampleInterface.show("Nami"));
        System.out.println(COUNTER.get());
    }

    private static class CglibSampleInterfaceImpl implements CglibSampleInterface {

        public CglibSampleInterfaceImpl() {
            System.out.println("CglibSampleInterfaceImpl init...");
        }

        @Override
        public String show(String name) {
            return String.format("%s show love to you!", name);
        }
    }
}

// 结果如下所示:
CglibSampleInterfaceImpl init...
Robin show love to you!
Nami show love to you!
2
 

  如输出结果所示,计数器的结果为 2,可以验证该结论:每次调用方法都会回调 Dispatcher 中的实例进行调用。

2.2.6 LazyLoader

  LazyLoader 即懒加载器,它只提供了一个方法 Object loadObject() throws ExceptionloadObject() 方法会在第一次被代理类的方法调用时触发,它返回一个被代理类的对象,这个对象会被存储起来然后负责所有被代理类方法的调用。

  适用于被代理类或者代理类的对象的创建比较麻烦,且不确定它是否会被使用。LazyLoader 可以类比为 Spring 中 Lazy 模式的 Singleton示例如下所示:

public class LazyLoaderDemo {
    private static final AtomicInteger COUNTER = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {
        // 被代理接口的对象
        CglibSampleInterfaceImpl impl = new CglibSampleInterfaceImpl();

        Enhancer enhancer = new Enhancer();
        enhancer.setInterfaces(new Class[]{CglibSampleInterface.class});
        enhancer.setCallback(new LazyLoader() {
            @Override
            public Object loadObject() throws Exception {
                COUNTER.incrementAndGet();
                // 返回被代理接口的对象
                return impl;
            }
        });
        CglibSampleInterface cglibSampleInterface = (CglibSampleInterface) enhancer.create();
        System.out.println(cglibSampleInterface.show("Robin"));
        System.out.println(cglibSampleInterface.show("Nami"));
        System.out.println(COUNTER.get());
    }

    private static class CglibSampleInterfaceImpl implements CglibSampleInterface {

        public CglibSampleInterfaceImpl() {
            System.out.println("CglibSampleInterfaceImpl init...");
        }

        @Override
        public String show(String name) {
            return String.format("%s show love to you!", name);
        }
    }
}

// 结果如下所示:
CglibSampleInterfaceImpl init...
Robin show love to you!
Nami show love to you!
1
 

  如输出结果所示,计数器的结果为 1,可以验证该结论:LazyLoader 中的实例只回调了1次。

2.3 BeanCopier

  BeanCopier 即 JavaBean 属性拷贝器,提供从一个 JavaBean 实例中拷贝属性到另一个 JavaBean 实例中的功能,类型必须完全匹配,属性才能拷贝成功(基本数据类型和其包装类不属于相同类型)。它还提供了一个 net.sf.cglib.core.Converter 转换器回调接口让使用者控制拷贝的过程。

  此外,BeanCopier 内部使用了缓存和基于 ASM 动态生成 BeanCopier 的子类(该子类实现的转换方法中直接使用实例的 GetterSetter 方法),拷贝速度极快BeanCopier 属性拷贝比直接的 SetterGetter 稍慢,原因在于首次需要动态生成 BeanCopier 的子类,一旦子类生成完成之后就和直接调用 SetterGetter 效率一致,但是效率远远高于其他使用反射的工具类库)。示例如下所示:

public class BeanCopierDemo {
	
	// 缓存 BeanCopier 实例,BeanCopier 生成是一个耗时的操作
    private static final Map<String, BeanCopier> CACHE = new ConcurrentHashMap<>();

    public static void main(String[] args) throws Exception {
    
        //这里 useConverter 设置为 false,调用 copy 方法的时候不能传入转换器实例
        BeanCopier beanCopier;
        String key = generateCacheKey(Person.class, Person.class);
        if (CACHE.containsKey(key)) {
            beanCopier = CACHE.get(key);
        } else {
            beanCopier = BeanCopier.create(Person.class, Person.class, false);
            CACHE.put(key, beanCopier);
        }
        
        Person person = new Person();
        person.setId(10086L);
        person.setName("Robin");
        person.setAge(25);
        
        Person newPerson = new Person();
        beanCopier.copy(person, newPerson, null); //这里转换器实例要传 null
        System.out.println(newPerson);
    }

    private static String generateCacheKey(Class<?> source, Class<?> target) {
        return String.format("%s-%s", source.getName(), target.getName());
    }

    @ToString
    @Data
    private static class Person {
        private Long id;
        private String name;
        private Integer age;
    }
}

// 结果如下所示:
BeanCopierDemo.Person(id=10086, name=throwable, age=25)
 

2.4 ImmutableBean

  ImmutableBean 即不可变的 Bean,它可以创建一个对象的包装类,但这个包装类是不可变的,否则会抛出 IllegalStateException 异常,但是可以通过操作底层对象来改变包装类的对象。示例如下所示:

public class ImmutableBeanDemo {

    public static void main(String[] args) throws Exception {
        Person person = new Person();
        person.setName("波雅汉考克");

        Person immutablePerson = (Person) ImmutableBean.create(person);
        System.out.println(immutablePerson.getName());

		// 通过修改底层对象来改变包装类的对象
        person.setName("白星公主");
        System.out.println(immutablePerson.getName());

		// 此处修改了包装类的对象,会抛出异常
        immutablePerson.setName("蕾贝卡");
        System.out.println(immutablePerson.getName());
    }

    @Data
    private static class Person {
        private String name;
    }
}

// 结果如下所示:
波雅汉考克
白星公主
Exception in thread "main" java.lang.IllegalStateException: Bean is immutable
 

2.5 BeanGenerator

  BeanGenerator 即 Bean 生成器,它能够在运行时动态的创建一个JavaBean。可以直接设置父类,生成的 JavaBean 就是父类类型的实例。示例如下所示:

public class BeanGeneratorDemo {

    public static void main(String[] args) throws Exception {
        BeanGenerator beanGenerator = new BeanGenerator();

        // 添加 JavaBean 的属性及其类型
        beanGenerator.addProperty("name", String.class);

        Object target = beanGenerator.create();

        Method setter = target.getClass().getDeclaredMethod("setName", String.class);
        Method getter = target.getClass().getDeclaredMethod("getName");

        // 设置属性的值
        setter.invoke(target, "千鹤");

        System.out.println(getter.invoke(target));
    }
}

// 结果如下所示:
千鹤
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

2.6 BeanMap

  BeanMap 类实现了 JDK 的 java.util.Map 接口,它可以将一个 JavaBean 对象中的所有属性转换为一个 <String, Object> 的Map实例。示例如下所示:

public class BeanMapDemo {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        person.setName("Nami");

        BeanMap beanMap = BeanMap.create(person);

        System.out.println(beanMap);
        System.out.println(beanMap.get("name"));
    }

    @Data
    private static class Person {
        private String name;
    }
}

// 结果如下所示:
{name=Nami}
Nami
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2.7 Mixin

  Mixin 能够将多个接口的多个实现合并到同一个接口的单个实现中。示例如下所示:

public class MixinDemo {

    interface InterfaceFirst {
        String first();
    }

    interface InterfaceSecond {
        String second();
    }

    static class ImplFirst implements InterfaceFirst {
        @Override
        public String first() {
            return "First one";
        }
    }

    static class ImplSecond implements InterfaceSecond {
        @Override
        public String second() {
            return "Second one";
        }
    }

    interface MixinImpl extends InterfaceFirst, InterfaceSecond {

    }

    public static void main(String[] args) throws Exception {

        Mixin mixin = Mixin.create(
                new Class[]{InterfaceFirst.class, InterfaceSecond.class, MixinImpl.class}, // 接口数组
                new Object[]{new ImplFirst(), new ImplSecond()} // 代理对象数组
                );

        MixinImpl mixinImpl = (MixinImpl) mixin;

        System.out.println(mixinImpl.first());
        System.out.println(mixinImpl.second());
    }
}

// 结果如下所示:
First one
Second one
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

2.8 FastClass

  FastClass 就是对 Class 对象进行特定的处理,可以理解为索引类,比如通过数组保存 method 引用,因此 FastClass 引出了一个 index 下标的新概念。通过数组存储 methodconstructorclass 信息,从而将原先的反射调用,转化为 class.index 的直接调用以提高效率,从而体现所谓的 FastClass。此外, 在接口或者代理类的方法比较少的时候,使用 FastClass 进行方法调用有可能比原生反射方法调用 Method#invoke() 的效率高。示例如下所示:

public class FastClassDemo {
    public static void main(String[] args) throws Exception {

        FastClass fastClass = FastClass.create(CglibSampleClass.class);
        FastMethod fastMethod = fastClass.getMethod("show", new Class[]{String.class});

        CglibSampleClass cglibSampleClass = new CglibSampleClass();

        // 使用 FastMethod 进行调用
        System.out.println(fastMethod.invoke(cglibSampleClass, new Object[]{"Robin"}));
        // 获得方法的下标索引 index
        System.out.println(fastMethod.getIndex());
    }
}

// 结果如下所示:
Robin show love to you!
0
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

三、扩展

3.1 LazyLoader 实现延迟加载

public class LazyLoaderExt {

    // 计数器
    private static final AtomicInteger COUNTER = new AtomicInteger(0);

    public static class PictureAlbum {
        private String topic;

        private List<PictureContent> pictureContentList;

        public PictureAlbum() {
            this.topic = "海贼王图片集";
            this.pictureContentList = getPictureContentList();
        }

        private List<PictureContent> getPictureContentList() {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(List.class);

            enhancer.setCallback(new LazyLoader() {
                @Override
                public Object loadObject() throws Exception {
                    List<PictureContent> list = new ArrayList<>();
                    list.add(new PictureContent("Nami"));
                    list.add(new PictureContent("Lufei"));
                    list.add(new PictureContent("波雅汉考克"));
                    COUNTER.getAndIncrement();
                    return list;
                }
            });

            return (List<PictureContent>) enhancer.create();
        }

    }

    // 图片实体
    public static class PictureContent {
        private String name;

        public PictureContent(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    public static void main(String[] args) {
    	// 实例化 PictureAlbum
        PictureAlbum pictureAlbum = new PictureAlbum();
        System.out.println(pictureAlbum.topic);

        System.out.println("COUNTER ==> " + COUNTER.get());

        System.out.println("=====图片名=====");
        for (PictureContent pictureContent : pictureAlbum.pictureContentList) {
            System.out.println(pictureContent.name);
        }

        System.out.println("COUNTER ==> " + COUNTER.get());
    }
}

// 结果如下所示:
海贼王图片集
COUNTER ==> 0
=====图片名=====
Nami
Lufei
波雅汉考克
COUNTER ==> 1
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

  从计数器的输出结果可以看到:即使实例化了 PictureAlbumpictureContentList 的赋值只有在调用它的时候,才会通过 LazyLoader#loadObject 方法去赋值。

3.2 Dispathcer 扩展类的接口

  该示例中有 UserService 类、IMethodInfo 接口以及该接口的实现类 DefaultMethodInfo,在这里,我们通过 CGLIB 创建一个代理类,该代理类的父类是 UserService,且实现了 IMethodInfo 接口,将接口 IMethodInfo 中所有的方法都转发给 DefaultMethodInfo 处理,代理类中的其他方法转发给父类 UserService 处理。

  简而言之,就是对 UserService 进行了增强,使其具有 IMethodInfo 接口中的功能。

public class DispatcherExt {

    public static class UserService {
        public void add() {
            System.out.println("新增用户");
        }

        public void update() {
            System.out.println("更新用户信息");
        }
    }

    // 用来获取方法信息的接口
    public interface IMethodInfo {
        // 获取方法数量
        int methodCount();

        // 获取被代理的对象中方法名称列表
        List<String> methodNames();
    }

    // IMethodInfo 的默认实现
    public static class DefaultMethodInfo implements IMethodInfo {

        private Class<?> targetClass;

        public DefaultMethodInfo(Class<?> targetClass) {
            this.targetClass = targetClass;
        }

        @Override
        public int methodCount() {
            return targetClass.getDeclaredMethods().length;
        }

        @Override
        public List<String> methodNames() {
            return Arrays.stream(targetClass.getDeclaredMethods()).
                    map(Method::getName).
                    collect(Collectors.toList());
        }
    }

    public static void main(String[] args) {
        Class<?> targetClass = UserService.class;
        Enhancer enhancer = new Enhancer();

        // 设置代理的父类
        enhancer.setSuperclass(targetClass);

        // 设置代理需要实现的接口列表
        enhancer.setInterfaces(new Class[]{IMethodInfo.class});

        // 创建一个方法统计器,即 IMethodInfo 的默认实现类
        IMethodInfo methodInfo = new DefaultMethodInfo(targetClass);

        // 创建回调用器列表
        Callback[] callbacks = {
                // 处理 UserService 中所有的方法
                new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        return methodProxy.invokeSuper(o, objects);
                    }
                },
                // 处理 IMethodInfo 接口中的方法
                new Dispatcher() {
                    @Override
                    public Object loadObject() throws Exception {
                        /**
                         * 用来处理代理对象中 IMethodInfo 接口中的所有方法
                         * 所以此处返回的为 IMethodInfo 类型的对象,
                         * 将由这个对象来处理代理对象中 IMethodInfo 接口中的所有方法
                         */
                        return methodInfo;
                    }
                }
        };

        enhancer.setCallbacks(callbacks);
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                // 当方法在 IMethodInfo 中定义的时候,返回 callbacks 中的第二个元素
                return method.getDeclaringClass() == IMethodInfo.class ? 1 : 0;
            }
        });

        Object proxy = enhancer.create();

        //代理的父类是UserService
        UserService userService = (UserService) proxy;
        userService.add();

        //代理实现了IMethodInfo接口
        IMethodInfo mf = (IMethodInfo) proxy;
        System.out.println(mf.methodCount());
        System.out.println(mf.methodNames());
    }
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
 
原文地址:https://www.cnblogs.com/sunupo/p/15497528.html