Я использую 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 все еще используются, хотя включено переплетение времени загрузки. Если мое понимание неверно, то есть ли способ узнать, правильно ли работает плетение времени загрузки весной или нет?
Хорошо, я постараюсь привести воспроизводимый пример и обновить вопрос.
@kriegaex Воспроизводимый пример размещен здесь. Возможно, я делаю что-то элементарное неправильно. В приведенном выше примере отправка curl --request GET 'http://localhost:8080/hello' приведет к вызову аспекта. Я обновил вопрос соответствующим образом с помощью репродуктора.
В вашем примере Spring по умолчанию имеет значение CGLIB, потому что у компонента нет интерфейса. В противном случае будут использоваться обычные динамические прокси.
В этом случае aop по-прежнему основан на динамическом прокси-сервере cglib или jdk, который, насколько я понимаю, является Spring по умолчанию. Я ищу способ включить переплетение времени загрузки аспекта в весеннем приложении.
Ваш MCVE не строится. package com.example.helloworld.service does not exist. Класс HelloWorldController импортирует com.example.helloworld.service.Profile, которого нет.
@NicoVanBelle, то, что вы говорите, относится к Spring AOP. Речь идет о нативном AspectJ, который вообще не использует никаких прокси.
aop.xml также пуст. Я пытаюсь локально исправить обе проблемы, чтобы запустить проект локально. В следующий раз вам следует протестировать образец проекта, прежде чем публиковать ссылку.
Становится все хуже и хуже. Аспект, реализация DAO и аннотация также пусты. Как этот фрагментарный проект предназначен для воспроизводства чего-либо?
@kriegaex Я знаю, но предположение OP было ошибочным, что по умолчанию Spring всегда использует CGLIB. Это предположение верно только в том случае, если вы укажете опцию proxyTargetClass=true. В противном случае он попытается использовать стандартные прокси-серверы на основе интерфейса Java.
Я приношу извинения. Каким-то образом мой локальный коммит не прошел. Я вталкиваю его.
@kriegaex Я нажал на это. Весь код теперь должен быть там, в ветке aspect.
@NicoVanBelle Я имел в виду, что по умолчанию Spring aop использует прокси, который может быть динамическим прокси CGLIB или jdk (на основе значения proxyTargetClass, как вы указали). Но здесь я пытался использовать переплетение времени загрузки AspectJ в приложении весенней загрузки.




Вы допустили две ошибки в своем проекте. Я исправила их в этом пиаре:
Не используйте @Import({ DaoExceptionHandler.class }), потому что это заставляет Spring относиться к собственному аспекту AspectJ как к классу Spring @Configuration, ложно создавая для него специальный тип прокси-сервера CGLIB. Этот прокси-сервер CGLIB не является обычным прокси-сервером Spring AOP, а представляет собой другой тип для конфигураций Spring с другим поведением. См. объяснение здесь. В любом случае, вам это не нужно, и это тоже неправильно.
Обязательно установите правильную область переплетения аспектов com.example.helloworld..*, где обозначение с двумя точками также включает в себя подпакеты.
Мета-комментарий для всех будущих читателей: Видите, вот почему я всегда прошу полный, минимальный воспроизводитель. Вопрос не содержит достаточно информации для ответа, например. аннотация @Import отсутствует. Я никогда не ожидал найти это в проекте GitHub. Но с помощью клонированного проекта решение было легко найти. Обратите внимание: если вам нужна помощь в решении проблемы, не думайте, что вы знаете, какие детали имеют решающее значение. Если бы вы знали, возможно, вам вообще не понадобилась бы никакая помощь.
Было бы хорошо иметь минимальный воспроизводитель для этой задачи. В журнале ясно видно, что ткач AspectJ активен, когда вы запускаете его с помощью
-javaagent. Я понятия не имею, как JOOQ работает внутри и использует ли он CGLIB или нет, возможно, это связано с вашим вопросом. Если бы я мог воспроизвести ситуацию и прикрепить к демо-приложению отладчик, было бы гораздо проще ответить на ваш вопрос.