Почему весенние транзакции не работают, когда я использую EnableTransactionManegment(mode=Advice.ASPECTJ)?

Я пытаюсь использовать транзакции 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?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
390
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Плетение во время загрузки (LTW)

Чтобы это работало с LTW, вы можете использовать -javaagent:path/to/aspectjweaver.jar в командной строке в сочетании с -javaagent:path/to/spring-instrument.jar, а также добавить @EnableLoadTimeWeaving, о котором вы упоминали ранее, в свою конфигурацию.

Плетение во время компиляции (CTW)

Я нашел способ заставить нативные декларативные транзакции 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 AspectJ работать с переплетением во время компиляции!

tiger 30.12.2020 08:40

У меня было немного свободного времени и мне было любопытно, иначе я бы не стал заморачиваться. Я не использую Spring обычно.

kriegaex 30.12.2020 10:01

Другие вопросы по теме

Работает только Post REST API, PUT, GET, DELETE API не работают в весеннем загрузочном приложении
TestContainers и ошибка: «Не удалось проверить соединение org.postgresql.jdbc.PgConnection» (поднятие одного контейнера для всех тестовых классов)
Я реализовал безопасность токена JWT в весеннем загрузочном коде. как я могу получить токен jwt в любом месте моего кода? нужно сохранить аудит
Развертывание войны не выполняется в tomcat из-за невозможности инициализации контекста, поскольку уже присутствует корневой контекст приложения
Не удалось найти этот тип процесса (веб) при развертывании весеннего загрузочного приложения
Как вызывать методы из шаблона Thymeleaf в Spring Boot?
Как лучше всего выполнить сквозное тестирование с использованием selenium webdriver и junit5?
@Repository и @EnableJpaRepositories не работают с последними версиями Hibernate и Spring
Как преобразовать дату HTML в ZonedDateTime в SpringBoot/MVC/Web?
Запуск Vue с Spring Boot