java 切面执行两次

我们在 java 应用里面,往往需要用切面去做一些事情,比如,利用切面自动打印日志。最近遇到一个问题,切面环绕方法被执行两次。

排除了手动调用,猜测是切面 bean 被注册了两个。那么怎么验证呢?

切面 bean 所在的文件是 util.xml,它被  common.xml 引入.

于是以毒攻毒,故意将 common.xml 文件入两次,此时,发现切面环绕方法被执行了四次,所以,很明显问题出在 common.xml 被重复引入。因为,如果是 util.xml 被重复引入,故意将 common.xml 引入两次,则环绕方法应该被执行三次(common.xml 中只引入一次 util.xml).

知道了这个之后就很容易了,因为 common.xml 是一个顶层的 spring 配置文件,只存在于 @ImportResource 中。最终找到问题是,一个工程里面有两个 main,每一个启动类上面都这样的注释:

@SpringBootApplication
@ImportResource(locations={"classpath:spring/common.xml"})

其中一个启动类是真正的启动类;另一个是备用工具类,也需要直接启动。

最后的解决方法是,把工具类上面的 @SpringBootApplication 这一行去掉。(原理上是要去掉两行的,但只用去掉这一行也能 work, 因为 ImportResource 与 Configuraion 一类的标签一起使用才有意义. 而 SpringBootApplication 包含了 Configuraion)

<think>好的,用户之前问过关于面向切面编程(AOP)的问题,现在他接着问“什么是切面”。我需要先回顾之前的对话,确保回答的一致性和连贯性。之前已经解释了AOP的概念,以及在若依微服务中的应用场景和解决的问题。现在需要专注于“切面”这个术语的定义,可能用户想更深入理解AOP中的核心组件。 首先,切面(Aspect)在AOP中的定义是关键。需要简明扼要地解释切面是什么,可能用户已经了解AOP的大致概念,但需要明确切面的组成部分和作用。应该用通俗易懂的例子,比如日志记录或权限检查,来说明切面如何将横切关注点模块化。 然后,可能需要分解切面的组成元素,如切入点(Pointcut)、通知(Advice)、连接点(Join Point)等。这些术语需要逐一解释,但要注意避免技术术语过于复杂,保持口语化。例如,切入点可以比喻为“告诉程序在哪里插入代码”,通知则是“插入的具体代码逻辑”。 用户可能还想知道切面的实际应用场景,结合之前提到的若依微服务中的例子,可以再次提到权限校验、日志记录等,说明切面如何在这些场景中发挥作用。这样不仅巩固了之前的回答,也帮助用户将理论概念与实际应用联系起来。 另外,需要考虑用户可能的深层需求。他们可能是在学习AOP时遇到了术语障碍,或者在实际开发中需要应用切面但不太确定如何操作。因此,在解释切面时,可以给出一个简单的代码示例,比如使用Spring AOP的注解,这样用户能更直观地理解。 还要注意用户是否可能混淆切面与其他编程概念,比如类或模块。需要强调切面的特殊性在于它处理的是横切关注点,而不是核心业务逻辑。通过比喻,如“插件”或“拦截器”,帮助用户形成直观的理解。 最后,总结切面的优势,如减少重复代码、提高维护性等,呼应之前AOP解决的问题,确保回答的完整性和一致性。同时,可以预告后续可能的问题,比如如何实现自定义切面,引导用户继续探索,但当前问题需要集中解答切面的定义和结构。</think>### **通俗解释:什么是切面(Aspect)?** **切面(Aspect)** 是面向切面编程(AOP)中的核心概念,可以理解为一个“模块化的工具箱”,专门用来解决那些**分散在系统各处、与核心业务无关但又必须存在的功能**(比如日志、权限、性能监控)。 **简单来说,切面就像是一个“插件”**,它能在不修改原有代码的情况下,给程序的某些关键节点(比如调用某个方法)**动态插入额外操作**。 --- ### **切面的组成** 切面由两部分构成: 1. **切入点(Pointcut)**: - 定义“**在哪里插入代码**”,例如:“所有以 `@GetMapping` 注解的接口方法”或“所有 `UserService` 类中的方法”。 - 类似地图上的标记,告诉程序:“在这些地方动手脚!” 2. **通知(Advice)**: - 定义“**插入什么代码**”,例如:“在方法执行前记录日志”或“在方法抛出异常时发送告警”。 - 具体分为五种类型: - `@Before`(方法执行) - `@After`(方法执行,无论成功或失败) - `@AfterReturning`(方法成功返回后执行) - `@AfterThrowing`(方法抛出异常后执行) - `@Around`(包裹整个方法,控制其执行过程) --- ### **生活中的比喻** 假设你开了一家餐厅,核心业务是做饭和上菜。但除了做饭,你还需要: - 记录每道菜的制作时间(性能监控) - 检查顾客是否有预约(权限校验) - 在顾客投诉时赠送小菜(异常处理) **传统做法**:厨师一边炒菜,一边自己掐表、查预约、处理投诉——手忙脚乱。 **切面做法**:雇一个“服务员”(切面),让他在以下节点自动完成这些操作: - 顾客进门时 → 检查预约(`@Before`) - 厨师开始炒菜时 → 开始计时(`@Around`) - 顾客投诉时 → 赠送小菜(`@AfterThrowing`) **结果**:厨师只专注炒菜(核心逻辑),其他杂活由切面统一处理! --- ### **若依微服务中的切面应用** 在若依框架中,切面常用于以下场景(具体实现代码可能简化): ```java @Aspect @Component public class LogAspect { // 定义切入点:所有Controller中的public方法 @Pointcut("execution(public * com.ruoyi..controller.*.*(..))") public void logPointcut() {} // 通知:在方法执行前记录日志 @Before("logPointcut()") public void logBefore(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("【日志】方法 " + methodName + " 被调用"); } } ``` 通过这段代码,所有 Controller 的方法调用时都会自动打印日志,**无需在每个方法里手动写日志代码**。 --- ### **切面解决了什么问题?** 1. **代码污染**:避免核心业务代码被非功能代码(如日志、权限)淹没。 2. **重复劳动**:相同逻辑(如权限校验)只需在切面中写一次,全局生效。 3. **维护困难**:修改日志格式或权限规则时,只需改动切面,无需搜索所有代码。 --- **总结**:切面就像程序中的“隐形管家”,把分散在各处的杂活(日志、权限等)集中管理,让开发者专注核心业务逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值