0


【Spring教程18】Spring框架实战:利用Aop测定业务层接口执行效率代码实例详解

欢迎大家回到《Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《详解解读AOP通知类型的使用》

在这里插入图片描述

1 需求分析

这个需求也比较简单,前面我们在介绍AOP的时候已经演示过:

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

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

具体实现的思路:

(1) 开始执行方法之前记录一个时间
(2) 执行方法
(3) 执行完方法之后记录一个时间
(4) 用后一个时间减去前一个时间的差值,就是我们需要的结果。

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

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

2 环境准备

  • 创建一个Maven项目
  • pom.xml添加Spring依赖
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.0</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies>
  • 添加AccountService、AccountServiceImpl、AccountDao与Account类
publicinterfaceAccountService{voidsave(Account account);voiddelete(Integer id);voidupdate(Account account);List<Account>findAll();AccountfindById(Integer id);}@ServicepublicclassAccountServiceImplimplementsAccountService{@AutowiredprivateAccountDao accountDao;publicvoidsave(Account account){
        accountDao.save(account);}publicvoidupdate(Account account){
        accountDao.update(account);}publicvoiddelete(Integer id){
        accountDao.delete(id);}publicAccountfindById(Integer id){return accountDao.findById(id);}publicList<Account>findAll(){return accountDao.findAll();}}publicinterfaceAccountDao{@Insert("insert into tbl_account(name,money)values(#{name},#{money})")voidsave(Account account);@Delete("delete from tbl_account where id = #{id} ")voiddelete(Integer id);@Update("update tbl_account set name = #{name} , money = #{money} where id = #{id} ")voidupdate(Account account);@Select("select * from tbl_account")List<Account>findAll();@Select("select * from tbl_account where id = #{id} ")AccountfindById(Integer id);}publicclassAccountimplementsSerializable{privateInteger id;privateString name;privateDouble money;//setter..getter..toString方法省略}
  • resources下提供一个jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
jdbc.username=root
jdbc.password=root
  • 创建相关配置类
//Spring配置类:SpringConfig@Configuration@ComponentScan("com.itheima")@PropertySource("classpath:jdbc.properties")@Import({JdbcConfig.class,MybatisConfig.class})publicclassSpringConfig{}//JdbcConfig配置类publicclassJdbcConfig{@Value("${jdbc.driver}")privateString driver;@Value("${jdbc.url}")privateString url;@Value("${jdbc.username}")privateString userName;@Value("${jdbc.password}")privateString password;@BeanpublicDataSourcedataSource(){DruidDataSource ds =newDruidDataSource();
    ds.setDriverClassName(driver);
    ds.setUrl(url);
    ds.setUsername(userName);
    ds.setPassword(password);return ds;}}//MybatisConfig配置类publicclassMybatisConfig{@BeanpublicSqlSessionFactoryBeansqlSessionFactory(DataSource dataSource){SqlSessionFactoryBean ssfb =newSqlSessionFactoryBean();
        ssfb.setTypeAliasesPackage("com.itheima.domain");
        ssfb.setDataSource(dataSource);return ssfb;}@BeanpublicMapperScannerConfigurermapperScannerConfigurer(){MapperScannerConfigurer msc =newMapperScannerConfigurer();
        msc.setBasePackage("com.itheima.dao");return msc;}}
  • 编写Spring整合Junit的测试类
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes =SpringConfig.class)publicclassAccountServiceTestCase{@AutowiredprivateAccountService accountService;@TestpublicvoidtestFindById(){Account ac = accountService.findById(2);}@TestpublicvoidtestFindAll(){List<Account> all = accountService.findAll();}}

最终创建好的项目结构如下:
在这里插入图片描述

3 功能开发

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

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

@EnableAspectJAutoProxy

步骤2:创建AOP的通知类

  • 该类要被Spring管理,需要添加@Component
  • 要标识该类是一个AOP的切面类,需要添加@Aspect
  • 配置切入点表达式,需要添加一个方法,并添加@Pointcut
@Component@AspectpublicclassProjectAdvice{//配置业务层的所有方法@Pointcut("execution(* com.itheima.service.*Service.*(..))")privatevoidservicePt(){}publicvoidrunSpeed(){}}

步骤3:添加环绕通知
在runSpeed()方法上添加@Around

@Component@AspectpublicclassProjectAdvice{//配置业务层的所有方法@Pointcut("execution(* com.itheima.service.*Service.*(..))")privatevoidservicePt(){}//@Around("ProjectAdvice.servicePt()") 可以简写为下面的方式@Around("servicePt()")publicObjectrunSpeed(ProceedingJoinPoint pjp){Object ret = pjp.proceed();return ret;}}
注意:

目前并没有做任何增强

步骤4:完成核心业务,记录万次执行的时间

@Component@AspectpublicclassProjectAdvice{//配置业务层的所有方法@Pointcut("execution(* com.itheima.service.*Service.*(..))")privatevoidservicePt(){}//@Around("ProjectAdvice.servicePt()") 可以简写为下面的方式@Around("servicePt()")publicvoidrunSpeed(ProceedingJoinPoint pjp){long start =System.currentTimeMillis();for(int i =0; i <10000; i++){
            pjp.proceed();}long end =System.currentTimeMillis();System.out.println("业务层接口万次执行时间: "+(end-start)+"ms");}}

步骤5:运行单元测试类
在这里插入图片描述
注意:因为程序每次执行的时长是不一样的,所以运行多次最终的结果是不一样的。

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

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

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

@Component@AspectpublicclassProjectAdvice{//配置业务层的所有方法@Pointcut("execution(* com.itheima.service.*Service.*(..))")privatevoidservicePt(){}//@Around("ProjectAdvice.servicePt()") 可以简写为下面的方式@Around("servicePt()")publicvoidrunSpeed(ProceedingJoinPoint pjp){//获取执行签名信息Signature signature = pjp.getSignature();//通过签名获取执行操作名称(接口名)String className = signature.getDeclaringTypeName();//通过签名获取执行操作名称(方法名)String methodName = signature.getName();long start =System.currentTimeMillis();for(int i =0; i <10000; i++){
            pjp.proceed();}long end =System.currentTimeMillis();System.out.println("万次执行:"+ className+"."+methodName+"---->"+(end-start)+"ms");}}

步骤7:运行单元测试类
在这里插入图片描述

4 补充说明

当前测试的接口执行效率仅仅是一个理论值,并不是一次完整的执行过程。
这块只是通过该案例把AOP的使用进行了学习,具体的实际值是有很多因素共同决定的。

标签: spring java 后端

本文转载自: https://blog.csdn.net/shenchengyv/article/details/134866492
版权归原作者 老牛源码 所有, 如有侵权,请联系我们删除。

“【Spring教程18】Spring框架实战:利用Aop测定业务层接口执行效率代码实例详解”的评论:

还没有评论