说说你所了解的Java代理,有遇到过Spring Aop失效场景吗

本文介绍了代理模式的概念、作用和实现方式,包括静态代理和动态代理。重点讲解了JDK动态代理和CGLIB动态代理的原理、特点及应用场景。最后讨论了Spring AOP中可能遇到的失效问题,如final、static、private方法以及同类内部调用导致的AOP失效。

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

目录

1.代理模式

1.1 静态代理

1.2 动态代理

1.3 应用场景

2.JDK动态代理 VS CGLIB动态代理

2.1 JDK动态代理

2.2 CGLIB动态代理

3.动态代理使用场景

4.Spring AOP失效问题


1.代理模式

概念:代理模式是一种设计模式,在开发中当我们要访问目标类时,不是直接访问目标类,而是直接调用其代理类,通过代理类去访问目标方法。

作用:可以在代理类调用目标类之前和之后去添加一些预处理和后处理的操作,来扩展一些不属于目标类的功能。如在方法开始之前记录日志;方法执行前进行额外的参数校验;进行事务管理(如手动提交事务)、权限校验等。

实现方式:静态代理、动态代理

1.1 静态代理

静态代理:在程序运行之前,给目标类编写了 其代理类的代码,编译了代理类,并生成了字节码文件(即预处理),在程序运行的时候直接去读取这些字节码文件。

以下编写简单的静态代理演示代码

1)首先定义一个接口,该接口提供了display()用于展示图片

// 定义一个接口
interfac
### Spring AOP 代理机制原理 Spring AOP 的核心在于通过动态代理实现面向切面编程的功能。其基本工作流程依赖于 Java 动态代理或 CGLIB 库,具体取决于配置和场景需求。 #### 动态代理的工作方式 在 Java 中,动态代理分为两种主要形式:基于接口的 JDK 动态代理和基于字节码操作的 CGLIB 动态代理[^1]。 - **JDK 动态代理**适用于目标类实现了至少一个接口的情况。它利用 `java.lang.reflect.Proxy` 类生成代理对象,并拦截方法调用。 - **CGLIB 动态代理**则用于目标类未实现任何接口的情形。它通过对目标类子类化并重写方法的方式完成代理功能[^2]。 以下是两者的核心区别: | 特性 | JDK 动态代理 | CGLIB 动态代理 | |-----------------|----------------------------------|--------------------------------| | 是否需要接口 | 需要 | 不需要 | | 实现方式 | 利用反射 | 字节码增强 | | 性能比较 | 较高 | 略低 | #### Spring AOP 源码剖析 Spring AOP 使用了上述两种代理机制之一来创建代理对象。当应用启动时,Spring 容器会根据条件决定采用哪种代理策略。如果目标 Bean 实现了一个或多个接口,则优先使用 JDK 动态代理;否则,默认切换到 CGLIB[^3]。 下面是一个简单的例子展示如何定义代理逻辑: ```java public class ServiceProxy implements InvocationHandler { private final Object target; public ServiceProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before advice"); Object result = method.invoke(target, args); System.out.println("After advice"); return result; } public Object getProxy() { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } } ``` 此代码片段展示了如何通过自定义 `InvocationHandler` 来控制方法调用前后的行为。 --- ### 常见问题及其解决方案 1. **无法找到合适的代理类型** 如果发现某些情况下既不适用 JDK 动态代理也不适合 CGLIB,可能是因为目标类缺少无参构造函数或其他约束条件所致。可以通过显式设置强制启用某一种代理模式解决该问题。 2. **性能瓶颈** 对于高频调用的方法来说,频繁触发代理可能会带来额外开销。优化建议包括减少不必要的通知(Advice)、合理设计切入点表达式以及评估是否真的需要引入 AOP 技术。 3. **事务管理失效** 当遇到事务传播失败等问题时,通常源于错误地访问当前线程绑定的对象实例而非实际代理版本。确保始终从容器获取服务 bean 而不是直接实例化它们即可规避此类风险。 --- ### 示例代码说明 以下是一段完整的 Spring Boot 配置样例,演示如何结合 XML 或注解声明切点与通知关系: ```xml <aop:config> <aop:pointcut id="businessService" expression="execution(* com.example.service.*.*(..))"/> <aop:before pointcut-ref="businessService" method="beforeAdvice"/> </aop:config> <bean id="loggingAspect" class="com.example.aspect.LoggingAspect"/> ``` 对应 AspectJ 注解风格如下所示: ```java @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void beforeAdvice(JoinPoint joinPoint){ System.out.println("Executing:" + joinPoint.getSignature()); } } ``` 以上分别体现了传统 XML 和现代注解驱动下的开发实践差异。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鹿的周先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值