目录

0 概述

0.1 CGLIB包结构

1 使用CGLIB实现动态代理

1.1 CGLIB代理相关的类

1.2 CGLIB动态代理的基本原理

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

1.3.1 实现MethodInterceptor接口

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

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

2 回调过滤器CallbackFilter

3 CGLIB对Mixin的支持

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

5 使用CGLIB动态生成Bean


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) throwsThrowable {

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) throwsThrowable {

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) throwsThrowable {

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

MixinByCGLIBMixinByCGLIB

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.classfalse);

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

BeanGeneratorByCGLIBBeanGeneratorByCGLIB

1d39cfaa

本篇学习文档参考于:

http://jnb.ociweb.com/jnb/jnbNov2005.html

http://wenku.baidu.com/view/3f92297c27284b73f24250b9.html

http://www.cnblogs.com/icejoywoo/

http://www.blogjava.net/calvin/archive/2005/11/28/21741.html

http://m635674608.iteye.com/blog/1435221
等其他高手博客提供的资料。

CGLIB代理到底是个什么东西?这是一篇最全的CGLIB大全相关推荐

  1. aop实现原理-动态代理CGLib代理

    那接下来的话,那咱们Spring当中,这个AOP,咱们先说概念,咱们先不写具体代码,咱们就是聊,聊Spring的AOP,Spring能帮我们干啥呢,我告诉你,Spring他作为对象的容器,Spring ...

  2. java 笔记(3) —— 动态代理,静态代理,cglib代理

    0.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口. 代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常会存 ...

  3. 手动使用cglib代理(了解)

    这个你学会了将来也没啥机会用,将来你要玩AOP,学会了也只是得瑟一下说来手写一个AOP,你看看我是否厉害,你不明白太阳是7个颜色构成的,也不影响你晒太阳,然后呢,AOP这个代码呢,咱们再来一个User ...

  4. Spring的@Configuration使用cglib代理的效果和我自己写的简单实现

    下面的代码,照着复制就能跑起来 今天看了下Spring的@Configuration,即java类配置bean,(这个spring3的新功能,虽然现在已经spring5了,但是这种配置bean的方式也 ...

  5. java代理(静态代理和jdk动态代理以及cglib代理)

    说到代理,脑袋中浮现一大堆代理相关的名词,代理模式,静态代理,jdk代理,cglib代理等等. 记忆特别深刻的是,一次面试中,一位面试官问我,spring的AOP核心采用的设计模式是什么什么模式,阅读 ...

  6. Spring源码深度解析(郝佳)-学习-jdk代理-cglib代理

    在java中目前主要使用的是jdk代理和cglib代理,这两种代理是Spring AOP的精髓所在,不过在理解Spring AOP之前,先来看看这两种代理的使用. 1. jdk代理使用示例 创建业务接 ...

  7. Spring原理学习(七)JDK动态代理与CGLIB代理底层实现

    AOP 底层实现方式之一是代理,由代理结合通知和目标,提供增强功能. 除此以外,aspectj 提供了两种另外的 AOP 底层实现: 第一种是通过 ajc 编译器在编译 class 类文件时,就把通知 ...

  8. Java动态代理与Cglib代理

    为什么80%的码农都做不了架构师?>>>    最近又继续回来死磕Spring源码,以前看的也忘得差不多了,这次先把Spring使用的动态代理cglib看了一下,打好基础知识. cg ...

  9. 基于Spring AOP的JDK动态代理和CGLIB代理

    一.AOP的概念  在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的 ...

最新文章

  1. Android中SQLite的使用
  2. elasticsearch 后置过滤器(Post Filter)
  3. malloc 背后的系统知识(虚拟内存地址)
  4. npm install 报错 npm WARN tar ENOENT: no such file or directory, open... 解决方式
  5. 中以什么开头仅可注释单行_Python从入门到精通第006课--注释与变量
  6. Windows Socket 编程_ 简单的服务器/客户端程序
  7. 重构职场竞争力之测试跨界思维
  8. db2嵌套查询效率_详解oracle嵌套循环及实例说明
  9. oracle 修改字段长度_Oracle字段长度引起的思考length()和lengthb()
  10. python中capitalize()函数的用法
  11. 17. 使用“swap技巧”除去多余得容量
  12. php $stomp write byte message,PHP通过Stomp协议与,ActiveMQ,通信所遇到的问题
  13. 云计算和虚拟化都要用到的核心技术 VXLAN 网络,你掌握了吗?
  14. Litestar4D道路照明设计
  15. 手机上php文件用什么打开方式,php是什么文件格式 php文件打开方法【图文】
  16. 错误: 找不到符号 符号: 类 ActivityMainBindingImpl
  17. 【mcuclub】MQ系列气体传感器
  18. 双线一柱变色MACD指标
  19. 在否定句和疑问句使用have动词_26
  20. 岛屿周长c语言,岛屿的周长 --leetcode刷题,golang实现

热门文章

  1. springboot 读取bootStrap.properties流程
  2. 调度流程图_Flink 实现Locality 模式调度
  3. java date sql和_Java.util.date 与 java.sql.date区别和转换
  4. 二叉树的基本操作_二叉树的遍历
  5. c语言 链表 库,玩转C链表
  6. apache php 调优_Apache的性能优化(二)
  7. linux远程访问及控制
  8. 扩展方法必须在非泛型静态类中定义_第11篇:Cython面向对象编程--扩展类的实例化...
  9. python 显示html_如何使用python在本地显示带有html表单的网...
  10. matlab 测量矩阵,急求一个测量矩阵采用分块多项式矩阵时怎样引用的代码!!!