exp:<aop:config/> 事务配置无效

当使用<aop:config/>进行事务配置时遇到无效问题,原因是StudentService未被Spring加载,而是被SpringMVC加载导致。解决方案是确保Spring启动时扫描到Service,或者显式配置bean以启用事务管理。Spring应先于SpringMVC启动,且Spring负责事务管理,SpringMVC处理请求。通过调整配置,使Spring扫描所有Service,避免在SpringMVC中处理事务。

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

配置如下:

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="get*" read-only="true"/>
        <tx:method name="query*" read-only="true"/>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>
<!-- AOP切入点设置 -->
<aop:config>
    <aop:pointcut id="dbService" expression="execution(* 
    com.qyd.sms.service.api.student.service.StudentService.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="dbService" />
</aop:config>

事务管理表现为无效,同时还有一个非常奇怪的现象:如果将com.qyd.sms.service.api.student.service.StudentService这个类,以<bean/>的形式显式的配置在配置文件中,事务管理就可以生效

不得其解,很幸运在网上找到了这个:spring+springMVC,声明式事务失效,原因以及解决办法,结合目前的情况(显式配置生效,注解不生效),以及这篇文章的内容,无效的原因应该是StudentService没有被spring加载,而是被springMVC加载,而srpingMVC加载时没有处理事务相关的部分,所以事务配置无效

有起色,去着重看一下项目的spring、springMVC的启动方式,

<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:/META-INF/spring/spring-beans.xml</param-value>
</context-param>

<servlet>
    <servlet-name>qyd-sms-servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:/META-INF/spring/spring-web.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>qyd-sms-servlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

spring是通过ContextLoaderListener启动,springMVC通过DispatcherServlet启动,经过验证,spring 先于 springMVC 启动(暂时将ContextLoaderListener启动的部分称为spring,表示spring核心的部分,而springMVC则是处理请求的部分)

当前配置:spring启动配置了事务管理,没有配置自动扫描,springMVC配置了全局的自动扫描

事务无效的原因分析:
spring启动时能够拿到事务管理信息,但是由于没有配置扫描配置,所以看不到通过注解注册的StudentService,也就无法进行StudentService的事务相关的处理

等到springMVC启动时,可以注册StudentService,但是没有事务管理相关的配置,也就不会做事务相关的处理(tip:我不会尝试在springMVC中加入事务管理配置,去试一下是否事务能生效,因为即使能生效,也不会采用这种做法,理解即可)

所以 只要在spring启动时看到注册StudentService,就能够进行事务相关的处理,事务就能够生效,这也解释了为什么显式配置一个bean就可以生效,通常我们不会去显式配置每一个service,所以spring配置扫描即可解决该问题

我的解决方案:

springMVC:

<mvc:annotation-driven/>
<context:component-scan base-package="com.qyd.sms.controller" />

spring:

<context:component-scan base-package="com.qyd.sms" >
    <context:exclude-filter type="annotation" 
    expression="org.springframework.stereotype.Controller"/>     
</context:component-scan>

配置文件如上,原因下面有说明。

说明:
经过测试,springMVC Controller的注册是不能放在spring启动时进行的,因为springMVC拿到注册的Controller信息后进行了的进一步处理,用于接收来访的请求

我更倾向于,spring,springMVC使用同一个bean容器,springMVC完全是基于spring来处理依赖注入的关系的,只不过springMVC做了额外的事

既然二者功能不同,对于配置文件的话,我比较倾向于根据功能完全分开,springMVC只负责了Controller层的注册的扫描,spring则负责其它所有。

### Spring AOP 中 `aspectj-autoproxy` 配置启动报错解决方案 当在 Spring AOP 使用 `<aop:aspectj-autoproxy>` 进行配置时,如果遇到启动时报错提示找不到切点方法(Pointcut),通常是因为以下几个原因引起的: #### 1. 切点表达式错误 切点表达式的语法可能存在问题,或者未正确定位目标类中的方法。确保切点表达式能够匹配到实际存在的方法。 例如,假设有一个服务类 `MyService` 和其方法 `doSomething()`,可以通过如下方式定义切点: ```java @Aspect public class LoggingAspect { @Before("execution(* com.example.service.MyService.doSomething(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("Method called: " + joinPoint.getSignature().getName()); } } ``` 如果切点路径不正确或拼写有误,则会引发无法找到切点的异常[^1]。 --- #### 2. 组件扫描范围不足 如果没有正确启用组件扫描或将目标类排除在外,可能导致 Aspect 或目标 Bean 未能加载至容器中。因此,在 XML 文件中需确认已启用组件扫描并覆盖相关包路径。 以下是正确的组件扫描配置示例: ```xml <context:component-scan base-package="com.example"/> <aop:aspectj-autoproxy/> ``` 这里需要确保 `base-package` 属性指定了包含所有目标类和 Aspect 类所在的包路径[^3]。 --- #### 3. 缺少必要的依赖库 Spring AOP 基于 AspectJ 实现动态代理功能,因此项目中必须引入相关的依赖项。缺少这些依赖可能会导致运行失败。 Maven 构建工具下的必要依赖应包括以下内容: ```xml <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <!-- 如果使用 CGLIB 动态代理 --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> ``` 此外,还需注意版本兼容性问题,尤其是不同版本间的 API 变更[^2]。 --- #### 4. 方法访问权限限制 只有公共 (`public`) 方法才能作为切入点被拦截。如果尝试将私有 (`private`)、受保护 (`protected`) 或默认访问级别的方法设为切入点,则会导致此问题发生。 修改方法声明使其公开即可解决问题: ```java // 正确做法 public void doSomething() {} // 错误示范 (非公有方法不可用作切入点) private void internalLogic() {} ``` --- #### 5. 启用了 ProxyTargetClass 而无对应支持 通过设置属性 `proxy-target-class="true"` 来强制使用 CGLIB 替代 JDK 动态代理模式下,某些场景仍可能出现冲突情况。此时建议验证所使用的对象确实适合此类代理机制,并调整相应参数值测试效果差异。 XML 示例代码片段如下所示: ```xml <aop:aspectj-autoproxy proxy-target-class="false"/> <!-- 默认采用接口形式 --> ``` --- ### 总结 综上所述,针对 Spring AOP 配置过程中因找不到切点而导致的应用程序初始化阶段抛出异常的情况,可以从以上几个方面逐一排查定位根本原因所在。最终目的是让框架成功识别所需监控的目标函数从而正常运作起来[^1]^[]^. ```python print("Debugging completed.") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值