好吧,我需要将一些 CDI 拦截器迁移到 Spring Boot,并且我编写了一个简单的“概念验证”测试用例:
package ch.cypherk.myapp.util.aop
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.EnableAspectJAutoProxy
import org.springframework.stereotype.Component
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner
import javax.inject.Inject
@RunWith(SpringJUnit4ClassRunner::class)
@SpringBootTest
class SimpleInterceptorIT{
companion object {
val expectedArg = "Hakuna Matata"
lateinit var interceptorOutput:String
}
@Inject
private lateinit var client:ClientClass
@Test
fun `interceptor works`(){
client.foo()
assertThat(interceptorOutput).isEqualTo("ch.cypherk.myapp.util.aop.TargetClass.foo(\"$expectedArg\")")
}
}
@Component
class TargetClass{
fun foo(arg:String){
println("I did something.")
}
}
@Component
class ClientClass(val target:TargetClass){
fun foo(){
target.foo("Hakuna Matata")
}
}
@Aspect
@Configuration
@EnableAspectJAutoProxy
class TestInterceptorConfiguration{
@Before("execution(* ch.cypherk.myapp.util.aop.TargetClass.*(..))")
fun intercept(joinPoint:JoinPoint){
val signature = joinPoint.signature
println(signature)
SimpleInterceptorIT.interceptorOutput =
"${signature.declaringTypeName}.${signature.name}(${
joinPoint.args
.map { when(it){
is String -> "\"$it\""
else -> it
}}
.joinToString(",")
})"
}
}
这些是该包中唯一的类。
输出:
void ch.cypherk.myapp.util.aop.TargetClass.foo(String)
I did something.
测试是绿色的。
现在让我们稍微扩大搜索范围......
@Aspect
@Configuration
@EnableAspectJAutoProxy
class TestInterceptorConfiguration{
@Before("execution(* ch.cypherk.myapp.util.aop.*.*(..))")
fun intercept(joinPoint:JoinPoint){
val signature = joinPoint.signature
println(signature)
SimpleInterceptorIT.interceptorOutput =
"${signature.declaringTypeName}.${signature.name}(${
joinPoint.args
.map { when(it){
is String -> "\"$it\""
else -> it
}}
.joinToString(",")
})"
}
}
这需要永恒才能开始。
是的,输出是
void ch.cypherk.myapp.util.aop.ClientClass.foo()
void ch.cypherk.myapp.util.aop.TargetClass.foo(String)
I did something.
是的,测试是绿色的。
是的,测试运行只需117ms
。
但是 Spring 需要很长时间才能启动。
为什么?更重要的是,我能做些什么呢?因为这是非常不好的。我查看了 spring-boot-starter-aop
并且它定义了
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.4.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
正如您所注意到的,所有这些都是编译范围的。
我的期望是,这一切都将在编译时编织。 事实似乎并非如此。或者即使是这样,它也不会阻止 Spring 对包做一些奇怪的事情。
我希望能得到一些帮助来理解这里发生的事情。
最佳答案
我不确定我如何理解aspectjweaver,在加载时向Java类引入建议
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
编译时编织是最简单的方法
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>UTF-8 </encoding>
</configuration>
<executions>
<execution>
<goals>
<!-- use this goal to weave all your main classes -->
<goal>compile</goal>
<!-- use this goal to weave all your test classes -->
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
尚未尝试过,但希望这对您有用。
关于java - 了解 Spring AOP 拦截器开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56442727/