Java 动态代理
JDK 动态代理
jdk 提供了动态代理的 API:
Interface proxy = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, new DynamicProxyHandler(targetObject));
- targetObject 为要被代理的目标对象
- proxy 为目标对象的代理对象
- DynamicProxyHandler 为 InvocationHandler 接口的实现类
如下:
class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(final Object proxied) {
this.proxied = proxied;
}
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
System.out.println("proxy: " + proxy.getClass().getName() + ", method:" + method.getName() + ", args: " + args);
return method.invoke(proxied, args);
}
}
当目标对象的方法被调用时,会先调用到 InvocationHandler 的 invoke 方法中,我们可以在这里对原有方法进行增强等逻辑.
CGLib 动态代理
CGLib (Code Generation Library) 是一个字节码工具库,被用在很多的 Java 框架里,如 Hibernate 或者 Spring,
该字节码工具允许在程序的编译阶段之后操作和创建 class.
CGLib - 字节码生成库是一个生成和转换字节码的高级APi, 它被用于 AOP, testing,data access frameworks 来生成动态代理对象
以及拦截字段访问.
CGLib 和 ASM 字节码库之间的关系如下:
CGLib 库组成方式如下:
- core: low-level 的字节码操作类,大部分都与 ASM 有关.
- transform: 在运行时或构建时用于类文件转换的类.
- proxy: 用于代理的创建及方法拦截的类.
- reflect: 用于更快反射和 C# 样式委托的类
- util: 工具类
- beans: JavaBean 相关的工具
官方文档对其的描述是:
本质上,它动态生成一个子类来复写被代理对象的 non-final 方法,并且连接到用于回调到用户定义的拦截器的勾子.
它比JDK 动态代理的方法更快.
常用方法:
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(PersonService.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(final Object o, final Method method, final Object[] args, final MethodProxy proxy) throws Throwable {
if (method.getName().equals("sayHello")) {
return "hello, kongkong, my kong";
}
return proxy.invokeSuper(o, args);
}
});
PersonService personService = (PersonService) enhancer.create();
String ret = personService.sayHello();
CGLib还有更多强大的功能,如,Bean Creator, Bean Copier 等,大家感兴趣可以参考上面的文档.
对比
- JDK 代理只能对接口的实现类生成代理,而CGLib不需要
- CGLib 不能代理 final 修饰的类(因为CGLib原理是继承,final的类是无法继承的)
- 效率方面:
----创建代理对象的效率: JDK代理 > CGLib
----执行效率:JDK代理 < CGLib
因为 JDK代理是通过反射机制实现,而 CGLib使用字节码处理框架,通过修改字节码生成子类.
文章目录
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。