Spring Boot进阶:原理、实战与面试题分析
上QQ阅读APP看书,第一时间看更新

3.3.1 测试案例设计

为了量化不同动态代理机制对性能的影响程度,我们将设计一个案例,在该案例中同样使用3.1.2节中介绍的AccountService接口以及它的实现类AccountServiceImpl。我们将通过创建一定数量的AccountServiceImpl实例并调用它的doAccountTransaction()方法,触发动态代理机制。

为了能够基于不同的代理机制来创建代理对象,需要引入Spring中一个非常有用的注解,即@Scope注解。我们已经在第2章中了解到该注解可以用来设置Bean的作用域。其实,@Scope注解还可以用来指定代理模式ScopedProxyMode。在Spring中,Scoped-ProxyMode是一个枚举,如代码清单3-15所示。

代码清单3-15 ScopedProxyMode枚举类代码

public enum ScopedProxyMode {
    DEFAULT,
    NO,
    INTERFACES,
    TARGET_CLASS;
}

请注意,ScopedProxyMode中的INTERFACES代表的就是JDK动态代理,而TARGET_CLASS使用的则是CGLIB动态代理。

现在,让我们创建两个配置类JDKProxyConfig和CGLIBProxyConfig,分别针对AccountServiceImpl指定两种不同的代理机制。其中,JDKProxyConfig如代码清单3-16所示。

代码清单3-16 JDKProxyConfig类代码

@Configuration
@EnableAspectJAutoProxy
public class JDKProxyConfig {
    @Bean
    @Scope(proxyMode=ScopedProxyMode.INTERFACES)
    public AccountService accountService(){
        return new AccountServiceImpl();
    }
}

而CGLIBProxyConfig则如代码清单3-17所示。

代码清单3-17 CGLIBProxyConfig类代码

@Configuration
@EnableAspectJAutoProxy
public class CGLIBProxyAppConfig {
    @Bean
    @Scope(proxyMode=ScopedProxyMode.TARGET_CLASS)
    public AccountService accountService(){
        return new AccountServiceImpl();
    }
}

借助于这两个配置文件,我们就可以通过AnnotationConfigApplicationContext这个基于注解配置的应用上下文对象来获取添加了不同代理机制的AccountServiceImpl对象,实现方式如代码清单3-18所示。

代码清单3-18 基于动态代理获取AccountService实现类代码

//基于JDKProxyConfig获取AccountServiceImpl对象
AccountService accountService = new AnnotationConfigApplicationContext(JDKProxyConfig.class).getBean(AccountService.class);

//基于CGLIBProxyConfig获取AccountServiceImpl对象
AccountService accountService = new AnnotationConfigApplicationContext(CGLIBProxyConfig.class).getBean(AccountService.class);

现在,准备工作已经完成,让我们编写一个测试用例来对不同代理机制的性能进行量化。测试用例如代码清单3-19所示。

代码清单3-19 动态代理性能测试用例代码

@Test
public void testAopProxyPerformance() {
    int countofObjects = 5000;
    AccountServiceImpl[] unproxiedClasses = new AccountServiceImpl[countofObjects];
    for (int i = 0; i < countofObjects; i++) {
        unproxiedClasses[i] = new AccountServiceImpl();
    }

    AccountService[] cglibProxyClasses = new AccountService[countofObjects];
    AccountService accountService = null;
    for (int i = 0; i < countofObjects; i++) {
        accountService = new AnnotationConfigApplicationContext(CGLIBProxyAppConfig.class).getBean(AccountService.class);
        cglibProxyClasses[i] = accountService;
    }

    AccountService[] jdkProxyClasses = new AccountService[countofObjects];
    for (int i = 0; i < countofObjects; i++) {
        accountService = new AnnotationConfigApplicationContext(JDKProxyAppConfig.class).getBean(AccountService.class);
        jdkProxyClasses[i] = accountService;
    }

    long timeTookForUnproxiedObjects = invokeTargetObjects(countofObjects, unproxiedClasses);
    displayResults("NOProxy", timeTookForUnproxiedObjects);

    long timeTookForJdkProxiedObjects = invokeTargetObjects(countofObjects, jdkProxyClasses);
    displayResults("JDKProxy", timeTookForJdkProxiedObjects);

    long timeTookForCglibProxiedObjects = invokeTargetObjects(countofObjects, cglibProxyClasses);
    displayResults("CGLIBProxy", timeTookForCglibProxiedObjects);
}

可以看到,我们分别针对不使用代理、使用JDK代理以及使用CGLIB代理的场景,创建了5000个AccountServiceImpl对象实例,并记录它们的创建时间。完整的代码可以参考:https://github.com/tianminzheng/spring-boot-examples/tree/main/SpringAopProxyExample