CgLib动态代理学习【Spring AOP基础之一】
如果不了解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/2036108/convert-class-object-to-bytes
CgLib动态代理学习【Spring AOP基础之一】的更多相关文章
- aop学习总结二------使用cglib动态代理简单实现aop功能
aop学习总结二------使用cglib动态代理简单实现aop功能 模拟业务需求: 1.拦截所有业务方法 2.判断用户是否有权限,有权限就允许用户执行业务方法,无权限不允许用户执行业务方法 (判断是 ...
- java:struts框架2(方法的动态和静态调用,获取Servlet API三种方式(推荐IOC(控制反转)),拦截器,静态代理和动态代理(Spring AOP))
1.方法的静态和动态调用: struts.xml: <?xml version="1.0" encoding="UTF-8"?> <!DOCT ...
- 【Java EE 学习 51】【Spring学习第三天】【cglib动态代理】【AOP和动态代理】【切入点表达式】
一.cglib动态代理 1.简介 (1)CGlib是一个强大的,高性能,高质量的Code生成类库.它可以在运行期扩展Java类与实现Java接口. (2) 用CGlib生成代理类是目标类的子类. (3 ...
- 从动态代理到Spring AOP(中)
一.前言 上一章节主要介绍了JDK动态代理和CGLIB动态代理:https://www.cnblogs.com/GrimMjx/p/11194283.html 这一章主要结合我们之前学习的动态代理的基 ...
- java中代理,静态代理,动态代理以及spring aop代理方式,实现原理统一汇总
若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. ...
- 从动态代理到Spring AOP(上)
一.前言 虽然平时日常开发很少用到动态代理,但是动态代理在底层框架等有着非常重要的意义.比如Spring AOP使用cglib和JDK动态代理,Hibernate底层使用了javassit和cglib ...
- 反射实现 AOP 动态代理模式(Spring AOP 的实现原理)
枚举 在某些情况下,一个类的对象是有限而且固定的,比如季节类,它只有4个对象.这种实例有限而且固定的类,在Java里被称为枚举类. 枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编 ...
- 反射实现 AOP 动态代理模式(Spring AOP 的实现 原理)
好长时间没有用过Spring了. 突然拿起书.我都发现自己对AOP都不熟悉了. 其实AOP的意思就是面向切面编程. OO注重的是我们解决问题的方法(封装成Method),而AOP注重的是许多解决解决问 ...
- cglib动态代理(即AOP)
Computer.java package com.wh.spring_aop; public class Computer { public void playLOL(){ System.out.p ...
随机推荐
- Chapter 1. Introduce
前言 本书全名是<H.264 and MPEG-4 Video Compression, Video Coding For Next-generation Multimedia>,作者为 ...
- 【原创】源码角度分析Android的消息机制系列(六)——Handler的工作原理
ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 先看Handler的定义: /** * A Handler allows you to send and process {@link Mes ...
- Pycharm直接连接Github
Pycharm可以说是使用Python语言开发者的必备利器.高校学生有学生邮箱就可以免费使用,着实省了我不少银两.附个license图: Git是一个开源的分布式版本控制系统,用以有效.高速的处理从很 ...
- python中json.loads,dumps,jsonify使用
search_info = {'id':132,'user_role':3} print type(search_info) #输出 <type 'dict'> #转为string用dum ...
- JDBC注册驱动
一.Sql server2008 使用sqljdbc4.jar private static String driver = "com.microsoft.sqlserver.jdbc.SQ ...
- string can not be resolved
参考:http://jingyan.baidu.com/article/a17d5285339c828099c8f245.html
- U盘发现器
U盘发现器 package com.lx.io; import java.io.File; import java.io.IOException; import java.util.ArrayList ...
- Oozie安装时放置Mysql驱动包的总结(网上最全)
不多说,直接上干货! 对于在oozie里放置Mysql驱动包的总结 根据网上的参考以及我个人经验安装的使用 (1)放一份到$OOZIE_HOME/libext下 (是 mysql-connector- ...
- 工程经验总结之吹水"管理大境界"
1.个人认为项目管理最核心的能力是预见风险和快速解决风险的能力. 从实践来看,没有百分百的完美计划,任何计划都有出现偏差的可能,或者说计划总是不会按照最初的设定去完美执行的. 项目经理存在的主要价值就 ...
- Multimodal —— 看图说话(Image Caption)任务的论文笔记(一)评价指标和NIC模型
看图说话(Image Caption)任务是结合CV和NLP两个领域的一种比较综合的任务,Image Caption模型的输入是一幅图像,输出是对该幅图像进行描述的一段文字.这项任务要求模型可以识别图 ...