【发布时间】:2021-08-05 16:45:05
【问题描述】:
我很确定这是一个错误配置,我只是不知道是哪一部分,因为我发现 AOP 教程都使用了 Maven,但我使用的是 Gradle。
所以我采用了 start.spring.io 创建的项目(Kotlin 1.5.21、Gradle 7.1.1、Spring Boot 2.5.3)和 spring-boot-starter-web 的启动器。
plugins {
id("org.springframework.boot") version "2.5.3"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.5.21"
kotlin("plugin.spring") version "1.5.21"
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
}
然后我添加了
implementation("org.springframework.boot:spring-boot-starter-aop")
和一个建议
@Target(AnnotationTarget.FUNCTION) @MustBeDocumented
annotation class UserAuthorized(val roles: Array<String>)
@Component @Aspect
class UserAuthorizedAdvice {
@Pointcut("@target(com.example.springbootplayground2.auth.UserAuthorized)")
fun userAuthorizedMethods() {}
@Before("userAuthorizedMethods()")
fun checkIfUserHasRequiredRole(jp: JoinPoint) {...}
}
现在应用程序在启动时崩溃(最后出现错误消息)。我尝试通过添加 @EnableAspectJAutoProxy 注释来修复它,但它没有帮助。
@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass=true)
class SpringbootPlayground2Application
在 Linux 上,这会崩溃
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tomcatServletWebServerFactory' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryConfiguration$EmbeddedTomcat.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'errorPageCustomizer' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.class]: Unsatisfied dependency expressed through method 'errorPageCustomizer' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dispatcherServletRegistration' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean]: Factory method 'dispatcherServletRegistration' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'multipartConfigElement' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/MultipartAutoConfiguration.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Unexpected AOP exception; nested exception is java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "cause" is null
引起
Caused by: java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "cause" is null
at org.springframework.cglib.core.CodeGenerationException.<init>(CodeGenerationException.java:25) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:587) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:585) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:110) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:108) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54) ~[spring-core-5.3.9.jar:5.3.9]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:134) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:572) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:419) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:57) ~[spring-aop-5.3.9.jar:5.3.9]
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:206) ~[spring-aop-5.3.9.jar:5.3.9]
在 MacOs (M1-cpu) 上,这会因java.lang.NullPointerException: null 而崩溃,原因是
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:142) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:104) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:450) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:199) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory$$FastClassBySpringCGLIB$$9c83fa9f.invoke(<generated>) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779) ~[spring-aop-5.3.9.jar:5.3.9]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.9.jar:5.3.9]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.9.jar:5.3.9]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:180) ~[spring-aop-5.3.9.jar:5.3.9]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.9.jar:5.3.9]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.9.jar:5.3.9]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.9.jar:5.3.9]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.9.jar:5.3.9]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692) ~[spring-aop-5.3.9.jar:5.3.9]
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory$$EnhancerBySpringCGLIB$$f87b4803.getWebServer(<generated>) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:182) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:160) ~[spring-boot-2.5.3.jar:2.5.3]
... 8 common frames omitted
Caused by: java.lang.IllegalStateException: StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[] failed to start
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.rethrowDeferredStartupExceptions(TomcatWebServer.java:187) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:126) ~[spring-boot-2.5.3.jar:2.5.3]
... 25 common frames omitted
更新
在这里你可以找到minimal version of my project
更新2
该项目现在有一个 solution branch 包含 kriegaex 的修复。
【问题讨论】:
-
在要求您提供MCVE 让我重现您的问题之前,我冒着风险猜测:您是否尝试限制切入点范围,添加
&& within(my.base.pkg..*)? -
我的切入点现在看起来像这样:
@Pointcut("@target(com.example.springbootplayground2.auth.UserAuthorized) && within(com.example..* )")。正面:应用程序在启动时不再失败。否定:建议甚至没有添加到我自己的课程中,特别是com.example.springbootplayground2.auth.AuthTestController -
就像我想的那样,你的切入点太宽泛了。但是现在没有应用任何方面,不应该发生。你确定没有错字,比如
com.example.*(单点)而不是com.example..*(双点)? Spring AOP 和组件扫描是否配置正确?另一个简单的切入点,例如execution(* my.package.MyClass.myMethod(..))是否有效?我认为,GitHub 上的 MCVE 会有所帮助。 -
a) 我不明白切入点怎么会太宽泛(尽管看起来确实如此)。这不像注释
com.example.springbootplayground2.auth.UserAuthorized可能存在于其他地方。 b) 不,我现在在我的切入点中看不到任何错字 c) Spring AOP 可能配置错误,但我不知道更好但幸运的是您可以签入 d) MCVE:github.com/simon-void/SpringWebAOP-MCVE -
(a) 因为
@target是一个动态切入点,其可能的目标只能在运行时确定。因此,Spring 为它找到的所有组件创建代理,包括 Spring 内部的。使用 AspectJ,您不会遇到这个问题,因此如果您愿意,可以切换到 AspectJ。但实际上,在这种情况下,限制切入点范围要容易得多。 (d) 我去看看。感谢您提供 GitHub 链接。
标签: spring spring-mvc gradle spring-aop