原创

死磕CGLIB

0 概述

CGLIB基于ASM实现。提供比反射更为强大的动态特性。使用CGLIB可以非常方便的实现的动态代理。

0.1 CGLIB包结构

  • net.sf.cglib.core
    底层字节码处理类。
  • net.sf.cglib.transform
    该包中的类用于class文件运行时转换或编译时转换。
  • net.sf.cglib.proxy
    该包中的类用于创建代理和方法拦截。
  • net.sf.cglib.reflect
    该包中的类用于快速反射,并提供了C#风格的委托。
  • net.sf.cglib.util
    集合排序工具类。
  • net.sf.cglib.beans
    JavaBean工具类。

1 使用CGLIB实现动态代理

1.1 CGLIB代理相关的类

  • net.sf.cglib.proxy.Enhancer
    主要的增强类。
  • net.sf.cglib.proxy.MethodInterceptor
    主要的方法拦截类,它是Callback接口的子接口,需要用户实现。
  • net.sf.cglib.proxy.MethodProxy
    JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用。
cglib是通过动态的生成一个子类去覆盖所要代理类的非final方法,并设置好callback,则原有类的每个方法调用就会转变成调用用户定义的拦截方法(interceptors)。 CGLIB代理相关的常用API如下图所示: net.sf.cglib.proxy.Callback接口在CGLIB包中是一个重要的接口,所有被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口。 net.sf.cglib.proxy.MethodInterceptor能够满足任何的拦截(interception )需要。对有些情况下可能过度。为了简化和提高性能,CGLIB包提供了一些专门的回调(callback)类型:
  • net.sf.cglib.proxy.FixedValue
    为提高性能,FixedValue回调对强制某一特别方法返回固定值是有用的。
  • net.sf.cglib.proxy.NoOp
    NoOp回调把对方法调用直接委派到这个方法在父类中的实现。
  • net.sf.cglib.proxy.LazyLoader
    当实际的对象需要延迟装载时,可以使用LazyLoader回调。一旦实际对象被装载,它将被每一个调用代理对象的方法使用。
  • net.sf.cglib.proxy.Dispatcher
    Dispathcer回调和LazyLoader回调有相同的特点,不同的是,当代理方法被调用时,装载对象的方法也总要被调用。
  • net.sf.cglib.proxy.ProxyRefDispatcher
    ProxyRefDispatcher回调和Dispatcher一样,不同的是,它可以把代理对象作为装载对象方法的一个参数传递。

1.2 CGLIB动态代理的基本原理

CGLIB动态代理的原理就是用Enhancer生成一个原有类的子类,并且设置好callback到proxy, 则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxy的intercept() 函数,如图 在intercept()函数里,除执行代理类的原因方法,在原有方法前后加入其他需要实现的过程,改变原有方法的参数值,即可以实现对原有类的代理了。这似于AOP中的around advice。

1.3 使用MethodInterceptor接口实现方法回调

当对代理中所有方法的调用时,都会转向MethodInterceptor类型的拦截(intercept)方法,在拦截方法中再调用底层对象相应的方法。下面我们举个例子,假设你想对目标对象的所有方法调用进行权限的检查,如果没有经过授权,就抛出一个运行时的异常。 net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用 来实现拦截(intercept)方法的调用。 MethodInterceptor接口只定义了一个方法:
public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;
参数
Object object
是被代理对象,不会出现死循环的问题。参数
java.lang.reflect.Method method
是java.lang.reflect.Method类型的被拦截方法。参数
Object[] args
是被被拦截方法的参数。参数
MethodProxy proxy
是CGLIB提供的MethodProxy 类型的被拦截方法。注意: 1、若原方法的参数存在基本类型,则对于第三个参数Object[] args会被转化成类的类型。如原方法的存在一个参数为int,则在intercept方法中,对应的会存在一个Integer类型的参数。 2、若原方法为final方法,则MethodInterceptor接口无法拦截该方法。

1.3.1 实现MethodInterceptor接口

class MethodInterceptorImpl implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before invoke " + method);Object result = proxy.invokeSuper(obj, args); System.out.println("After invoke" + method);return result; } }
Object result=proxy.invokeSuper(o,args);
表示调用原始类的被拦截到的方法。这个方法的前后添加需要的过程。在这个方法中,我们可以在调用原方法之前或之后注入自己的代码。由于性能的原因,对原始方法的调用使用CGLIB的net.sf.cglib.proxy.MethodProxy对象,而不是反射中一般使用java.lang.reflect.Method对象。

1.4 使用CGLIB代理最核心类Enhancer生成代理对象

net.sf.cglib.proxy.Enhancer中有几个常用的方法:
  • void setSuperclass(java.lang.Class superclass)
    设置产生的代理对象的父类。
  • void setCallback(Callback callback)
    设置CallBack接口的实例。
  • void setCallbacks(Callback[] callbacks)
    设置多个CallBack接口的实例。
  • void setCallbackFilter(CallbackFilter filter)
    设置方法回调过滤器。
  • Object create()
    使用默认无参数的构造函数创建目标对象。
  • Object create(Class[], Object[])
    使用有参数的构造函数创建目标对象。参数Class[] 定义了参数的类型,第二个Object[]是参数的值。
注意:在参数中,基本类型应被转化成类的类型。 基本代码:
public Object createProxy(Class targetClass) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(targetClass); enhancer.setCallback(new MethodInterceptorImpl ()); return enhancer.create(); }
createProxy方法返回值是targetClass的一个实例的代理。

1.5 使用CGLIB继进行动态代理示例

例1:使用CGLIB生成代理的基本使用。
import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class TestMain { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Cglib.class); enhancer.setCallback(new HelloProxy()); Cglib cglibProxy = (Cglib)enhancer.create(); cglibProxy.cglib(); } }
class Cglib{ public void cglib(){ System.out.println("CGLIB");} }
class HelloProxy implements MethodInterceptor{ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Hello"); Object object = proxy.invokeSuper(obj, args); System.out.println("Powerful!"); return object; } }
输出内容:
Hello CGLIB Powerful!
例2:使用CGLIB创建一个Dao工厂,并展示一些基本特性。
public interface Dao { void add(Object o); void add(int i); void add(String s); }
public class DaoImpl implements Dao { @Override public void add(Object o) { System.out.println("add(Object o)");} @Override public void add(int i) { System.out.println("add(int i)");} public final void add(String s) { System.out.println("add(String s)"); } }
public class Proxy implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("拦截前...");// 输出参数类型 for (Object arg : args) { System.out.print(arg.getClass() + ";");} Object result = proxy.invokeSuper(obj, args); System.out.println("拦截后...");return result; } }
public class DaoFactory { public static Dao create() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(DaoImpl.class); enhancer.setCallback(new Proxy()); Dao dao = (Dao) enhancer.create(); return dao; } } public class TestMain { public static void main(String[] args) { Dao dao = DaoFactory.
create
();dao.add(new Object()); dao.add(1); dao.add("1"); } }
输出内容:
拦截前... class java.lang.Object;add(Object o) 拦截后... 拦截前... class java.lang.Integer;add(int i) 拦截后... add(String s)

2 回调过滤器CallbackFilter

net.sf.cglib.proxy.CallbackFilter有选择的对一些方法使用回调。 CallbackFilter可以实现不同的方法使用不同的回调方法。所以CallbackFilter称为"回调选择器"更合适一些。 CallbackFilter中的accept方法,根据不同的method返回不同的值i,这个值是在callbacks中callback对象的序号,就是调用了callbacks[i]。
import java.lang.reflect.Method; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.CallbackFilter; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import net.sf.cglib.proxy.NoOp; public class CallbackFilterDemo { public static void main(String[] args) { // 回调实例数组 Callback[] callbacks = new Callback[] { new MethodInterceptorImpl(), NoOp.
INSTANCE
};// 使用enhancer,设置相关参数。 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(User.class); enhancer.setCallbacks(callbacks); enhancer.setCallbackFilter(new CallbackFilterImpl()); // 产生代理对象 User proxyUser = (User) enhancer.create(); proxyUser.pay(); // 买 proxyUser.eat(); // 吃 }
/** * 回调过滤器类。 */ private static class CallbackFilterImpl implements CallbackFilter { @Override public int accept(Method method) { String methodName = method.getName(); if ("eat".equals(methodName)) { return 1; // eat()方法使用callbacks[1]对象拦截。 } else if ("pay".equals(methodName)) { return 0; // pay()方法使用callbacks[0]对象拦截。 } return 0; } }
 
/** * 自定义回调类。 */ private static class MethodInterceptorImpl implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before invoke " + method);Object result = proxy.invokeSuper(obj, args); // 原方法调用。 System.out.println("After invoke" + method);return result; } } }
class User { public void pay() { System.out.println("买东西");} public void eat() { System.out.println("吃东西");} }
输出结果:
Before invoke public void sjq.cglib.filter.User.pay() pay() After invokepublic void sjq.cglib.filter.User.pay() eat()

3 CGLIB对Mixin的支持

CGLIB的代理包net.sf.cglib.proxy.Mixin类提供对Minix编程的支持。Minix允许多个对象绑定到一个单个的大对象上。在代理中对方法的调用委托到下面相应的对象中。 这是一种将多个接口混合在一起的方式, 实现了多个接口。 Minix是一种多继承的替代方案, 很大程度上解决了多继承的很多问题, 实现和理解起来都比较容易。
import net.sf.cglib.proxy.Mixin; public class MixinDemo { public static void main(String[] args) { //接口数组 Class<?>[] interfaces = new Class[] { MyInterfaceA.class, MyInterfaceB.class }; //实例对象数组 Object[] delegates = new Object[] { new MyInterfaceAImpl(), new MyInterfaceBImpl() }; //Minix组合为o对象。 Object o = Mixin.
create
(interfaces, delegates);MyInterfaceA a = (MyInterfaceA) o; a.methodA(); MyInterfaceB b = (MyInterfaceB) o; b.methodB(); System.out.println("\r\n 输出Mixin对象的结构...");Class clazz = o.getClass(); Method[] methods = clazz.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { System.out.println(methods[i].getName());} System.out.println(clazz);} } interface MyInterfaceA { public void methodA(); } interface MyInterfaceB { public void methodB(); } class MyInterfaceAImpl implements MyInterfaceA { @Override public void methodA() { System.out.println("MyInterfaceAImpl.methodA()");} } class MyInterfaceBImpl implements MyInterfaceB { @Override public void methodB() { System.out.println("MyInterfaceBImpl.methodB()");} }
输出结果:
MyInterfaceAImpl.methodA() MyInterfaceBImpl.methodB() 输出Mixin对象的结构... methodA methodB newInstance class sjq.cglib.mixin.MyInterfaceA
MixinByCGLIB
M
i
x
i
n
B
y
C
G
L
I
B
d1f6261a

4 CGLIB用来对象之间拷贝属性

package sjq.cglib.bean.copy; import net.sf.cglib.beans.BeanCopier; public class PropertyCopyDemo { public static void main(String[] args) { //两个对象 Other other = new Other("test", "1234"); Myth myth = new Myth(); System.out.println(other); System.out.println(myth);//构建BeanCopier,并copy对象的属性值。 BeanCopier copier = BeanCopier.
create
(Other.class, Myth.class, false);copier.copy(other, myth, null); System.out.println(other); System.out.println(myth);} } class Other { private String username; private String password; private int age; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Other(String username, String password) { super(); this.username = username; this.password = password; } @Override public String toString() { return "Other: " + username + ", " + password + ", " + age; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } class Myth { private String username; private String password; private String remark; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "Myth: " + username + ", " + password + ", " + remark; } public void setRemark(String remark) { this.remark = remark; } public String getRemark() { return remark; } }
运行结果如下: Other: test, 1234, 0 Myth: null, null, null Other: test, 1234, 0 Myth: test, 1234, null

5 使用CGLIB动态生成Bean

import java.util.Iterator; import java.util.Map; import java.util.Set; import net.sf.cglib.beans.BeanGenerator; import net.sf.cglib.beans.BeanMap; /** *动态实体bean */ public class CglibBean { /** * 实体Object */ public Object object = null; /** * 属性map */ public BeanMap beanMap = null; public CglibBean() { super(); } @SuppressWarnings("unchecked") public CglibBean(Map<String, Class> propertyMap) { this.object = generateBean(propertyMap); this.beanMap = BeanMap.
create
(this.object);} /** * 给bean属性赋值 * @param property属性名 * @param value值 */ public void setValue(String property, Object value) { beanMap.put(property, value); } /** * 通过属性名得到属性值 * @param property属性名 */ public Object getValue(String property) { return beanMap.get(property); } /** * 得到该实体bean对象。 */ public Object getObject() { return this.object; } /** * 生成Bean * @param propertyMap * @return */ @SuppressWarnings("unchecked") private Object generateBean(Map<String, Class> propertyMap) { BeanGenerator generator = new BeanGenerator(); Set keySet = propertyMap.keySet(); for (Iterator i = keySet.iterator(); i.hasNext();) { String key = (String) i.next(); generator.addProperty(key, (Class) propertyMap.get(key)); } return generator.create(); } } 测试并使用动态Bean import java.lang.reflect.Method; import java.util.HashMap; /** * Cglib测试类 */ public class CglibTest { @SuppressWarnings("unchecked") public static void main(String[] args) throws ClassNotFoundException { // 设置类成员属性 HashMap<String, Class> propertyMap = new HashMap<String, Class>(); propertyMap.put("id", Class.
forName
("java.lang.Integer"));propertyMap.put("name", Class.
forName
("java.lang.String"));propertyMap.put("address", Class.
forName
("java.lang.String"));// 生成动态Bean CglibBean bean = new CglibBean(propertyMap); // 给Bean设置值 bean.setValue("id", new Integer(123)); bean.setValue("name", "454"); bean.setValue("address", "789"); // 从Bean中获取值,当然了获得值的类型是Object System.out.println(">>id=" + bean.getValue("id")); System.out.println(">>name=" + bean.getValue("name")); System.out.println(">>address=" + bean.getValue("address"));// 获得bean的实体Object object = bean.getObject(); // 通过反射查看所有方法名 Class clazz = object.getClass(); Method[] methods = clazz.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { System.out.println(methods[i].getName()); } } }
输出: >>id=123 >>name=454 >>address=789 setId getAddress getName getId setName setAddress class net.sf.cglib.empty.Object
BeanGeneratorByCGLIB
 
正文到此结束
Loading...