Spring Boot 学习第八天:AOP代理机制对性能的影响

1 概述

        在讨论动态代理机制时,一个不可避免的话题是性能。无论采用JDK动态代理还是CGLIB动态代理,本质上都是在原有目标对象上进行了封装和转换,这个过程需要消耗资源和性能。而JDK和CGLIB动态代理的内部实现过程本身也存在很大差异。下面将讨论两种动态代理机制对系统运行性能所带来的影响。

2 测试案例设计

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

        为了能够基于不同的代理机制来创建对象,需要引入Spring中一个非常有用的注解,即@Scope。这个注解可以用来设置Bean的作用域,还可以用来指定代理模式ScopedProxyMode,在Spring中,ScopedProxyMode是一个枚举,代码如下:

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

    private ScopedProxyMode() {
    }
}

        这里的INTERFACES代表的就是JDK动态代理,而TARGET_CLASS使用的则是CGLIB动态代理。现在,创建两个配置类JDKProxyConfig和CGLIBProxyConfig,分别针对AccountServiceImpl指定两种不同的代理机制。JDKProxyConfig代码如下:

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

        CGLIBProxyConfig代码如下:

@EnableAspectJAutoProxy
@Configuration
public class CGLIBProxyConfig {

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

        借助于这两个配置类,就可以通过AnnotationConfigApplicationContext这个基于注解配置的应用上下文对象来获取添加了不同代理机制的AccountServiceImpl对象。准备工作已经完成,编写一个测试用例来对不同代理机制的性能进行量化。代码如下:

public class ProxyTest {
    private static final Logger LOGGER = Logger.getLogger(ProxyTest.class);

    @Test
    public void testAopProxyPerformance() throws MinimumAccountException {
        int countObjects = 5000;
        AccountServiceImpl[] unproxiedClasses = new AccountServiceImpl[countObjects];
        for (int i = 0; i < countObjects; i++) {
            unproxiedClasses[i] = new AccountServiceImpl();
        }
        AccountService[] cglibProxyClasses = new AccountService[countObjects];
        AccountService accountService = null;
        for (int i = 0; i < countObjects; i++) {
            accountService = new AnnotationConfigApplicationContext(CGLIBProxyConfig.class).getBean(AccountService.class);
            cglibProxyClasses[i] = accountService;
        }
        AccountService[] jdkProxyClasses = new AccountService[countObjects];
        for (int i = 0; i < countObjects; i++) {
            accountService = new AnnotationConfigApplicationContext(JDKProxyConfig.class).getBean(AccountService.class);
            jdkProxyClasses[i] = accountService;
        }

        long noProxy = invokeTargetObjects(countObjects, unproxiedClasses);
        displayResults("NOProxy",noProxy);
        long jdkProxy = invokeTargetObjects(countObjects, jdkProxyClasses);
        displayResults("JDKProxy",jdkProxy);
        long cglibProxy = invokeTargetObjects(countObjects, cglibProxyClasses);
        displayResults("cglibProxy",cglibProxy);

    }
    private void displayResults(String label, long timeTook) {
        LOGGER.info(label + ": " + timeTook + "(ns) " + (timeTook / 1000000) + "(ms)");
    }
    private long invokeTargetObjects(int countObjects,AccountService[] classes) throws MinimumAccountException {
        long start = System.nanoTime();
        Account source = new Account(101,"Account1");
        Account dest = new Account(102,"Account2");
        for (int i = 0; i < countObjects; i++) {
            classes[i].doAccountTransaction(source, dest, 100);
        }
        long end = System.nanoTime();
        return end - start;
    }
}

        运行结果:

        可以看到,分别针对不使用代理、使用JDK代理和CGLIB代理的场景,创建了5000个AccountServiceImpl对象实例,并记录它们的创建时间。以上量化结果取决于不同的机器配置,但不影响得出结论。从结果中不难看出,JDK动态代理在性能上优于CGLIB动态代理,但相差并不大。 

  其他类的代码如下:

public class Account {
    private String accountName;
    private Integer accountNumber;

    public String getAccountName() {
        return accountName;
    }
    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }

    public Integer getAccountNumber() {
        return accountNumber;
    }
    public void setAccountNumber(Integer accountNumber) {
        this.accountNumber = accountNumber;
    }

    public Account(Integer accountNumber, String accountName) {
        this.accountNumber = accountNumber;
        this.accountName = accountName;
    }
}
public interface AccountService {
	
	boolean doAccountTransaction(Account source, Account dest, int amount);
}
public class AccountServiceImpl implements AccountService {
	@Override
	public boolean doAccountTransaction(Account source, Account dest, int amount) {
		
		return true;
	}

}

         


http://www.niftyadmin.cn/n/5534867.html

相关文章

CSS filter(滤镜)属性,并实现页面置灰效果

目录 一、filter&#xff08;滤镜&#xff09;属性 二、准备工作 三、常用的filter属性值 1、blur(px) 2、brightness(%) 3、contrast(%) 4、grayscale(%) 5、opacity(%) 6、saturate(%) 7、sepia(%) 8、invert(%) 9、hue-rotate(deg) 10、drop-shadow(h-shadow v…

flutter开发实战-ListWheelScrollView与自定义TimePicker时间选择器

flutter开发实战-ListWheelScrollView与自定义TimePicker 最近在使用时间选择器的时候&#xff0c;需要自定义一个TimePicker效果&#xff0c;当然这里就使用了ListWheelScrollView。ListWheelScrollView与ListView类似&#xff0c;但ListWheelScrollView渲染效果类似滚筒效果…

使用React复刻ThreeJS官网示例——keyframes动画

最近在看three.js相关的东西&#xff0c;想着学习一下threejs给的examples。源码是用html结合js写的&#xff0c;恰好最近也在学习react&#xff0c;就用react框架学习一下。 本文参考的是threeJs给的第一个示例 three.js examples (threejs.org) 一、下载threeJS源码 通常我们…

【LC刷题】DAY22:491 46 47 332 51 37

【LC刷题】DAY22&#xff1a;491 46 47 332 51 37 文章目录 【LC刷题】DAY22&#xff1a;491 46 47 332 51 37491. 非递减子序列 [link](https://leetcode.cn/problems/non-decreasing-subsequences/description/)46. 全排列 [link](https://leetcode.cn/problems/permutations…

Kafka集群部署(手把手部署图文详细版)

1.1.1 部署zookpeer 在node02下载并解压zookeeper软件包 cd /usr/local wget https://archive.apache.org/dist/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz 或者&#xff1a;scp cat192.168.28.100:/home/cat/zookeeper-3.4.6.tar.gz /tmp&#xff08;注意目录&#xf…

Feign 原理流程图练习-01

目录 作业: 老师给的参考流程图 要求 解答 知识扩展 Feign基础原理 接口定义 代理对象生成 请求调用 请求发送 响应处理 容错与熔断 总结 作业: 老师给的参考流程图 pdf版本 【金山文档 | WPS云文档】 Feign https://kdocs.cn/l/ctbagIyxN348 ​ 要求 结合上面…

单例模式(下)

文章目录 文章介绍步骤安排及单例讲解step1&#xff1a;注册单例类型&#xff08;main.cpp&#xff09;step2&#xff1a;定义类和私有构造函数&#xff08;keyboardinputmanager.h&#xff09;step3:&#xff08;keyboardinputmanager.cpp&#xff09;step4&#xff1a;在qml中…

Neo4j 图数据库 高级操作

Neo4j 图数据库 高级操作 文章目录 Neo4j 图数据库 高级操作1 批量添加节点、关系1.1 直接使用 UNWIND 批量创建关系1.2 使用 CSV 文件批量创建关系1.3 选择方法 2 索引2.1 创建单一属性索引2.2 创建组合属性索引2.3 创建全文索引2.4 列出所有索引2.5 删除索引2.6 注意事项 3 清…