Spring框架中的JDK与CGLib动态代理

本文介绍了Spring框架中JDK和CGLib动态代理的区别和使用场景。当getBean方法传入非接口类时,Spring默认使用JDK代理,必须传入接口类名。通过调整<aop:aspectj-autoproxy>的proxy-target-class属性,可以切换到CGLib代理。JDK代理依赖于接口,生成的目标类实现了原始接口;CGLib则为目标类创建子类。动态代理的创建需要XML配置和切面类方法匹配,@Transactional注解会触发JDK代理的事务管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在利用spring执行代码获取代理类时,getBean方法中必须是接口类名,否则将会出现错误,例如

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
IMathService mathService = applicationContext.getBean(MathService.class);

在getBean中写入的是MathService,而不是IMathService,此时控制台将会出现错误:
在这里插入图片描述
此时出现错误的原因是由于此时是由JDK进行代理,其中必须是接口类,否则将不能正常运行,Spring中有JDK代理和CGLib动态代理两种代理方式,两种方式所产生的代理类有着不同。
在具体的例子实现中,新建接口和实现类:

package com.jd.math;
public interface IMathService {
	int add(int a,int b);
	int div(int a,int b);
}

package com.jd.math;
import org.springframework.stereotype.Service;
@Service
public class MathService implements IMathService {
	@Override
	public int add(int a, int b) {	
		return a+b;
	}
	@Override
	public int div(int a, int b) {	
		return a/b;
	}
}

在spring中的xml文件中配置代码:

<context:component-scan base-package="com.jd"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

用main方法对其中的获取的类名进行输出:

public class Test {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
		IMathService mathService = applicationContext.getBean(IMathService.class);
		System.out.println(mathService.getClass());
		applicationContext.close();
	}
}

此时获得正确的JDK代理类名
在这里插入图片描述
在xml中配置的代码 aop:aspectj-autoproxy</aop:aspectj-autoproxy> ,其中包含了属性:proxy-target-class=" ",在未说明的情况下,其中的默认值为false,此时将以JDK代理方式进行代理,getBean中只能是接口类,若将xml中的属性改为 <aop:aspectj-autoproxy proxy-target-class=“true”></aop:aspectj-autoproxy>,此时进行main输出:
在这里插入图片描述
此时输出的结果是CGLib动态代理所产生的结果,此时将getBean中的类名改为方法名MathService,依然能够输出正确的CGLib动态代理的结果。在CGLib时,进行输出代理类的父类,加入代码:

System.out.println(mathService.getClass().getSuperclass());

得到此时的输出结果:
在这里插入图片描述
再将xml代码中属性改为false,获得JDK代理时的代理类父类结果:
在这里插入图片描述
在JDK代理方式下,获取代理类的实现:

public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
		IMathService mathService = applicationContext.getBean(IMathService.class);
		System.out.println(mathService.getClass().getSuperclass());
		Class clazz = mathService.getClass();
		Class [] array = clazz.getInterfaces();
		for(Class c : array) {
			System.out.println(c.getName());
		}
		applicationContext.close();
	}

此时获得输出结果:
在这里插入图片描述
对比可以发现,CGLib动态代理所产生的的代理类是目标类的子类,JDK动态代理产生的代理类与目标类没有继承关系;其代理类是目标类所实现的接口的实现类。所以JDK只能由接口类来创建实现,而CGLib动态代理即可由接口类,也可由目标类实现类。

代理类创建代理对象两个因素
1.xml里面需要配置代理。
2.调用切面类的方法与切面类的表达式相匹配

注解@Transationa
在事务中一个类中的方法被@transationa修饰,则spring自动为该类创建代理类及其代理对象,且创建的为JKD代理对象:

public interface IDataService {
	boolean del();
}

@Service
public class DataService implements IDataService {

	@Override
	@Transactional
	public boolean del() {
		return true;
	}
}
public static void main(String[] args)  {
		ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("application.xml");
		IDataService dataService = application.getBean(IDataService.class);
		System.out.println(dataService.getClass().getName());
		application.close();
	}

xml文件中配置代码为:<aop:aspectj-autoproxy proxy-target-class=“false”></aop:aspectj-autoproxy>,此时结果:
在这里插入图片描述
若删去注解@Transationa,将得到结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值