java - @Transactional 不适用于 AspectJ
问题描述
我决定使用它来避免无法从同一个类中调用AspectJ
带有注释的方法的事实@Transactional
所以我添加了这个配置:
@Configuration
@EnableTransactionManagement(mode= AdviceMode.ASPECTJ)
@EnableLoadTimeWeaving(aspectjWeaving= AspectJWeaving.ENABLED)
public class App implements LoadTimeWeavingConfigurer {
@Override
public LoadTimeWeaver getLoadTimeWeaver() {
return new InstrumentationLoadTimeWeaver();
}
}
在build.gradle
runtimeOnly("org.aspectj:aspectjweaver:1.9.7")
我运行应用程序(嵌入tomcat的spring boot应用程序)-javaagent:C:\xx\xx\.m2\repository\org\springframework\spring-instrument-5.3.12.jar
但是当我尝试
public void m1() {
this.m2()
}
@Transactional(propagation = Propagation.REQUIRED)
public void m2() {
....
}
似乎该m2()
方法未在事务中执行,
在我使用这些日志记录级别进行调试时的日志中:
logging.level.org.springframework.transaction.interceptor=trace
logging.level.org.springframework.orm.jpa=trace
没有这样的行:
Creating new transaction with name [xxx.m2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
我在那里错过了什么吗?
解决方案
我克隆了你的 GitHub 项目,然后添加了
implementation 'org.springframework:spring-instrument'
您还应该将 Spring(事务)方面的范围限制为仅编织您自己的应用程序类,以避免[Xlint:cantFindType]
在尝试编织 Spring 自己的类时出现大量消息。您可以通过提供自己的src/main/resources/org/aspectj/aop.xml
文件来执行此操作,如下所示:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<!-- You can also add -Xlint:ignore in order to avoid lots of '[Xlint:cantFindType]' warnings -->
<weaver options="-verbose -showWeaveInfo">
<!-- Only weave classes in our application-specific packages -->
<include within="com.example.aspectj..*"/>
</weaver>
</aspectj>
编织器选项还可以更轻松地查看哪些方面被编织到哪些连接点中,例如在启动期间您看到
[AppClassLoader@77556fd] weaveinfo Join point 'method-execution(void com.example.aspectj.services.FooService.m2())' in Type 'com.example.aspectj.services.FooService' (FooService.java:27) advised by around advice from 'org.springframework.transaction.aspectj.JtaAnnotationTransactionAspect' (AbstractTransactionAspect.aj:67)
这证明它FooService.m2()
实际上是被编织的。
对于不太“嘈杂”的 AspectJ 编织器,只需使用<weaver options="-showWeaveInfo -Xlint:ignore">
- 不再有警告或有关注册哪些方面的信息,但仍然是有关编织连接点的信息,这很重要,IMO。
然后,我使用 Spring 工具和 AspectJ weaver 代理启动了应用程序。只有前者不足以启动仪器,我需要两个代理。因为在 JDK 16+ 上,您需要将java.lang
包打开到未命名的模块才能应用 LTW,并且我在最近的 JDK 上进行测试,所以我还添加了相应的--add-opens
选项(在 JDK 15 之前不需要):
--add-opens java.base/java.lang=ALL-UNNAMED
-javaagent:.../aspectjweaver-1.9.7.jar
-javaagent:.../spring-instrument-5.3.12.jar
然后一切正常:
o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
com.example.aspectj.AspectjApplication : Started AspectjApplication in 7.339 seconds (JVM running for 10.046)
com.example.aspectj.AspectjApplication : running ..
com.example.aspectj.services.FooService : m1 : called
o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.example.aspectj.services.BooService.m3]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(1516190088<open>)] for JPA transaction
o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@543f6ccb]
com.example.aspectj.services.BooService : m3 : called
o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(1516190088<open>)]
o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(1516190088<open>)] after transaction
o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.example.aspectj.services.FooService.m2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(45178615<open>)] for JPA transaction
o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@20e4fce0]
com.example.aspectj.services.FooService : m2 : called
o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(45178615<open>)]
o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(45178615<open>)] after transaction
更新:对于开箱即用的 Spring (Boot) 带来的问题,我真的很抱歉,但是现在,您要么必须使用 AspectJ 核心转储文件ajdump.*.txt
- 事务方面的编织仍然有效,就像我之前说的 -或使用您自己的aop.xml
文件(见上文)。作为包含您自己的应用程序基础包以进行方面编织的替代方法,您还可以采取相反的方向,即排除导致核心转储的类或包。在 Spring Boot 2.5.6 中,您只需添加
<exclude within="org.springframework.boot.jdbc.DataSourceBuilder.OraclePoolDataSourceProperties"/>
在 Spring Boot 2.3.3 中,AspectJ 抱怨这个类:
<exclude within="org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer"/>
我认为这需要在 Spring Boot 或 Spring Core、Spring-TX 或 Spring-Aspects 中修复,无论这些方面位于何处。
更新 2:我创建了Spring Core 问题 #27650以跟踪 AspectJ 核心转储问题。这不是您最初问题的根本原因,因为事务方面编织无论如何都可以工作,但无论如何都需要在 Spring(并且可能在 AspectJ 中)解决它。
推荐阅读
- python - 在安装 deepspeech 环境期间,tensorflow 依赖项不断给我 colab 中的错误
- html - Bootstrap - 具有可滚动内容的 Flex Box 容器
- python - 多项式变换的图像变形
- mysql - RAND() 在 SQL 触发器中用于获取随机数。如果它生成已使用的号码会怎样?
- google-cloud-platform - 将数据插入旧表和 BigQuery 中的所有者的提取脚本 - GCP
- c++ - 为什么尽管具有相同的算法和数据结构,其他解决方案的效率是 10 倍?
- django - 了解 Django 排除有关 ForeignKey 关系的查询集
- python - Simple-Salesforce API 版本
- javascript - 用javascript计算日期时间(以天为单位)
- c# - 使用指针在函数中传递公共变量的地址