Как определить, используется ли переплетение времени загрузки в Spring Boot?

Я использую Spring Boot 3.0.12. Чтобы включить переплетение во время загрузки.

Воспроизводимый пример размещен здесь. (филиал - aspect). Чтобы воспроизвести проблему, сделайте

curl --request GET 'http://localhost:8080/hello'

Я создал aop.xml под META-INF, как показано ниже.

<aspectj>
  <aspects>
    <aspect name = "com.example.helloworld.aspects.DaoExceptionHandler"/>

    <weaver options = "-verbose -showWeaveInfo">
      <include within = "com.example.helloworld.*"/>
    </weaver>
  </aspects>
</aspectj>

Я начинаю приложение с javaagent:/Users/dm/.m2/repository/org/aspectj/aspectjweaver/1.9.20/aspectjweaver-1.9.20.jar.

Ниже зависимости добавлены в мой pom.xml.

<dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.9.20</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.20</version>
    </dependency>

Мой код аспекта показан ниже

@Aspect
@Slf4j
public class DaoExceptionHandler {
  @AfterThrowing(
      pointcut =
          "execution(* *(..)) &&"
              + " @annotation(com.example.helloworld.utils.HandleDaoException)",
      throwing = "ex")
  public void handle(RuntimeException ex) {
    log.error("Exception received on dao", ex);
    throw JooqUtil.mapException(ex);
  }
}

Я использую @HandleDaoException, как показано ниже.

@Component
public class DaoImpl {
  @HandleDaoException
  public void getError() {
    throw new IllegalArgumentException("Test");
  }
}

Во время запуска приложения я вижу журналы, как показано ниже.

2024-04-23T16:21:08.770+05:30  INFO 33973 --- [           main] c.e.helloworld.HelloWorldApplication     : Started HelloWorldApplication in 0.797 seconds (process running for 1.13)
[MethodUtil@4b627298] info AspectJ Weaver Version 1.9.20 built on Tuesday Aug 15, 2023 at 23:35:34 PDT
[MethodUtil@4b627298] info register classloader sun.reflect.misc.MethodUtil@4b627298
[MethodUtil@4b627298] info using configuration /Users/debrajmanna/code/java/github/spring-boot-hello-world/target/classes/META-INF/aop.xml
[MethodUtil@4b627298] info register aspect com.example.helloworld.aspects.DaoExceptionHandler

Когда я комментирую любой метод @HandleDaoException, аспект работает правильно, я вижу журналы, как показано ниже.

java.lang.IllegalArgumentException: Test
    at com.example.helloworld.dao.DaoImpl.getError(DaoImpl.java:10) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-6.0.13.jar:6.0.13]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) ~[spring-aop-6.0.13.jar:6.0.13]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-6.0.13.jar:6.0.13]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) ~[spring-aop-6.0.13.jar:6.0.13]
    at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) ~[spring-aop-6.0.13.jar:6.0.13]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) ~[spring-aop-6.0.13.jar:6.0.13]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) ~[spring-aop-6.0.13.jar:6.0.13]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-6.0.13.jar:6.0.13]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.13.jar:6.0.13]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) ~[spring-aop-6.0.13.jar:6.0.13]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) ~[spring-aop-6.0.13.jar:6.0.13]
    at com.example.helloworld.dao.DaoImpl$$SpringCGLIB$$0.getError(<generated>) ~[classes/:na]
    at com.example.helloworld.controller.HelloWorldController.sendGreetings(HelloWorldController.java:17) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-6.0.13.jar:6.0.13]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-6.0.13.jar:6.0.13]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.0.13.jar:6.0.13]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) ~[spring-webmvc-6.0.13.jar:6.0.13]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-6.0.13.jar:6.0.13]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.0.13.jar:6.0.13]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081) ~[spring-webmvc-6.0.13.jar:6.0.13]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974) ~[spring-webmvc-6.0.13.jar:6.0.13]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011) ~[spring-webmvc-6.0.13.jar:6.0.13]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.0.13.jar:6.0.13]
...

Если удалить -javaagent из команды запуска моего приложения, а также указать @EnableAspectJAutoProxy, то я также увижу приведенную выше трассировку стека при вызове DaoExceptionHandler.

Насколько я понимаю, без времени загрузки используются весенние настройки по умолчанию для прокси-серверов CGLIB. Судя по приведенной выше трассировке стека исключений, прокси-серверы CGLIB все еще используются, хотя включено переплетение времени загрузки. Если мое понимание неверно, то есть ли способ узнать, правильно ли работает плетение времени загрузки весной или нет?

Было бы хорошо иметь минимальный воспроизводитель для этой задачи. В журнале ясно видно, что ткач AspectJ активен, когда вы запускаете его с помощью -javaagent. Я понятия не имею, как JOOQ работает внутри и использует ли он CGLIB или нет, возможно, это связано с вашим вопросом. Если бы я мог воспроизвести ситуацию и прикрепить к демо-приложению отладчик, было бы гораздо проще ответить на ваш вопрос.

kriegaex 23.04.2024 10:23

Хорошо, я постараюсь привести воспроизводимый пример и обновить вопрос.

tuk 23.04.2024 12:00

@kriegaex Воспроизводимый пример размещен здесь. Возможно, я делаю что-то элементарное неправильно. В приведенном выше примере отправка curl --request GET 'http://localhost:8080/hello' приведет к вызову аспекта. Я обновил вопрос соответствующим образом с помощью репродуктора.

tuk 23.04.2024 13:14

В вашем примере Spring по умолчанию имеет значение CGLIB, потому что у компонента нет интерфейса. В противном случае будут использоваться обычные динамические прокси.

Nico Van Belle 23.04.2024 13:43

В этом случае aop по-прежнему основан на динамическом прокси-сервере cglib или jdk, который, насколько я понимаю, является Spring по умолчанию. Я ищу способ включить переплетение времени загрузки аспекта в весеннем приложении.

tuk 23.04.2024 14:21

Ваш MCVE не строится. package com.example.helloworld.service does not exist. Класс HelloWorldController импортирует com.example.helloworld.service.Profile, которого нет.

kriegaex 23.04.2024 15:48

@NicoVanBelle, то, что вы говорите, относится к Spring AOP. Речь идет о нативном AspectJ, который вообще не использует никаких прокси.

kriegaex 23.04.2024 15:50

aop.xml также пуст. Я пытаюсь локально исправить обе проблемы, чтобы запустить проект локально. В следующий раз вам следует протестировать образец проекта, прежде чем публиковать ссылку.

kriegaex 23.04.2024 15:55

Становится все хуже и хуже. Аспект, реализация DAO и аннотация также пусты. Как этот фрагментарный проект предназначен для воспроизводства чего-либо?

kriegaex 23.04.2024 15:58

@kriegaex Я знаю, но предположение OP было ошибочным, что по умолчанию Spring всегда использует CGLIB. Это предположение верно только в том случае, если вы укажете опцию proxyTargetClass=true. В противном случае он попытается использовать стандартные прокси-серверы на основе интерфейса Java.

Nico Van Belle 23.04.2024 16:46

Я приношу извинения. Каким-то образом мой локальный коммит не прошел. Я вталкиваю его.

tuk 23.04.2024 17:16

@kriegaex Я нажал на это. Весь код теперь должен быть там, в ветке aspect.

tuk 23.04.2024 17:18

@NicoVanBelle Я имел в виду, что по умолчанию Spring aop использует прокси, который может быть динамическим прокси CGLIB или jdk (на основе значения proxyTargetClass, как вы указали). Но здесь я пытался использовать переплетение времени загрузки AspectJ в приложении весенней загрузки.

tuk 23.04.2024 17:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
0
13
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вы допустили две ошибки в своем проекте. Я исправила их в этом пиаре:

  1. Не используйте @Import({ DaoExceptionHandler.class }), потому что это заставляет Spring относиться к собственному аспекту AspectJ как к классу Spring @Configuration, ложно создавая для него специальный тип прокси-сервера CGLIB. Этот прокси-сервер CGLIB не является обычным прокси-сервером Spring AOP, а представляет собой другой тип для конфигураций Spring с другим поведением. См. объяснение здесь. В любом случае, вам это не нужно, и это тоже неправильно.

  2. Обязательно установите правильную область переплетения аспектов com.example.helloworld..*, где обозначение с двумя точками также включает в себя подпакеты.

Мета-комментарий для всех будущих читателей: Видите, вот почему я всегда прошу полный, минимальный воспроизводитель. Вопрос не содержит достаточно информации для ответа, например. аннотация @Import отсутствует. Я никогда не ожидал найти это в проекте GitHub. Но с помощью клонированного проекта решение было легко найти. Обратите внимание: если вам нужна помощь в решении проблемы, не думайте, что вы знаете, какие детали имеют решающее значение. Если бы вы знали, возможно, вам вообще не понадобилась бы никакая помощь.

kriegaex 23.04.2024 20:29

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