java - 了解 Spring AOP 拦截器开销

标签 java spring-boot kotlin aspectj spring-aop

好吧,我需要将一些 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/

相关文章:

java - 更改字符串值与 if 语句的性能

java - RESTFB 返回的公开帖子很少

java - 有没有一种方法可以在 Spring Boot 应用程序中自定义 JPA 实体的仅一个特定 String 类型字段的序列化?

java - Mockito 无法创建 @Autowired Spring-Data Repository 的 Spy

android - fragment 实例被保留但子 fragment 没有重新附加

android - 当我尝试将更改监听器添加到搜索栏时,应用程序关闭(Android Studio,Kotlin)

java - 为什么我的二进制数据从网络服务器获取后会变大?

java - 使用正则表达式在 Java 中拆分嵌套的 JSON

Spring针对不同的api端点提供多种身份验证方法

android - Kotlin: 'length' 类型的表达式 'Int' 不能作为函数调用。找不到函数 'invoke()'