如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习【Spring AOP基础之一】

  由于Java动态代理Proxy.newProxyInstance()的时候会发现其参数类型是ClassLoader classLoader, Class<?>[] interface, InvocationHandler handler, 只支持根据接口实现代理类,如果所有代码都是自己掌控,当然没有问题。所有的业务逻辑均抽象出接口,然后所有的业务类实现接口,这样所有的业务类均可以使用Java动态代理作为AOP编程的底层支持;但是,假设如果我们想要给一个外部依赖的类添加AOP,并且外部的类并没有实现接口,此时Java动态代理就无能为力了,此时就需要CgLib出场了。

  业务逻辑类(无接口实现)

public class EasyClass {
public void easyMethod() {
System.out.println("这是一个非常简单的方法");
}
}

  如果想要使用CgLib给该业务逻辑类创建代理,并且在业务方法的前后等位置增加一些处理逻辑,需要实现net.sf.cglib.proxy.MethodInterceptor接口,并且重写它的intercept方法(代理类中额外的逻辑实现需要在这个函数中实现,是否调用原有类中的方法也需要在这里体现),下面简单在原有方法前后增加一些逻辑;

public class EasyIntercepter implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before");
Object result = proxy.invokeSuper(obj, args);
System.out.println("after");
return result;
}
}

  接下来使用net.sf.cglib.proxy.Enhancer生成相应的代理类即可

public class EasyProxyTest {
public static void main(String[] args) { EasyClass easyClass = (EasyClass)Enhancer.create(
EasyClass.class,
null, new EasyIntercepter() );
easyClass.easyMethod(); //another method
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(EasyClass.class);
enhancer.setCallback(new EasyIntercepter());
((EasyClass)enhancer.create()).easyMethod();
}
}

  输出内容如下:

  从输出内容来看,已经简单的在原有的业务方法前后添加的处理逻辑,所以这个技术就可以用来当做AOP底层生成的技术之一,Spring AOP也正是用这个技术来生成,当配置文件中启用了cglib生成代理类,或者是需要代理的对象没有实现接口,Spring均会使用cglib生成代理类。但是需要使用maven或者gradle引入cglib的引用。

  其方法应该类似于JDK动态代理。该方法是生成原有类的子类,并使用MethodInterceptor截取每个方法的调用。

  将上面生成的代理类反向编译如下:

import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature; public class EasyClass$$EnhancerByCGLIB$$48da2939 extends EasyClass implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$easyMethod$0$Method;
private static final MethodProxy CGLIB$easyMethod$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy; static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("net.sf.cglib.proxy.EasyClass$$EnhancerByCGLIB$$48da2939");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
CGLIB$easyMethod$0$Method = ReflectUtils.findMethods(new String[]{"easyMethod", "()V"}, (var1 = Class.forName("net.sf.cglib.proxy.EasyClass")).getDeclaredMethods())[0];
CGLIB$easyMethod$0$Proxy = MethodProxy.create(var1, var0, "()V", "easyMethod", "CGLIB$easyMethod$0");
} final void CGLIB$easyMethod$0() {
super.easyMethod();
} public final void easyMethod() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
} if(var10000 != null) {
var10000.intercept(this, CGLIB$easyMethod$0$Method, CGLIB$emptyArgs, CGLIB$easyMethod$0$Proxy);
} else {
super.easyMethod();
}
} final boolean CGLIB$equals$1(Object var1) {
return super.equals(var1);
} public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
} if(var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
return var2 == null?false:((Boolean)var2).booleanValue();
} else {
return super.equals(var1);
}
} final String CGLIB$toString$2() {
return super.toString();
} public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
} return var10000 != null?(String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy):super.toString();
} final int CGLIB$hashCode$3() {
return super.hashCode();
} public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
} if(var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return var1 == null?0:((Number)var1).intValue();
} else {
return super.hashCode();
}
} final Object CGLIB$clone$4() throws CloneNotSupportedException {
return super.clone();
} protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
} return var10000 != null?var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy):super.clone();
} public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -1577766638:
if(var10000.equals("easyMethod()V")) {
return CGLIB$easyMethod$0$Proxy;
}
break;
case -508378822:
if(var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case 1826985398:
if(var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1913648695:
if(var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1984935277:
if(var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
} return null;
} public EasyClass$$EnhancerByCGLIB$$48da2939() {
CGLIB$BIND_CALLBACKS(this);
} public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
} public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
} private static final void CGLIB$BIND_CALLBACKS(Object var0) {
EasyClass$$EnhancerByCGLIB$$48da2939 var1 = (EasyClass$$EnhancerByCGLIB$$48da2939)var0;
if(!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if(var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if(CGLIB$STATIC_CALLBACKS == null) {
return;
}
} var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
} } public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
EasyClass$$EnhancerByCGLIB$$48da2939 var10000 = new EasyClass$$EnhancerByCGLIB$$48da2939();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
} public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
EasyClass$$EnhancerByCGLIB$$48da2939 var10000 = new EasyClass$$EnhancerByCGLIB$$48da2939();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
} public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
EasyClass$$EnhancerByCGLIB$$48da2939 var10000 = new EasyClass$$EnhancerByCGLIB$$48da2939;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
} public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
} return var10000;
} public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
default:
}
} public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0};
} public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
} static {
CGLIB$STATICHOOK1();
}
}

  

  上述方法中CGLIB$CALLBACK_0就是设置的callback函数,及实现的MethodInceptor接口的逻辑类,所以当调用easyMethod的时候,如果代理类中存在实现MethodInceptor接口的逻辑类,调用其intercept方法,其实这个地方的原理和JDK动态代理有些相似。

  反编译的方法是git clone cglib的工程文件,找到Enhancer类中创建代理类byte[]的位置,将byte[]数组写成.class文件,然后反编译.class文件。因为和JDK动态代理一样,运行时动态生成类都是动态生成byte[]类结构,然后通过defineClass加载到虚拟机中进一步得到对象。

  目前不知道如何从一个class类型得到其byte[]文件,所以只能采取上面的方法;关于这个我查阅到两个相关问题,感觉没有很简单的方法,大多回答是基于已有.class文件,但是这里只有动态的class类型,并没有生成.class文件。

  https://stackoverflow.com/questions/7980133/converting-a-given-class-lets-say-java-lang-object-to-a-byte-array-is-it-po

  https://stackoverflow.com/questions/2036108/convert-class-object-to-bytes

CgLib动态代理学习【Spring AOP基础之一】的更多相关文章

  1. aop学习总结二------使用cglib动态代理简单实现aop功能

    aop学习总结二------使用cglib动态代理简单实现aop功能 模拟业务需求: 1.拦截所有业务方法 2.判断用户是否有权限,有权限就允许用户执行业务方法,无权限不允许用户执行业务方法 (判断是 ...

  2. java:struts框架2(方法的动态和静态调用,获取Servlet API三种方式(推荐IOC(控制反转)),拦截器,静态代理和动态代理(Spring AOP))

    1.方法的静态和动态调用: struts.xml: <?xml version="1.0" encoding="UTF-8"?> <!DOCT ...

  3. 【Java EE 学习 51】【Spring学习第三天】【cglib动态代理】【AOP和动态代理】【切入点表达式】

    一.cglib动态代理 1.简介 (1)CGlib是一个强大的,高性能,高质量的Code生成类库.它可以在运行期扩展Java类与实现Java接口. (2) 用CGlib生成代理类是目标类的子类. (3 ...

  4. 从动态代理到Spring AOP(中)

    一.前言 上一章节主要介绍了JDK动态代理和CGLIB动态代理:https://www.cnblogs.com/GrimMjx/p/11194283.html 这一章主要结合我们之前学习的动态代理的基 ...

  5. java中代理,静态代理,动态代理以及spring aop代理方式,实现原理统一汇总

    若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. ...

  6. 从动态代理到Spring AOP(上)

    一.前言 虽然平时日常开发很少用到动态代理,但是动态代理在底层框架等有着非常重要的意义.比如Spring AOP使用cglib和JDK动态代理,Hibernate底层使用了javassit和cglib ...

  7. 反射实现 AOP 动态代理模式(Spring AOP 的实现原理)

    枚举 在某些情况下,一个类的对象是有限而且固定的,比如季节类,它只有4个对象.这种实例有限而且固定的类,在Java里被称为枚举类. 枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编 ...

  8. 反射实现 AOP 动态代理模式(Spring AOP 的实现 原理)

    好长时间没有用过Spring了. 突然拿起书.我都发现自己对AOP都不熟悉了. 其实AOP的意思就是面向切面编程. OO注重的是我们解决问题的方法(封装成Method),而AOP注重的是许多解决解决问 ...

  9. cglib动态代理(即AOP)

    Computer.java package com.wh.spring_aop; public class Computer { public void playLOL(){ System.out.p ...

随机推荐

  1. 9.Smarty的循环

    1.session循环 目的:循环输出一个二维数组 构造一个二维数组 $towSide = array( array("name"=>"caimuqing" ...

  2. IP协议详解

    Internet地址结构 表示IP地址 目前的IP版本有4和6. 目前最流行的就是IPv4,有十进制和二进制两种表示方法.分别是: 点分四组十进制.每一组范围是[0~255],如:255.255.25 ...

  3. Java 实现FTP上传和下载

    1. 目前网上开源的FTP Client主要有JFTP.FTP4.edtFtpjJ和Apache.FTPClient. 2. jftp地址:http://www.jmethods.com/ 3. ed ...

  4. 如何用快速傅里叶变换实现DFT

    [目标]   如何以 \(O(N \log N)\) 的效率将系数多项式转换为点值多项式. [前置技能]   众所周知,\(x^n=1\)的根有n个,而且它们分别是\(e^{\frac{2*π*i}{ ...

  5. 一大波jQuery事件即将来袭!

    一.jQuery事件 1.focus()元素获得焦点 2.blur()元素失去焦点 3.change() 表单元素的值发生变化(可用于验证用户名是否存在) 4.click() 鼠标单击 5.dbcli ...

  6. TCP简单通讯

    客户端代码: package com.kaige123.net01; import java.io.IOException; import java.io.InputStream; import ja ...

  7. 深入理解Java内部类

         内部类就是定义在一个类中的另外一个类,是一种从属关系.在没有实际了解内部类之前,我始终困惑,为什么要在一个类中定义另外一个类,这不是增加代码结构复杂度么?现在才大致能知道这种设计的优势是大于 ...

  8. A----奇怪的玩意

      题目: 我们的化学生物学家发明了一种新的叫stripies非常神奇的生命.该stripies是透明的无定形变形虫似的生物,生活在果冻状的营养培养基平板菌落.大部分的时间stripies在移动.当他 ...

  9. Android - Fragment (三)不同Fragment之间的通信

    在Fragment的java文件中,可以使用getActivity()来获得调用它的activity, 然后再找到另一个Fragment,进行通信 getActivity().getFragmentM ...

  10. 【Splay】例题

    营业额统计 题目背景 HNOI2002 DAY2 T2 题目描述 Tiger 最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger 拿出了公司 ...