一、需求分析

这个需求比较简单

  • 需求:任意业务层接口执行均可显示其执行效率(执行时长)

这个的目的是查看每个业务层执行的时间,这样就可以监控出哪个业务比较耗时,将其查找出来方便优化。

具体实现的思路:

(1) 开始执行方法之前记录一个时间

(2) 执行方法

(3) 执行完方法之后记录一个时间

(4) 用后一个时间减去前一个时间的差值,就是我们需要的结果。

所以要在方法执行的前后添加业务,经过分析我们将采用环绕通知

说明:原始方法如果只执行一次,时间太快,两个时间差可能为0,所以我们要执行万次来计算时间差。

二、环境准备

  • 创建一个Maven项目

  • pom.xml添加Spring依赖

    1. <dependencies>
    2.    <dependency>
    3.      <groupId>org.springframework</groupId>
    4.      <artifactId>spring-context</artifactId>
    5.      <version>5.2.10.RELEASE</version>
    6.    </dependency>
    7.    <dependency>
    8.      <groupId>org.springframework</groupId>
    9.      <artifactId>spring-jdbc</artifactId>
    10.      <version>5.2.10.RELEASE</version>
    11.    </dependency>
    12.    <dependency>
    13.      <groupId>org.springframework</groupId>
    14.      <artifactId>spring-test</artifactId>
    15.      <version>5.2.10.RELEASE</version>
    16.    </dependency>
    17.    <dependency>
    18.      <groupId>org.aspectj</groupId>
    19.      <artifactId>aspectjweaver</artifactId>
    20.      <version>1.9.4</version>
    21.    </dependency>
    22.    <dependency>
    23.      <groupId>mysql</groupId>
    24.      <artifactId>mysql-connector-java</artifactId>
    25.      <version>5.1.47</version>
    26.    </dependency>
    27.    <dependency>
    28.      <groupId>com.alibaba</groupId>
    29.      <artifactId>druid</artifactId>
    30.      <version>1.1.16</version>
    31.    </dependency>
    32.    <dependency>
    33.      <groupId>org.mybatis</groupId>
    34.      <artifactId>mybatis</artifactId>
    35.      <version>3.5.6</version>
    36.    </dependency>
    37.    <dependency>
    38.      <groupId>org.mybatis</groupId>
    39.      <artifactId>mybatis-spring</artifactId>
    40.      <version>1.3.0</version>
    41.    </dependency>
    42.    <dependency>
    43.      <groupId>junit</groupId>
    44.      <artifactId>junit</artifactId>
    45.      <version>4.12</version>
    46.      <scope>test</scope>
    47.    </dependency>
    48.  </dependencies>
  • 添加AccountService、AccountServiceImpl、AccountDao与Account类

    1. public interface AccountService {
    2.    void save(Account account);
    3.    void delete(Integer id);
    4.    void update(Account account);
    5.    List<Account> findAll();
    6.    Account findById(Integer id);
    7. }

    8. @Service
    9. public class AccountServiceImpl implements AccountService {

    10.    @Autowired
    11.    private AccountDao accountDao;

    12.    public void save(Account account) {
    13.        accountDao.save(account);
    14.   }

    15.    public void update(Account account){
    16.        accountDao.update(account);
    17.   }

    18.    public void delete(Integer id) {
    19.        accountDao.delete(id);
    20.   }

    21.    public Account findById(Integer id) {
    22.        return accountDao.findById(id);
    23.   }

    24.    public List<Account> findAll() {
    25.        return accountDao.findAll();
    26.   }
    27. }
    28. public interface AccountDao {

    29.    @Insert("insert into tbl_account(name,money)values(#{name},#{money})")
    30.    void save(Account account);

    31.    @Delete("delete from tbl_account where id = #{id} ")
    32.    void delete(Integer id);

    33.    @Update("update tbl_account set name = #{name} , money = #{money} where id = #{id} ")
    34.    void update(Account account);

    35.    @Select("select * from tbl_account")
    36.    List<Account> findAll();

    37.    @Select("select * from tbl_account where id = #{id} ")
    38.    Account findById(Integer id);
    39. }

    40. public class Account implements Serializable {

    41.    private Integer id;
    42.    private String name;
    43.    private Double money;
    44.    //setter..getter..toString方法省略
    45. }
  • resources下提供一个jdbc.properties,并有如下数据

    1. jdbc.driver=com.mysql.jdbc.Driver
    2. jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
    3. jdbc.username=root
    4. jdbc.password=root

  • 创建相关配置类

    1. //Spring配置类:SpringConfig
    2. @Configuration
    3. @ComponentScan("com.itheima")
    4. @PropertySource("classpath:jdbc.properties")
    5. @Import({JdbcConfig.class,MybatisConfig.class})
    6. public class SpringConfig {
    7. }
    8. //JdbcConfig配置类
    9. public class JdbcConfig {
    10.    @Value("${jdbc.driver}")
    11.    private String driver;
    12.    @Value("${jdbc.url}")
    13.    private String url;
    14.    @Value("${jdbc.username}")
    15.    private String userName;
    16.    @Value("${jdbc.password}")
    17.    private String password;

    18.    @Bean
    19.    public DataSource dataSource(){
    20.        DruidDataSource ds = new DruidDataSource();
    21.        ds.setDriverClassName(driver);
    22.        ds.setUrl(url);
    23.        ds.setUsername(userName);
    24.        ds.setPassword(password);
    25.        return ds;
    26.   }
    27. }
    28. //MybatisConfig配置类
    29. public class MybatisConfig {

    30.    @Bean
    31.    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
    32.        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
    33.        ssfb.setTypeAliasesPackage("com.itheima.domain");
    34.        ssfb.setDataSource(dataSource);
    35.        return ssfb;
    36.   }

    37.    @Bean
    38.    public MapperScannerConfigurer mapperScannerConfigurer(){
    39.        MapperScannerConfigurer msc = new MapperScannerConfigurer();
    40.        msc.setBasePackage("com.itheima.dao");
    41.        return msc;
    42.   }
    43. }
  • 编写Spring整合Junit的测试类

    1. @RunWith(SpringJUnit4ClassRunner.class)
    2. @ContextConfiguration(classes = SpringConfig.class)
    3. public class AccountServiceTestCase {
    4.    @Autowired
    5.    private AccountService accountService;

    6.    @Test
    7.    public void testFindById(){
    8.        Account ac = accountService.findById(2);
    9.   }

    10.    @Test
    11.    public void testFindAll(){
    12.        List<Account> all = accountService.findAll();
    13.   }

    14. }

最终创建好的项目结构如下:

三、功能开发

步骤1:开启SpringAOP的注解功能

在Spring的主配置文件SpringConfig类中添加注解

  1. @EnableAspectJAutoProxy
步骤2:创建AOP的通知类
  • 该类要被Spring管理,需要添加@Component

  • 要标识该类是一个AOP的切面类,需要添加@Aspect

  • 配置切入点表达式,需要添加一个方法,并添加@Pointcut

  1. @Component
  2. @Aspect
  3. public class ProjectAdvice {
  4.    //配置业务层的所有方法
  5.    @Pointcut("execution(* com.itheima.service.*Service.*(..))")
  6.    private void servicePt(){}
  7.    
  8.    public void runSpeed(){
  9.        
  10.   }
  11. }
步骤3:添加环绕通知

在runSpeed()方法上添加@Around

  1. @Component
  2. @Aspect
  3. public class ProjectAdvice {
  4.    //配置业务层的所有方法
  5.    @Pointcut("execution(* com.itheima.service.*Service.*(..))")
  6.    private void servicePt(){}
  7.    //@Around("ProjectAdvice.servicePt()") 可以简写为下面的方式
  8.    @Around("servicePt()")
  9.    public Object runSpeed(ProceedingJoinPoint pjp){
  10.        Object ret = pjp.proceed();
  11.        return ret;
  12.   }
  13. }

注意:目前并没有做任何增强

步骤4:完成核心业务,记录万次执行的时间
  1. @Component
  2. @Aspect
  3. public class ProjectAdvice {
  4.    //配置业务层的所有方法
  5.    @Pointcut("execution(* com.itheima.service.*Service.*(..))")
  6.    private void servicePt(){}
  7.    //@Around("ProjectAdvice.servicePt()") 可以简写为下面的方式
  8.    @Around("servicePt()")
  9.    public void runSpeed(ProceedingJoinPoint pjp){
  10.        
  11.        long start = System.currentTimeMillis();
  12.        for (int i = 0; i < 10000; i++) {
  13.           pjp.proceed();
  14.       }
  15.        long end = System.currentTimeMillis();
  16.        System.out.println("业务层接口万次执行时间: "+(end-start)+"ms");
  17.   }
  18. }
步骤5:运行单元测试类

注意:因为程序每次执行的时长是不一样的,所以运行多次最终的结果是不一样的。

步骤6:程序优化

目前程序所面临的问题是,多个方法一起执行测试的时候,控制台都打印的是:

业务层接口万次执行时间:xxxms

我们没有办法区分到底是哪个接口的哪个方法执行的具体时间,具体如何优化?

  1. @Component
  2. @Aspect
  3. public class ProjectAdvice {
  4.    //配置业务层的所有方法
  5.    @Pointcut("execution(* com.itheima.service.*Service.*(..))")
  6.    private void servicePt(){}
  7.    //@Around("ProjectAdvice.servicePt()") 可以简写为下面的方式
  8.    @Around("servicePt()")
  9.    public void runSpeed(ProceedingJoinPoint pjp){
  10.        //获取执行签名信息
  11.        Signature signature = pjp.getSignature();
  12.        //通过签名获取执行操作名称(接口名)
  13.        String className = signature.getDeclaringTypeName();
  14.        //通过签名获取执行操作名称(方法名)
  15.        String methodName = signature.getName();
  16.        
  17.        long start = System.currentTimeMillis();
  18.        for (int i = 0; i < 10000; i++) {
  19.           pjp.proceed();
  20.       }
  21.        long end = System.currentTimeMillis();
  22.        System.out.println("万次执行:"+ className+"."+methodName+"---->" +(end-start) + "ms");
  23.   }
  24. }
步骤7:运行单元测试类

Java开发学习(十七)----AOP案例之测量业务层接口执行效率的更多相关文章

  1. Java开发学习(十五)----AOP入门案例及其工作流程解析

    一.AOP简介 1.1 什么是AOP AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构. OOP(Object Oriented ...

  2. Java开发学习(十六)----AOP切入点表达式及五种通知类型解析

    一.AOP切入点表达式 对于AOP中切入点表达式,总共有三个大的方面,分别是语法格式.通配符和书写技巧. 1.1 语法格式 首先我们先要明确两个概念: 切入点:要进行增强的方法 切入点表达式:要进行增 ...

  3. Java开发学习(二十七)----SpringMVC之Rest风格解析及快速开发

    一.REST简介 REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格 当我们想表示一个网络资源的时候,可以使用两种方式: 传统风格资源描 ...

  4. Java开发学习(三十七)----SpringBoot多环境配置及配置文件分类

    一.多环境配置 在工作中,对于开发环境.测试环境.生产环境的配置肯定都不相同,比如我们开发阶段会在自己的电脑上安装 mysql ,连接自己电脑上的 mysql 即可,但是项目开发完毕后要上线就需要该配 ...

  5. Java开发学习心得(一):SSM环境搭建

    目录 Java开发学习心得(一):SSM环境搭建 1 SSM框架 1.1 Spring Framework 1.2 Spring MVC Java开发学习心得(一):SSM环境搭建 有一点.NET的开 ...

  6. Java开发学习(二十二)----Spring事务属性、事务传播行为

    一.事务配置 上面这些属性都可以在@Transactional注解的参数上进行设置. readOnly:true只读事务,false读写事务,增删改要设为false,查询设为true. timeout ...

  7. Java开发学习(二十四)----SpringMVC设置请求映射路径

    一.环境准备 创建一个Web的Maven项目 参考Java开发学习(二十三)----SpringMVC入门案例.工作流程解析及设置bean加载控制中环境准备 pom.xml添加Spring依赖 < ...

  8. Java开发学习(二十五)----使用PostMan完成不同类型参数传递

    一.请求参数 请求路径设置好后,只要确保页面发送请求地址和后台Controller类中配置的路径一致,就可以接收到前端的请求,接收到请求后,如何接收页面传递的参数? 关于请求参数的传递与接收是和请求方 ...

  9. Java开发学习(二十六)----SpringMVC返回响应结果

    SpringMVC接收到请求和数据后,进行了一些处理,当然这个处理可以是转发给Service,Service层再调用Dao层完成的,不管怎样,处理完以后,都需要将结果告知给用户. 比如:根据用户ID查 ...

随机推荐

  1. victoriaMetrics无法获取抓取target的问题

    victoriaMetrics无法获取抓取target的问题 问题描述 最近在新环境中部署了一个服务,其暴露的指标路径为:10299/metrics,配置文件如下(名称字段有修改): apiVersi ...

  2. 好客租房10-jsx的基本使用

    1.1createElement()的问题 1繁琐不简洁 2不直观 无法一眼看出所描述的结构 3不优雅 用户体验不爽 React.createElement("div",     ...

  3. 使用acme.sh自动申请、续期、部署免费的SSL证书

    参考文档:https://github.com/acmesh-official/acme.sh 一个使用纯shell操作的免费SSL证书申请部署工具. 免费的SSL证书由以下CA机构提供: ZeroS ...

  4. OpenWrt 20.02.2 小米路由器3G配置CP1025网络打印

    家里的施乐 CP116w 工作快五年了终于罢工了. 黑粉报错, 自己也不会拆, 只能搁置了. 后来换了个 HP CP1025. 这个打印机也不错, 墨盒便宜没什么废粉, 就是启动慢一点, 而且 -- ...

  5. 【仿真】Carla介绍与基本使用 [1] (附代码 基础版)

    0. 参考与前言 主要介绍无人驾驶的仿真环境CARLA,开源社区维护,以下为相关参考链接: Carla官方文档 建议后续找的时候 先按好版本号,有些功能/api 是新版本里有的 Carla官方gith ...

  6. 碎碎念软件研发02:敏捷之Scrum

    一.什么是 Scrum 1.1 Scrum 定义 Scrum 是敏捷开发方法之一,它使用比较广泛. 敏捷的其它开发方法还有 XP(极限编程).FDD(特性驱动开发).Crystal(水晶方法).TDD ...

  7. 《回炉重造 Java 基础》——集合(容器)

    整体框架 绿色代表接口/抽象类:蓝色代表类. 主要由两大接口组成,一个是「Collection」接口,另一个是「Map」接口. 前言 以前刚开始学习「集合」的时候,由于没有好好预习,也没有学好基础知识 ...

  8. python各版本下载

    python2源码压缩包 Python-2.7.9.tgz   Python-2.7.10.tgz Python-2.7.11.tgz Python-2.7.12.tgz Python-2.7.13. ...

  9. 从零开始学Java——个人笔记(持续更新中)

    从零开始学Java 学习流程 第一阶段:建立编程思想 Java概述 变量 运算符 控制结构 数组.排序和查找 面向对象编程(基础) 面向对象编程(中级) 项目&学习以致用 编程之乐 第二阶段: ...

  10. html实现3d视觉特效

    <html> <head> <title>HTML5实现3D球效果</title> <style type="text/css" ...