一、概述

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


cglib常用api_方法调用cglib常用api_方法调用_02


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

View Code

 

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


cglib常用api_方法调用cglib常用api_方法调用_02


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​​ 修饰的类。示例如下所示:


cglib常用api_方法调用cglib常用api_方法调用_02


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()​​ 来创建类的字节码,然后使用字节码加载完成后的类动态生成代理对象。

  结果如下所示:


cglib常用api_方法调用cglib常用api_方法调用_02


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

  ​​InvocationHandler​​ 即 ​​net.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 Exception​​ ,​​loadObject()​​ 方法会在第一次被代理类的方法调用时触发,它返回一个被代理类的对象,这个对象会被存储起来然后负责所有被代理类方法的调用。

  适用于被代理类或者代理类的对象的创建比较麻烦,且不确定它是否会被使用。​​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​​ 的子类(该子类实现的转换方法中直接使用实例的 ​​Getter​​ 和 ​​Setter​​ 方法),拷贝速度极快(​​BeanCopier​​ 属性拷贝比直接的 ​​Setter​​、​​Getter​​ 稍慢,原因在于首次需要动态生成 ​​BeanCopier​​ 的子类,一旦子类生成完成之后就和直接调用 ​​Setter​​、​​Getter​​ 效率一致,但是效率远远高于其他使用反射的工具类库)。示例如下所示:

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 下标的新概念。通过数组存储 ​​method​​,​​constructor​​ 等 ​​class​​ 信息,从而将原先的反射调用,转化为 ​​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

  从计数器的输出结果可以看到:即使实例化了 ​​PictureAlbum​​,​​pictureContentList​​ 的赋值只有在调用它的时候,才会通过 ​​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