热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

SpringAOP的使用详解

这篇文章主要介绍了SpringAOP的使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

什么是AOP

AOP(Aspect Oriented Programming 面向切面编程),通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

常用于日志记录,性能统计,安全控制,事务处理,异常处理等等。

定义AOP术语

切面(Aspect):切面是一个关注点的模块化,这个关注点可能是横切多个对象;

连接点(Join Point):连接点是指在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候;

通知(Advice):指在切面的某个特定的连接点上执行的动作。Spring切面可以应用5中通知:

  • 前置通知(Before):在目标方法或者说连接点被调用前执行的通知;
  • 后置通知(After):指在某个连接点完成后执行的通知;
  • 返回通知(After-returning):指在某个连接点成功执行之后执行的通知;
  • 异常通知(After-throwing):指在方法抛出异常后执行的通知;
  • 环绕通知(Around):指包围一个连接点通知,在被通知的方法调用之前和之后执行自定义的方法。

切点(Pointcut):指匹配连接点的断言。通知与一个切入点表达式关联,并在满足这个切入的连接点上运行,例如:当执行某个特定的名称的方法。

引入(Introduction):引入也被称为内部类型声明,声明额外的方法或者某个类型的字段。

目标对象(Target Object):目标对象是被一个或者多个切面所通知的对象。

AOP代理(AOP Proxy):AOP代理是指AOP框架创建的对对象,用来实现切面契约(包括通知方法等功能)

织入(Wearving):指把切面连接到其他应用出程序类型或者对象上,并创建一个被通知的对象。或者说形成代理对象的方法的过程。

Spring对AOP的支持

  1. 基于代理的经典SpringAOP;
  2. 纯POJO切面;
  3. @AspectJ注解驱动的切面;
  4. 注入式AspectJ切面(适用于Spring各版本);

前三种都是SpringAOP实现的变体,SpringAOP构建在动态代理基础之上,因此,Spring对AOP的支持局限于方法的拦截。

切入点表达式

使用SpringAOP

SpringAOP的支持必须呀导入spring-aspects的jar包


  org.springframework
  spring-aspects
  4.3.5.RELEASE

使用注解定义切面

采用注解的方式定义切面以及通知

@Aspect
public class Audience {
  //使用@Pointcut注解声明频繁使用的切入点表达式
  @Pointcut("execution(* com.wqh.concert.Performance.perform(..))")
  public void performance(){}
  
  @Before("performance()")
  public void silenceCellPhones(){
    System.out.println("Sillencing cell phones");
  }
  @Before("performance()")
  public void takeSeats(){
    System.out.println("Task Seat");
  }
  @AfterReturning("performance()")
  public void applause(){
    System.out.println("CLAP CLAP CLAP");
  }
  @AfterThrowing("performance()")
  public void demandRefund(){
    System.out.println("Demand a Refund");
  }
}

另外需要在applicationContext.xml也就是spring的配置文件中添加配置:




在XML中声明切面

定义pojo类,这里只是把上面定义的注解全public class AudienceXML {

public void silenceCellPhones() {
  System.out.println("Sillencing cell phones");
}
public void takeSeats() {
  System.out.println("Task Seat");
}
public void applause() {
  System.out.println("CLAP CLAP CLAP");
}
public void demandRefund() {
  System.out.println("Demand a Refund");
}

applicationContext.xml配置




  
  
    
    
    
    
    
    
    
  

环绕通知

在springAOP中有五种通知,环绕通知是最为强大的通知。它能够让你编写的逻辑将被通知的目标方法完全包装起来。实际上就像在一个通知方法中同时编写前置通知和后置通知。
本片文章具体讲解环绕通知的使用。

使用注解

使用环绕通知定义切面:

@Aspect
public class AudienceAround {
  //使用@Pointcut注解声明频繁使用的切入点表达式
  @Pointcut("execution(* com.wqh.concert.Performance.perform(..))")
  public void performance(){}
  @Around("performance()")
  public void watchPerformance(ProceedingJoinPoint joinPoint){
    try {
      System.out.println("Silencing cell phones");
      System.out.println("Taking seats");
      joinPoint.proceed();
      System.out.println("Demanding a refund");
    } catch (Throwable throwable) {
      throwable.printStackTrace();
    }
  }
}

可以看到在上面的代码中,定义通知的时候在通知方法中添加了入参:ProceedingJoinPoint。在创建环绕通知的时候,这个参数是必须写的。因为在需要在通知中使用ProceedingJoinPoint.proceed()方法调用被通知的方法。

另外,如果忘记调用proceed()方法,那么通知实际上会阻塞对被通知方法的调用。

在XML中定义

首先去掉上面类的所有注解:这里为了区别就重新创建一个类

public class AudienceAroundXML {
  public void watchPerformance(ProceedingJoinPoint joinPoint){
    try {
      System.out.println("Silencing cell phones");
      System.out.println("Taking seats");
      joinPoint.proceed();
      System.out.println("Demanding a refund");
    } catch (Throwable throwable) {
      throwable.printStackTrace();
    }
  }
}

配置:



 

  
    
    
  

处理通知中的参数

Spring借助AspectJ的切点表达式语言来定义Spring切面

在spring中尝试使用其他指示器时,会抛出IllegalArgument-Exception异常。

如上的这些指示器,只有exception指示器是实际执行匹配的,而其他都是用来限制匹配的。

切面表达式分析

带参数的切点表达式分解

在该切点表达式中使用了args(trackNumber)限定符。表示传递给playTrack()方法的int类型参数也会传递到通知中去。参数名trackNumber也与切点方法签名中的参数相匹配。

创建切面

@Aspect
public class TrackCounter {
  @Pointcut("execution(* com.wqh.aop.CompactDisc.playTrack(int))&&args(trackNumber)")
  public void trackPlayder(int trackNumber){}
  @Before("trackPlayder(trackNumber)")
  public void countTrack(int trackNumber) {
    System.out.println("前置通知:targetNumber=" + trackNumber);
  }
}

连接点类

@Service
public class CompactDisc {
  public void playTrack(int trackNumber){
    System.out.println("trackNumber =" + trackNumber);
  }
}

XML配置




 
 

测试

@Test
public void testT(){
  ApplicationContext applicatiOnContext=
      new ClassPathXmlApplicationContext(
          new String[]{"classpath:/spring/applicationContext.xml"});
  CompactDisc compactDisc = (CompactDisc) applicationContext.getBean("compactDisc");
  compactDisc.playTrack(12);
}

上面给指定方法传入的参数是12,在通知中获取到了该参数

另外:在xml中配置切面来处理通知中的参数,其实也差不多,只是把切点表达式放到了XML配置文件中。

给类添加新的功能

引入Spring实战中的知识

在SpringAOP中,我们可以为Bean引入新的方法。代理拦截器调用并委托给实现该方法的其他对象。

当引入接口的方法被调用时,代理会把此调用委托给实现了新接口的某给其他对象。

使用注解方式引入

代码
首先是连接点的接口及其实现类

public interface Person {
  void say();
}
public class ChinesePerson implements Person {
  @Override
  public void say() {
    System.out.println("说中文");
  }
}

创建需要添加的功能,这里个人类扩展一个吃的功能

public interface Food {
  void eat();
}
public class ChineseFood implements Food {
  @Override
  public void eat() {
    System.out.println("吃中餐");
  }
}

编写切面

@Aspect
public class addFuction {
  @DeclareParents(value = "com.wqh.addfunction.Person+",defaultImpl = ChineseFood.class)
  public static Food food;
}

注意这里的表达式使用的式@DeclareParents注解;该注解所标注的静态属性指明了要引入的接口。

注解中使用的value属性指定哪种类型的bean要引入该接口,这里Person后后面的“+”号表示所有子类型,而不是该类的本身。defaultImpl,指定了为引入功能提供实现的类。

使用XML配置bean:






测试

@Test
public void testAdd(){
  ApplicationContext applicatiOnContext= new ClassPathXmlApplicationContext(
      "classpath:spring/applicationContext.xml");
  Person person = (Person) applicationContext.getBean("chinesePerson");
  person.say();
  //这里可以将chinesePerson bean转换为Food类,所以添加成功
  Food food = (Food) applicationContext.getBean("chinesePerson");
  food.eat();
}

在XML中引入

首先将上面的addFuction注解全部删除,其他不变;然后在xml中添加相应的配置:





 
   
     
   
 

这里的types-matching与上面的vale作用一样;

default-impl与defaultImpl作用一样,这也可以使用delegate-ref;当然如果使用delegate-ref则是要引用SpringBean;

implement-interface则是要引入的接口

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 网易严选Java开发面试:MySQL索引深度解析
    本文详细记录了网易严选Java开发岗位的面试经验,特别针对MySQL索引相关的技术问题进行了深入探讨。通过本文,读者可以了解面试官常问的索引问题及其背后的原理。 ... [详细]
  • 本文介绍了多个关于JavaScript的书籍资源、实用工具和编程实例,涵盖从入门到进阶的各个阶段,帮助读者全面提升JavaScript编程能力。 ... [详细]
  • 探索电路与系统的起源与发展
    本文回顾了电路与系统的发展历程,从电的早期发现到现代电子器件的应用。文章不仅涵盖了基础理论和关键发明,还探讨了这一学科对计算机、人工智能及物联网等领域的深远影响。 ... [详细]
  • 科研单位信息系统中的DevOps实践与优化
    本文探讨了某科研单位通过引入云原生平台实现DevOps开发和运维一体化,显著提升了项目交付效率和产品质量。详细介绍了如何在实际项目中应用DevOps理念,解决了传统开发模式下的诸多痛点。 ... [详细]
  • 本文详细介绍如何利用已搭建的LAMP(Linux、Apache、MySQL、PHP)环境,快速创建一个基于WordPress的内容管理系统(CMS)。WordPress是一款流行的开源博客平台,适用于个人或小型团队使用。 ... [详细]
  • 本文详细介绍了 RosPack 类的功能和用法,探讨了其在 ROS 系统中的重要作用。RosPack 类提供了类似于终端命令 rospack 的功能,能够方便地查询和管理 ROS 包的相关信息。 ... [详细]
  • 在成功安装和测试MySQL及Apache之后,接下来的步骤是安装PHP。为了确保安全性和配置的一致性,建议在安装PHP前先停止MySQL和Apache服务,并将MySQL集成到PHP中。 ... [详细]
  • 本文探讨了Java编程的核心要素,特别是其面向对象的特性,并详细介绍了Java虚拟机、类装载器体系结构、Java类文件和Java API等关键技术。这些技术使得Java成为一种功能强大且易于使用的编程语言。 ... [详细]
author-avatar
懿切瀡纟彖_639
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有