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

SpringAOPAspectJ使用及配置过程解析

这篇文章主要介绍了SpringAOPAspectJ使用及配置过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

这篇文章主要介绍了Spring AOP AspectJ使用及配置过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

AspectJ是一个基于Java语言的AOP框架,Spring2.0以后新增了对AspectJ切点表达式支持。因为Spring1.0的时候Aspectj还未出现;

AspectJ1.5中新增了对注解的支持,允许直接在Bean类中定义切面。新版本的Spring框架建
议我们都使用AspectJ方式来开发AOP,并提供了非常灵活且强大的切点表达式 ;

当然无论使用Spring自己的AOP还是AspectJ相关的概念都是相同的;

注解配置

依赖导入:


  org.springframework
  spring-aspects
  5.2.2.RELEASE

通知类型

  • @AspectJ提供的通知类型:
  • @Before 前置通知 在原始方法执行前执行
  • @AfterReturning 后置通知 在原始方法执行前执行
  • @Around 环绕通知 彻底拦截原始方法的执行,执行前后都可以增加逻辑,也可以不执行原始方法
  • @AfterThrowing抛出通知,执行原始方法出现异常时执行
  • @After 最终final通知,不管是否异常,原始方法调用后都会执行
  • @DeclareParents 引介通知,相当于IntroductionInterceptor (了解即可)

定义切点

通过execution函数来定义切点

语法:execution(访问修饰符 返回类型 方法名 参数 异常)

表达式示例:

  • 匹配所有类public方法:execution(public * *(..))第一个*表示返回值 ..表示任意个任意类型参数
  • 匹配指定包下所有方法: execution(* cn.xxx.dao.*(..)) 第一个想*表示忽略权限和返回值类型
  • 匹配指定包下所有方法:execution(* cn.xxx.dao..*(..))包含子包
  • 匹配指定类所有方法: execution(* cn.xxx.service.UserService.*(..))
  • 匹配实现特定接口所有类方法 : execution(* cn.xxx.dao.GenericDAO+.*(..))
  • 匹配所有save开头的方法: execution(* save*(..))

前置通知

pom依赖:

  
    
      org.springframework
      spring-context
      5.2.2.RELEASE
    
    
      org.springframework
      spring-aspects
      5.2.2.RELEASE
    
    
    
      org.springframework
      spring-test
      5.2.2.RELEASE
      test
    
    
    
      org.springframework
      spring-test
      5.2.2.RELEASE
      test
    
    
    
      junit
      junit
      4.13
      test
    
  

xml需要添加aop名称空间及xsd:

<&#63;xml version="1.0" encoding="UTF-8"&#63;>


  

  

  

test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Test1 {
  @Autowired
  PersonDao personDao;

  @Test
  public void test(){
    personDao.delete();
    personDao.update();
  }
}

切面类:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class MyAspect {
   //表示PersonDao下所有方法都作为切点
  @Before(value = "execution(* com.yh.demo1.PersonDao.*(..))")
  public void beforeAdvice(){
    System.out.println("before code run.....");
  }
}

当我们需要获取切点信息(被增强的代码)时,可以在通知添加参数,想下面这样

@Aspect
public class MyAspect {
  @Before(value = "execution(* com.yh.demo1.PersonDao.*(..))")
  public void beforeAdvice2(JoinPoint point){
    System.out.println("before code run2....." + point);
  }
}

后置通知:

//当需要获取原始方法的返回值时可以在注解中添加returning参数来指定参数名 Aspectj会自动将返回值放到参数中
@AfterReturning(value = "execution(* com.yh.demo1.PersonDao.delete(..))",returning = "result")
public void afterAdvice(Object result){
  System.out.println("删除方法执行后 .....  返回值为:"+ result);
}

后置通知可以获取目标方法的返回值

环绕通知:

@Around(value = "execution(* com.yh.demo1.PersonDao.insert(..))")
public void aroundAdvice(ProceedingJoinPoint point) throws Throwable {
  //code............
  System.out.println("环绕前置..");

  //执行原始方法 __当需要获取返回值时可以声明变量接收
  Object result = point.proceed();
  System.out.println("原始方法返回值: "+result);
  //code............
  System.out.println("环绕后置..");
}

环绕通知与其他通知最大的区别在于环绕通知可以控制是否调用原始方法

注意:参数类型必须为ProceedingJoinPoint,否则 无法执行原始方法,

异常通知

@AfterThrowing(value = "execution(* com.yh.demo1.PersonDao.save(..))",throwing = "e")
public void exceptionHandler(JoinPoint point,Exception e){
  System.out.println(point + " 方法出现"+e.getMessage()+"异常");
}

当方法中出现时才会执行该通知,若需要获取异常信息,可在注解中添加throwing指定参数名称

我们可以使用环绕+异常通知来处理数据库事务,在环绕中开启事务以及提交事务,异常通知中回滚事务,当然Spring已经对事务进行了封装不需要自己写

最终通知

@After(value = "execution(* *delete(..))")
public void afterRun(){
  System.out.println("最终");
}

最终通知叫做after 即调用原始方法之后执行无论原始方法中是否出现异常

而后置叫做afterReturning表示在成功返回后才会执行执行

带有逻辑符的表达式:
在表达式中可以使用户逻辑操运算符,与&& 或|| 非!

示例:

/*
execution(* cn.xxx.service.UserDao.insert(..))||execution(* cn.xxx.service.UserDao.delete(..))

execution(* cn.xxx.service.UserDao.*nsert(..))&&execution(* cn.xxx.service.UserDao.inser*(..))

!execution(* cn.xxx.service.UserDao.insert(..))
*/
2|4切点命名

切点命名

假设有多个通知应用在同一个切点上时,我们需要重复编写execution表达式,且后续要修改切点时则多个通知都需要修改,维护起来非常麻烦,我们可以通过给切点指定名称从而完成对切点的重复使用和统一操作,以提高开发维护效率;

//定义命名切点 方法名称即切点名称
@Pointcut(value = "execution(* com.yh.demo1.PersonDao.save(..))")
private void savePointcut(){}

@Pointcut(value = "execution(* com.yh.demo1.PersonDao.delete(..))")
private void deletePointcut(){}

多个通知应用到同一个切点:

//使用命名切点
@Before(value = "savePointcut()")
public void beforeAdvice(){
  System.out.println("before code run.....");
}
//使用命名切点
@Around(value = "savePointcut()")
public void beforeAdvice2(ProceedingJoinPoint point) throws Throwable {
  System.out.println("环绕前");
  point.proceed();
  System.out.println("环绕后");

一个通知应用到多个切点

//同一个通知对应多个切点
@After(value = "savePointcut()||deletePointcut()")
public void afterAdvice(){
  System.out.println("after code run.....");
}

XML配置

XML配置所需的jar 以及各个对象之间的依赖关以及表达式的写法都是一样的,仅仅是换种方式来写而已;

xml:

    
  
    
  

    
  
        
    
        
    
      
      
      
      
      
    
   
    
    
  
 
 

通知类:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.JoinPoint;

public class XMLAdvice {
  public void before(JoinPoint pointcut){ System.out.println("前置通知 切点:"+pointcut); }

  public void afterReturning(JoinPoint point,Object result){
    System.out.println("后置通知 切点:"+point);
  }

  public void after(JoinPoint point){ System.out.println("最终通知 切点:"+point); }

  public void exception(JoinPoint point,Throwable e){
    System.out.println("异常通知: " + e+"切点:"+point);
  }

  public void around(ProceedingJoinPoint point) throws Throwable {
    System.out.println("环绕前");
    point.proceed();
    System.out.println("环绕后");
  }
}

你会发现 ,无论是XML还是注解都不需要手动指定代理,以及目标对象,Aspectj会从切点中获取目标对象信息并自动创建代理;

AspectJ是目前更流行的方式,具体采用XML还是注解需要根据项目具体情况,小组协作开发推荐xml;

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


推荐阅读
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 本文详细介绍如何利用已搭建的LAMP(Linux、Apache、MySQL、PHP)环境,快速创建一个基于WordPress的内容管理系统(CMS)。WordPress是一款流行的开源博客平台,适用于个人或小型团队使用。 ... [详细]
  • 本文介绍如何将自定义项目设置为Tomcat的默认访问项目,使得通过IP地址访问时直接展示该自定义项目。提供了三种配置方法:修改项目路径、调整配置文件以及使用WAR包部署。 ... [详细]
  • 本文详细介绍了Java中的访问器(getter)和修改器(setter),探讨了它们在保护数据完整性、增强代码可维护性方面的重要作用。通过具体示例,展示了如何正确使用这些方法来控制类属性的访问和更新。 ... [详细]
  • 本文详细介绍了如何使用ActionScript 3.0 (AS3) 连接并操作MySQL数据库。通过具体的代码示例和步骤说明,帮助开发者理解并实现这一过程。 ... [详细]
  • 本文详细探讨了HTTP 500内部服务器错误的成因、解决方案及其在Web开发中的影响。通过对具体案例的分析,帮助读者理解并解决此类问题。 ... [详细]
  • 分享一个简化版的Silverlight链接图项目:Link Map Simplified
    本文介绍了一个使用Silverlight开发的可视化工具,主要用于展示和操作复杂的实体关系图(Graph)。该工具在犯罪调查系统中得到了广泛应用,帮助用户直观地获取和理解相关信息。 ... [详细]
  • 本文介绍了Android开发中Intent的基本概念及其在不同Activity之间的数据传递方式,详细展示了如何通过Intent实现Activity间的跳转和数据传输。 ... [详细]
  • 优化 Android 按钮状态下的背景和文本颜色变化
    本文介绍如何通过 Android 的 Selector 实现按钮在不同状态下(如按压)的背景和文本颜色动态变化。我们将详细讲解实现步骤,并提供完整的代码示例。 ... [详细]
  • 本文详细介绍超文本标记语言(HTML)的基本概念与语法结构。HTML是构建网页的核心语言,通过标记标签描述页面内容,帮助开发者创建结构化、语义化的Web页面。 ... [详细]
  • 本文介绍了ArcXML配置文件的分类及其在不同服务中的应用,详细解释了地图配置文件的结构和功能,包括其在Image Service、Feature Service以及ArcMap Server中的使用方法。 ... [详细]
  • 本文详细介绍了 RosPack 类的功能和用法,探讨了其在 ROS 系统中的重要作用。RosPack 类提供了类似于终端命令 rospack 的功能,能够方便地查询和管理 ROS 包的相关信息。 ... [详细]
  • 本文探讨了如何使用自增和自减运算符遍历二维数组中的元素。通过实例详细解释了指针与二维数组结合使用的正确方法,并解答了常见的错误用法。 ... [详细]
  • Struts与Spring框架的集成指南
    本文详细介绍了如何将Struts和Spring两个流行的Java Web开发框架进行整合,涵盖从环境配置到代码实现的具体步骤。 ... [详细]
  • 本文介绍了如何通过设置背景形状来轻松地为 Android 的 TextView 添加圆形边框。我们将详细讲解 XML 代码的配置,包括圆角、描边和填充等属性。 ... [详细]
author-avatar
Aime--Gemini
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有