被代理类Person和拦截器PersonProxy
/**
* @author gaokuo
*/
public class Person {
public String eat(){
return (System.currentTimeMillis() & 1) == 1 ? "饱了" : "八成饱";
}
public final String sleep(){
return (System.currentTimeMillis() & 1) == 1 ? "sleeping!" : "呼噜,呼噜~";
}
}
/**
* @author gaokuo
*/
@Slf4j
public class PersonProxy implements MethodInterceptor {
private final Object target;
public PersonProxy(Object target) {
this.target = target;
}
/**
* @param o cglib生成的代理类对象
* @param method 被代理对象的方法
* @param objects 方法参数
* @param methodProxy cglib生成的代理类对象的方法
* @return ~
* @throws Throwable ~
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println();
log.info("拦截方法开始执行===========================================");
log.info("第一个参数Object o o_class:{}",o.getClass().getName());
log.info("第二个参数Method method method_name:{},method:{}",method.getName(),method);
log.info("第四个参数MethodProxy methodProxy methodProxy_name:{},methodProxy:{}",methodProxy.getSuperName(),methodProxy);
//使用methodProxy.invokeSuper会生成FastClass
Object result = methodProxy.invokeSuper(o,objects);
//直接调用被代理方法,不会生成FastClass
//Object result = method.invoke(target,objects);
log.info("方法执行结果为:{}",result);
log.info("拦截方法结束执行===========================================");
return result;
}
}
所需依赖
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.0-alpha5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.0-alpha5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
测试,生成类
/**
* @author gaokuo
*/
public class TestCglib {
@Test
public void test1() {
//获取当前项目的根目录,将类生成到项目根目录
String userDir = System.getProperty("user.dir");
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, userDir);
//被代理对象
Person target = new Person();
//拦截器
PersonProxy personCglib = new PersonProxy(target);
//获取 CGLIB 代理对象
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Person.class);
enhancer.setCallback(personCglib);
//可以看到是person的子类,所以final方法无法被加强
Person personProxy = (Person) enhancer.create();
// 调用代理对象的方法
System.out.println(personProxy.eat());
System.out.println(personProxy.sleep());
}
}
输出:
class com.gaokuo.cglib.Person$$EnhancerByCGLIB$$773ecdd5
[main] INFO com.gaokuo.cglib.PersonProxy - 拦截方法开始执行===========================================
[main] INFO com.gaokuo.cglib.PersonProxy - 第一个参数Object o o_class:com.gaokuo.cglib.Person$$EnhancerByCGLIB$$773ecdd5
[main] INFO com.gaokuo.cglib.PersonProxy - 第二个参数Method method method_name:eat,method:public java.lang.String com.gaokuo.cglib.Person.eat()
[main] INFO com.gaokuo.cglib.PersonProxy - 第四个参数MethodProxy methodProxy methodProxy_name:CGLIB$eat$0,methodProxy:net.sf.cglib.proxy.MethodProxy@5acf93bb
[main] INFO com.gaokuo.cglib.PersonProxy - 方法执行结果为:八成饱
八成饱
[main] INFO com.gaokuo.cglib.PersonProxy - 拦截方法结束执行===========================================
呼噜,呼噜~
可以看到,第一个参数o的类型为com.gaokuo.cglib.Person$$EnhancerByCGLIB$$773ecdd5,该类在项目根目录下可以看到。
执行逻辑
首先,personProxy对象的类型为com.gaokuo.cglib.Person$$EnhancerByCGLIB$$773ecdd5,我们调用了它的eat方法:
public final String eat() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$eat$0$Method, CGLIB$emptyArgs, CGLIB$eat$0$Proxy) : super.eat();
}
可以看到,正常var10000不为空的情况下,执行的是拦截器的intercept方法,我们在这个方法内部调用了:
Object result = methodProxy.invokeSuper(o,objects);
这就来到了methodProxy.invokeSuper方法:
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
fci.f2的类型为com.gaokuo.cglib.Person$$EnhancerByCGLIB$$773ecdd5$$FastClassByCGLIB$$6546c77,
不同的methodProxy实例内置了不同的FastClass类(如果是一个代理对象那就是同一个FastClass类),
同一个对象的不同methodProxy实例的fci.i2各不相同,每个数字代表一个方法。下面是fci.f2.invoke方法:
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
773ecdd5 var10000 = (773ecdd5)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
return new Boolean(var10000.equals(var3[0]));
case 1:
return var10000.toString();
case 2:
return new Integer(var10000.hashCode());
case 3:
return var10000.clone();
case 4:
return var10000.newInstance((Callback[])var3[0]);
case 5:
return var10000.newInstance((Callback)var3[0]);
case 6:
return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 7:
return var10000.eat();
.........................省略一堆
case 15:
return var10000.CGLIB$eat$0();
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
比如是调用eat方法开始的话,这里传入的会是15,CGLIB$eat$0()方法只有一行,return super.eat();
然后就到了上面的拦截器方法了,继续往下执行直至结束。
可以看到,整个过程没有用到反射,而是生成了FastClass类,根据方法的签名(一个数值)来调用已经生成的方法,
可见频繁调用的场景下使用该模式效率是高的。