Я пытаюсь использовать транзакции Spring с AspectJ
**Мой проект: build.config
plugins {
id 'org.springframework.boot' version '2.3.3.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id "io.freefair.aspectj.post-compile-weaving" version "5.1.0"
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
project.ext {
aspectjVersion = "1.8.2"
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework:spring-jdbc'
implementation 'org.springframework:spring-tx'
implementation 'org.postgresql:postgresql'
implementation 'org.aspectj:aspectjrt'
implementation 'org.aspectj:aspectjweaver'
implementation 'org.aspectj:aspectjtools'
implementation 'org.springframework:spring-aspects:5.3.2'
implementation 'org.springframework:spring-instrument:5.3.2'
}
test {
useJUnitPlatform()
}
DataConfig.класс
@Configuration
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
public class DataConfig {
@Bean
public DataSource postgres() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/postgres?serverTimezone=UTC");
dataSource.setUsername("postgres");
dataSource.setPassword("admin");
dataSource.setSchema("public");
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(postgres());
}
}
MainDAO.класс
@Repository
public class MainDAO {
private final JdbcTemplate jdbcTemplate;
public MainDAO(DataSource postgres) {
this.jdbcTemplate = new JdbcTemplate(postgres);
}
public Integer getSoundsCount() {
return jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM Sound", Integer.class);
}
@Transactional(propagation = Propagation.MANDATORY)
public void insertSound() {
insertAuthor();
jdbcTemplate.update(
"INSERT INTO Sound (author, name, id) VALUES (?,?,?)",
0, "Spring", 0);
}
}
Когда я вызываю метод insertSound из моей службы, он запускается без исключения. Но это должно вызвать исключение, потому что метод insertSound имеет распространение. ОБЯЗАТЕЛЬНО.
Если я изменю режим Advice EnableTransactionManegment на mode=Advice.PROXY, тогда я получу исключение
Но с режимом=Advice.ASPECTJ транзакция не работает.
Я также пытаюсь запустить приложение с аннотацией EnableLoadTimeWeaving и установить библиотеку spring-instrument в качестве java-агента, но транзакция также не работает:
Что я должен сделать, чтобы транзакция работала с режимом=Advice.ASPECTJ?
Чтобы это работало с LTW, вы можете использовать -javaagent:path/to/aspectjweaver.jar
в командной строке в сочетании с -javaagent:path/to/spring-instrument.jar
, а также добавить @EnableLoadTimeWeaving
, о котором вы упоминали ранее, в свою конфигурацию.
Я нашел способ заставить нативные декларативные транзакции Spring AspectJ работать с переплетением во время компиляции, см. мой запрос на извлечение. Одна ключевая вещь среди других деталей:
@Bean
public PlatformTransactionManager transactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(h2());
// Make native AspectJ declarative transactions work with compile-time weaving
AnnotationTransactionAspect.aspectOf().setTransactionManager(transactionManager);
return transactionManager;
}
Смотрите также этот ответ для справки.
При обычном запуске приложения (то есть без каких-либо аргументов -javaagent
, потому что аспект транзакции уже скомпилирован) после mvn compile
журнал консоли должен отображать Native AspectJ active = true
каждый раз, когда вызывается URI sounds/add
. Эта строка журнала запускается этим оператором отладки, который я добавил для иллюстрации:
@Transactional//(propagation = Propagation.MANDATORY)
public void insertSound() {
boolean nativeAspectjActive = Arrays
.stream(new Exception().getStackTrace())
.map(StackTraceElement::toString)
.anyMatch(signature -> signature.contains("MainDAO.insertSound_aroundBody"));
logger.info("Native AspectJ active = " + nativeAspectjActive);
// (...)
}
У меня было немного свободного времени и мне было любопытно, иначе я бы не стал заморачиваться. Я не использую Spring обычно.
Спасибо, что нашли способ заставить нативные декларативные транзакции Spring AspectJ работать с переплетением во время компиляции!