设计模式(四):代理模式之CGLIB动态代理(CGLIB Dynamic Proxy)

基于静态代理和动态代理需要绑定接口的局限性,而对类的代理在某些场景下确实是需要的,所以某些大牛就创造了CGLIB这个动态代理类库。

CGLIB底层是基本ASM字节码处理框架,该库允许在程运行时对字节码进行修改和动态生成新的类。

CGLIB所创建的动态代理对象的性能比JDK所创建的动态代理对象的性能高(大概10倍),但CGLIB在创建代理对象时所花费的时间却比JDK动态代理多(大概8倍)。

对于singleton的代理对象或者具有实例池的代理,因无须频繁创建对象,比较适用CGLIB动态代理技术;反之则适合采用JDK动态代理技术。

CGLIB

CGLIB 生成的动态代理,是在运行期间通过 Java 的反射机制,生成被代理目标类的子类,同时实现了net.sf.cglib.proxy.Factory接口,这个接口是CGLIB自己加入的。

CGLIB 是通过继承实现代理,所以被代理的目标类不能被final关键字修饰,因为final修饰的父类是不能被继承的;目标类的方法不能被final,static,private修饰, final,static的方法不能被重载,否则就不会被拦截, private修饰不能被外部调用。

CGLIB 的核心是MethodInterceptor接口,目标对象的所有方法都会转给MethodInterceptor.intercept()方法来执行,该方法会拦截所有父类方法的调用,同时织入横切逻辑(在该方法里写增强的功能,如加入日志、安全检查等)。

使用步骤

  1. 业务类
  2. 创建MethodInterceptor接口的实现类(我称之为CGLIB工厂类),将目标类对象传入该工厂类的构造方法,新建一个创建代理对象的方法,重写intercept方法,在该方法编写增强功能。
  3. 外部调用时生成CGLIB工厂类的对象,在构造方法里传入被代理的目标类对象,在工厂类对象调用方法创建代理对象并返回。
  4. 代理对象调用目标类的方法。

intercept方法

intercept(Object obj, Method method, Object[] paramArr, MethodProxy methodProxy)方法解析

  1. Object obj:第一个参数表示目标类对象。
  2. Method method:第二个参数为目标为的反射对象。
  3. Object[] objArr:第三个参数为方法的参动入参。
  4. MethodProxy methodProxy:第四个参数为代理类对象。

示例代码

业务类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 不需要实现接口的业务类
*
*/
public class UserService {

public void queryInfo(int id) {
System.out.println("根据ID查询信息。。。 " + id);
}

public final void updateInfo(int id, String name) {
System.out.println("根据ID和名称更新信息 。。。" + id);
}
}

CGLIB拦截类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class CglibInterceptor implements MethodInterceptor {
//被代理的目标类
private Object target;
public CglibInterceptor(Object target) {
this.target = target;
}

//创建代理对象
public Object getInstance(Object obj) {
this.obj = obj;
return getInstance();
}

//创建代理对象
public Object getInstance() {
Enhancer enhancer = new Enhancer();
//指定需要创建子类的父类
enhancer.setSuperclass(this.target.getClass());
//回调方法
enhancer.setCallback(this);
//创建代理对象
return enhancer.create();
}

@Override
public Object intercept(Object obj, Method method, Object[] paramArr, MethodProxy methodProxy) throws Throwable {
System.out.println("transaction begin...");
//执行方法,调的是父类的方法,代理对象是目标对象的子类
methodProxy.invokeSuper(obj, paramArr);
System.out.println("transaction end...");
return null;
}
}

客户端调用

1
2
3
4
5
6
7
8
9
10
11
12
public class CGLIBMain {

public static void main(String[] args) {
//创建目标类对象
UserService userServiceImpl = new UserService();
//自定拦截
CglibInterceptor customizeMethodInterceptor =
new CglibInterceptor(userServiceImpl);
UserService instance = (UserService) customizeMethodInterceptor.getInstance();
instance.queryInfo(11);
}
}

相关参考

动态代理之Cglib浅析
ImportNew CGLIB专题

设计模式(四):代理模式之CGLIB动态代理(CGLIB Dynamic Proxy)

http://blog.gxitsky.com/2018/03/16/DesignPatterns-04-Proxy-Cglib/

作者

光星

发布于

2018-03-16

更新于

2023-06-06

许可协议

评论