JDK动态代理和cglib代理对比

1.JDK动态代理:所要代理的类必须实现了接口。

 

public class JDKProxyFactory implements InvocationHandler{
	private Object targetObject;
	
	public Object createProxyIntance(Object targetObject){
		this.targetObject = targetObject;
		return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), 
				this.targetObject.getClass().getInterfaces(), this);
	}

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {//环绕通知
		PersonServiceBean bean = (PersonServiceBean) this.targetObject;
		Object result = null; 
		if(bean.getUser()!=null){
			//..... advice()-->前置通知
			try {
				result = method.invoke(targetObject, args);
				// afteradvice() -->后置通知
			} catch (RuntimeException e) {
				//exceptionadvice()--> 例外通知
			}finally{
				//finallyadvice(); -->最终通知
			}
		}

		return result;
	}

}

 使用是:

 

                JDKProxyFactory factory = new JDKProxyFactory();
		PersonService service = (PersonService) factory.createProxyIntance(new PersonServiceBean("xxx"));
		service.save("888");

 

2。cglib可实现没有接口的类的代理:

 

package com.fsj.proxy;

import java.lang.reflect.Method;

import com.fsj.service.PersonService;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;


public class CGLIBProxy implements MethodInterceptor{

	private Object targetObject;
	
	public Object createProxyInstance(Object targetObject)
	{
		this.targetObject = targetObject;
		Enhancer enhancer = new Enhancer();//使用cglib的Enhancer		
		//将目标对象的类设置为enhancer的父类,
		//那么enhancer会覆盖目标类中的所有非final的方法,在覆盖方法中加入一些自身的代码
		enhancer.setSuperclass(this.targetObject.getClass());
		//回调自身,前提是必须实现MethodInterceptor接口
		enhancer.setCallback( this);//会回调intercept方法
		//返回代理对象
		return enhancer.create();
	}

	/**
	 * @param proxy 代理对象本身
	 * @param method 拦截到的方法
	 * @param args 方法的所有参数
	 * @param methodProxy 方法的代理对象
	 */
	@Override
	public Object intercept(Object proxy, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		//调用前处理------------advice()------前置通知
		PersonService ps = (PersonService)this.targetObject;
		Object result = null;
		if(ps.getName()!=null)
		{
			
			try {
				result = methodProxy.invoke(targetObject, args);
				//调用后也可以处理------------afteradvice()--------后置通知
			} catch (Exception e) {
				//出错时处理------------exceptionadvice()---------例外通知
				e.printStackTrace();
			}finally
			{
				//出不出错都处理------------finallyadvice()--------最终通知
			}
		}
		
		return result;
	}
}

 

 

使用是:

 

		PersonService ps = new PersonService();
//		ps.setName("fs");		
		CGLIBProxy cglibProxy = new CGLIBProxy();
		PersonService  psProxy = (PersonService)cglibProxy.createProxyInstance(ps);
		psProxy.add();

 

 

 

<think>我们被要求比较JDK动态代理Cglib动态代理的区别。根据提供的引用材料,我们可以从多个维度进行对比。以下是详细的对比分析: 1. **实现原理**: - **JDK动态代理**:基于接口。它使用Java反射机制,在运行时生成一个实现了指定接口的代理类(通常命名为$ProxyN)。代理对象会拦截所有接口方法调用,并将调用转发给InvocationHandler对象处理。 - **Cglib动态代理**:基于继承。它通过操作字节码(使用ASM库)生成目标类的子类作为代理类。代理类重写了目标类的方法,在方法中插入拦截逻辑,因此可以代理没有实现接口的类。 2. **目标类要求**: - **JDK动态代理**:要求目标类必须实现至少一个接口(因为代理类会实现相同的接口)[^1][^3]。 - **Cglib动态代理**:要求目标类不能是final类,且目标方法不能是final(因为需要继承并重写方法)[^2]。 3. **性能对比**: - **生成代理速度**:JDK动态代理在生成代理对象时较快,因为它直接使用反射API;而Cglib在生成代理对象时较慢,因为它需要动态生成字节码[^2]。 - **方法调用速度**:JDK动态代理在方法调用时较慢(因为使用反射调用);Cglib动态代理在方法调用时较快(因为它直接调用子类方法,且可以被JIT优化)[^2][^3]。 - **内存占用**:JDK动态代理内存占用较低(生成的代理类较简单);Cglib动态代理内存占用较高(因为它生成了完整的子类)[^2]。 4. **使用场景**: - **JDK动态代理**:适用于目标对象已经实现了一个或多个接口的情况。例如,Spring AOP默认使用JDK动态代理(当目标对象实现了接口时)[^3]。 - **Cglib动态代理**:适用于目标对象没有实现接口的情况,或者需要代理类而不是接口。Spring AOP在目标对象没有实现接口时会自动切换到Cglib[^3]。 5. **依赖**: - **JDK动态代理**:是Java标准库的一部分(java.lang.reflect包),无需额外依赖。 - **Cglib动态代理**:需要引入第三方库(cglibasm)。 6. **优缺点总结**: - **JDK动态代理**: - 优点:原生支持,无额外依赖;生成代理较快。 - 缺点:只能代理接口;反射调用有性能开销。 - **Cglib动态代理**: - 优点:可以代理类;方法调用速度快。 - 缺点:需要额外依赖;不能代理final类或方法;生成代理较慢,且内存占用高。 ### 对比表格 | 对比维度 | JDK动态代理 | Cglib动态代理 | |------------------|--------------------------------------|----------------------------------------| | **实现原理** | 基于接口(生成接口实现类) | 基于继承(生成目标类的子类) | | **目标类要求** | 必须实现接口 | 不能是final类,方法不能是final | | **生成代理速度** | 较快(反射API) | 较慢(需生成字节码) | | **方法调用速度** | 较慢(反射调用) | 较快(直接调用,可被JIT优化) | | **内存占用** | 较低 | 较高(生成完整子类) | | **使用场景** | 代理有接口的目标对象 | 代理无接口的目标对象 | | **依赖** | JDK原生支持 | 需引入cglibasm库 | ### 总结建议 - 如果目标对象已经实现了接口,优先使用**JDK动态代理**,因为它更轻量且无额外依赖。 - 如果目标对象没有实现接口,或者需要更高的方法调用性能,则使用**Cglib动态代理**,尽管它会带来额外的依赖内存开销。 在Spring框架中,默认策略是:如果目标对象实现了接口,则使用JDK动态代理;否则使用Cglib。也可以通过配置强制使用Cglib代理(如`@EnableAspectJAutoProxy(proxyTargetClass=true)`)[^3]。 --- §§相关问题§§ 1. 在Spring框架中如何配置强制使用Cglib代理? 2. 如何通过代码示例演示JDK动态代理Cglib动态代理的创建过程? 3. 动态代理在Spring AOP中的具体应用场景有哪些?</think>### JDK动态代理CGLIB动态代理对比分析 #### 1. 实现原理对比 | **维度** | **JDK动态代理** | **CGLIB动态代理** | |------------------|--------------------------------------------------------------------------------|----------------------------------------------------------------------------------| | **代理机制** | 基于接口实现<br>运行时生成接口的代理类(`$Proxy0`格式) | 基于继承实现<br>运行时生成目标类的子类 | | **底层技术** | Java反射机制<br>(`java.lang.reflect.Proxy` + `InvocationHandler`) | ASM字节码操作库<br>(通过`Enhancer`生成子类字节码) | | **目标类要求** | 必须实现至少一个接口 | 目标类不能是final类<br>目标方法不能是final | > 💡 **本质差异**: > JDK代理是**接口契约型代理**(实现相同接口)[^4] > CGLIB是**继承扩展型代理**(生成目标类的子类)[^1] --- #### 2. 性能对比 | **指标** | JDK动态代理 | CGLIB动态代理 | |------------------|--------------------------------------|----------------------------------------| | **代理生成速度** | 较快<br>(直接调用反射API) | 较慢<br>(需动态生成字节码) | | **方法调用速度** | 较慢<br>(反射调用有性能损耗) | 较快<br>(直接方法调用,可被JIT优化) | | **内存占用** | 较低<br>(轻量级代理类) | 较高<br>(生成完整子类) | **性能曲线示例**: ```mermaid graph LR A[首次调用] -->|JDK| B[反射初始化开销] A -->|CGLIB| C[字节码生成开销] D[多次调用] -->|JDK| E[反射调用持续损耗] D -->|CGLIB| F[直接调用高效执行] ``` > 📊 **实测数据参考**: > 万次方法调用时,CGLIBJDK代理快约30%-50%[^2] --- #### 3. 使用限制对比 | **限制类型** | JDK动态代理 | CGLIB动态代理 | |--------------------|-------------------------------------------------|------------------------------------------------| | **类限制** | 无类限制 | 不能代理final类<br>(如`String`, `Integer`等) | | **方法限制** | 只能代理接口方法 | 不能代理final方法<br>(如`Object.getClass()`) | | **依赖要求** | JDK原生支持 | 需引入第三方库<br>(cglib + asm) | --- #### 4. 使用场景对比 | **场景** | 推荐方案 | 原因说明 | |--------------------------|-------------------|--------------------------------------------------------------------------| | Spring默认代理策略 | JDK动态代理 | 当目标类实现接口时优先使用[^3] | | 代理无接口的类 | CGLIB | 可代理普通POJO类 | | 高性能要求的核心业务 | CGLIB | 避免反射调用损耗 | | 简单功能扩展(如日志) | JDK动态代理 | 开发便捷,无需额外依赖 | | 需要代理final方法 | 两者均不支持 | 需考虑AspectJ编译时织入 | --- #### 5. 代码结构差异 **JDK代理核心组件**: ```java // 调用处理器 public class JdkHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) { // 前置增强 Object result = method.invoke(target, args); // 反射调用 // 后置增强 return result; } } // 创建代理 Service proxy = (Service) Proxy.newProxyInstance( loader, new Class[]{Service.class}, // 必须为接口 new JdkHandler(target) ); ``` **CGLIB核心组件**: ```java // 方法拦截器 public class CglibInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { // 前置增强 Object result = proxy.invokeSuper(obj, args); // 直接调用父类方法 // 后置增强 return result; } } // 创建代理 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TargetClass.class); // 设置目标类(非接口) enhancer.setCallback(new CglibInterceptor()); TargetClass proxy = (TargetClass) enhancer.create(); ``` > 🔑 **关键区别**: > CGLIB的`invokeSuper()`直接调用父类方法,避免了JDK的反射调用[^1] --- #### 6. 框架应用策略 在Spring AOP中的智能选择机制: ```mermaid graph TD A[创建代理] --> B{目标类实现接口?} B -->|是| C[使用JDK动态代理] B -->|否| D[使用CGLIB代理] C --> E[生成接口代理类] D --> F[生成子类代理] ``` 可通过配置强制使用CGLIB: ```java @EnableAspectJAutoProxy(proxyTargetClass = true) // Spring配置 ``` --- ### 总结建议 | **选择依据** | **推荐方案** | |------------------------|--------------| | 目标类已实现接口 | ✅ JDK代理 | | 目标类是普通类 | ✅ CGLIB | | 需要最高性能 | ✅ CGLIB | | 避免第三方依赖 | ✅ JDK代理 | | 代理final类/方法 | ❌ 均不支持 | > 💎 **最佳实践**: > - 在Spring生态中优先采用框架的自动代理机制 > - 独立开发时根据目标类结构性能需求选择 > - 高并发场景建议用CGLIB+缓存优化(避免重复生成代理类)[^2] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值