Хорошо, поэтому мне нужно перенести некоторые CDI Interceptors на 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-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>
Все это - как вы заметили - compile scoped.
Тогда я ожидал, что все это будет сплетено во время компиляции.
Кажется, это не так. Или, если это так, это не мешает Spring делать что-то странное с пакетом.
Буду признателен за помощь в понимании происходящего здесь.