cglib的Enhancer和Callback的使用详解
发布时间: 2023-12-31 17:15:18 阅读量: 71 订阅数: 41
# 1. 简介
## 1.1 什么是cglib
Cglib(Code Generation Library)是一个基于字节码生成的动态代理库,它可以在运行时生成指定类的子类,并覆写其中的方法,实现代理功能。与Java的动态代理(基于接口)相比,Cglib可以对类进行代理,包括没有实现任何接口的类。它通过生成目标类的子类来完成代理,因此需要依赖于底层的字节码技术。
Cglib被广泛应用于AOP(面向切面编程)框架、ORM(对象关系映射)框架等领域,提供了更加灵活和强大的功能。
## 1.2 Enhancer的作用和使用方式
Enhancer是Cglib库中的一个核心类,用于创建代理对象。它通过设置被代理类、回调对象和方法过滤器来生成代理类实例。
使用Enhancer创建代理对象的步骤如下:
1. 创建Enhancer对象:`Enhancer enhancer = new Enhancer();`
2. 设置被代理类:`enhancer.setSuperclass(TargetClass.class);`
3. 设置回调对象:`enhancer.setCallback(callback);`
4. 执行代理操作:`TargetClass proxy = (TargetClass) enhancer.create();`
Enhancer通过字节码技术实现了对被代理类的子类生成,并在子类中覆写了目标方法,在方法中进行回调操作。
## 1.3 Callback的概念和分类
在Cglib中,Callback(回调)是用于在生成的代理类的方法中插入用户自定义逻辑的接口。Cglib提供了多种类型的Callback,可以根据需求选择不同的实现方式。
常见的Callback类型包括:
- NoOp:空回调,不对方法进行任何处理;
- FixedValue:固定返回值回调,在方法调用时返回一个固定的值;
- MethodInterceptor:方法拦截器回调,在方法调用前后进行拦截和处理;
- LazyLoader:懒加载回调,在方法调用时进行懒加载操作。
通过合理选择和组合Callback,可以实现不同的代理功能和行为。在接下来的章节中,我们将详细介绍每种Callback的用法和实例。
### 2. Enhancer的基本用法
在使用cglib进行代理操作时,首先需要创建一个Enhancer对象。Enhancer对象是cglib中的主要类,负责生成代理对象。其基本用法如下:
```java
Enhancer enhancer = new Enhancer(); // 创建Enhancer对象
enhancer.setSuperclass(TargetClass.class); // 设置被代理类
enhancer.setCallback(callback); // 设置回调对象
enhancer.setCallbackFilter(filter); // 设置方法过滤器
TargetClass proxy = (TargetClass) enhancer.create(); // 创建代理对象
```
2.1 创建Enhancer对象
在创建Enhancer对象时,我们可以通过`new Enhancer()`来实例化对象。
2.2 设置被代理类、回调对象和方法过滤器
通过调用`setSuperclass()`方法来设置被代理类。需要注意的是,被代理类必须是非final、非枚举、非接口的普通Java类。
回调对象是指当代理对象中的方法被调用时,cglib会将调用委托给回调对象来执行相应的操作。回调对象可以是实现了`Callback`接口的任意类。
方法过滤器是用来过滤被代理类中的方法,可以通过`setCallbackFilter()`方法设置。方法过滤器是一个实现了`CallbackFilter`接口的类,并且需要重写`accept()`方法来决定哪些方法需要被代理。
2.3 执行代理操作
通过调用`enhancer.create()`方法来创建代理对象。生成的代理对象会继承被代理类,并重写被代理类中的非final方法。代理对象可以调用被代理类中的原始方法,同时也可以通过回调对象实现其他的操作。
总结:Enhancer的基本用法包括创建Enhancer对象、设置被代理类、回调对象和方法过滤器,最后执行代理操作生成代理对象。
### 3. Callback的基本类型
在使用Enhancer创建代理对象时,我们需要指定一个Callback对象来对方法的调用进行处理。Callback是一个接口,定义了不同的回调策略,用于对被代理类的方法进行增强或处理。Enhancer中提供了几种常用的Callback类型,下面依次进行介绍。
#### 3.1 NoOp
NoOp是Enhancer中的一个默认Callback类型,其实现了Callback接口但没有做任何处理,直接返回默认值。当我们不需要对被代理类的方法进行任何增强或处理时,可以使用NoOp作为Callback。
下面是一个使用NoOp的示例代码:
```java
public class NoOpSample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyClass.class);
enhancer.setCallback(NoOp.INSTANCE);
MyClass proxy = (MyClass) enhancer.create();
proxy.method1();
proxy.method2();
}
}
class MyClass {
public void method1() {
System.out.println("Method 1");
}
public void method2() {
System.out.println("Method 2");
}
}
```
输出结果为:
```
Method 1
Method 2
```
在上面的示例中,我们通过Enhancer创建了一个代理对象,并将NoOp作为Callback对象进行设置。当我们调用代理对象的方法时,NoOp直接返回了默认值,不做任何处理。
#### 3.2 FixedValue
FixedValue是Enhancer提供的另一个Callback类型,它可以让代理对象的方法总是返回一个固定的值。这在某些场景下非常有用,例如缓存代理,在一定时间内将相同的方法调用结果缓存起来,避免重复计算。
下面是一个使用FixedValue的示例代码:
```java
public class FixedValueSample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyClass.class);
enhancer.setCallback((FixedValue) () -> "Fixed Value");
MyClass proxy = (MyClass) enhancer.create();
String result1 = proxy.method1();
String result2 = proxy.method2();
System.out.println("Result 1: " + result1);
System.out.println("Result 2: " + result2);
}
}
class MyClass {
public String method1() {
return "Method 1";
}
public String method2() {
return "Method 2";
}
}
```
输出结果为:
```
Result 1: Fixed Value
Result 2: Fixed Value
```
在上面的示例中,我们使用了一个Lambda表达式将FixedValue回调对象设置为代理对象的Callback。无论调用代理对象的哪个方法,返回的结果都是固定的"Fixed Value"。
#### 3.3 MethodInterceptor
MethodInterceptor是Enhancer中最常用的Callback类型,它可以对被代理类的方法进行拦截和增强。通过MethodInterceptor,我们可以在调用被代理类的方法前后执行自定义的逻辑。
下面是一个使用MethodInterceptor的示例代码:
```java
public class MethodInterceptorSample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyClass.class);
enhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> {
System.out.println("Before method: " + method.getName());
Object result = proxy.invokeSuper(obj, args1);
System.out.println("After method: " + method.getName());
return result;
});
MyClass proxy = (MyC
```
0
0