Spring spring

Spring中文网站 > Spring 框架安全 > Spring动态代理原理 Spring的动态代理有几种实现方式
Spring动态代理原理 Spring的动态代理有几种实现方式
发布时间:2026/07/21 11:34:07

品牌型号:联想ThinkPad X1

系统:Windows10家庭版

软件版本:Spring 5.3.7

们在用Spring的时候,事务、AOP等功能看起来很神奇。只需要添加@Transactional注解,方法就自动有了事务能力。代码中不需要编写手动开启、提交事务的逻辑,这背后靠的就是动态代理。动态代理在Spring里到底是怎么运作的?它有几种实现方式,各自又有什么差别?这些问题平时用的时候感知不强,但真正理解了之后,遇到代理失效、事务不生效这类问题,排查起来会快很多。下面就给大家介绍一下Spring动态代理原理,Spring的动态代理有几种实现方式的相关内容。

一、Spring动态代理原理

Spring的动态代理是在不修改原来代码的情况下,为目标对象包装一层代理对象,所有对目标方法的调用都要先经过这层代理,代理里可以在方法执行前后插入额外逻辑。这就是AOP能实现的基础,事务、日志、权限这些横切逻辑,都是通过代理对象织入进去的。

JDK代理工厂生成代理
图1:JDK代理工厂生成代理

Spring容器在初始化Bean的时候,会判断这个Bean有没有需要代理的切面逻辑,如果有,容器不会直接把原始对象放进去,而是创建一个代理对象注册到容器里,后面从容器里拿到的Bean,其实已经是代理对象了,不是原始类的实例。调用方法的时候,代理对象先拦截,执行前置逻辑,再触发目标方法,执行后置逻辑,整个流程对调用方是完全透明的。

AOP切面类
图2:AOP切面类

代理对象会在Bean初始化的后置阶段完成创建,具体是通过BeanPostProcessor来实现的,Spring内部有个AbstractAutoProxyCreator,它实现了BeanPostProcessor接口,在postProcessAfterInitialization方法里判断当前Bean是否需要被代理,需要的话就在这里生成代理对象并返回,替换掉原始Bean。

自定义简易版AutoProxyCreator
图3:自定义简易版AutoProxyCreator

理解这个原理之后,有些常见问题就好解释了,例如同一个类里方法A调用方法B,B上加了@Transactional,事务却不生效是因为A直接调用的是原始对象的B方法,压根没经过代理,事务逻辑自然不会触发。

二、Spring的动态代理有几种实现方式

Spring的动态代理有两种实现,一种是JDK动态代理,还有一种是CGLIB代理。JDK动态代理是Java自带的,核心是java.lang.reflect.Proxy,它通过反射在运行时生成一个实现了目标接口的代理类。注意这里的限制,目标类必须实现接口,代理对象和目标对象共同实现同一个接口,调用方拿到的是接口类型的引用,实际执行的是代理类里的逻辑。

JDK动态代理的前提是必须实现接口
图4:JDK动态代理的前提是必须实现接口

CGLIB走的是另一条路,它不依赖接口,而是直接对目标类生成一个子类作为代理,通过继承的方式重写父类方法,在重写的方法里插入额外逻辑再调用父类原始方法。因为不需要接口,普通的类也能被代理,覆盖范围比JDK动态代理更广。不过有个限制,final修饰的类没办法被继承,final方法也没办法被重写,这种情况下CGLIB代理会失效。

引入依赖
图5:引入依赖

Spring在选择用哪种代理方式的时候有自己的判断逻辑,在早期版本默认是能用JDK动态代理就用JDK,目标类没有实现接口才换CGLIB,Spring Boot 2.x之后默认改成了优先用CGLIB,因为CGLIB不要求目标类有接口,省去了一些因为缺少接口导致代理异常的问题。当然这个默认行为可以通过配置修改,spring.aop.proxy-target-class设成false就切回JDK动态代理优先。

CGLIB代理工厂
图6:CGLIB代理工厂

JDK动态代理依赖标准Java API,不需要额外引入库,生成代理的速度快,但只能代理接口;CGLIB生成子类的过程相对耗时一些,但不受接口限制,灵活性更高,实际项目里用得更多。

以上就是Spring动态代理原理,Spring的动态代理有几种实现方式的全部内容了。动态代理是Spring很多核心功能的底层支撑,两种实现方式记住各自的限制就够用了,JDK动态代理要求目标类有接口,CGLIB通过继承实现、碰到final会失效。在Spring Boot中默认用的是CGLIB,大多数场景不用操心选哪个。

180 1563 6924