spring AOP注解实现

一、什么是AOP

引用一下维基百科的定义

面向切面的程序设计(Aspect-oriented programming,AOP,又译作面向方面的程序设计剖面导向程序设计)是计算机科学中的一种程序设计思想,旨在将横切关注点与业务主体进行进一步分离,以提高程序代码的模块化程度。通过在现有代码基础上增加额外的通知(Advice)机制,能够对被声明为“切点(Pointcut)”的代码块进行统一管理与装饰,如“对所有方法名以‘set*’开头的方法添加后台日志”。该思想使得开发人员能够将与代码核心业务逻辑关系不那么密切的功能(如日志功能)添加至程序中,同时又不降低业务代码的可读性。面向切面的程序设计思想也是面向切面软件开发的基础。

面向切面的程序设计将代码逻辑切分为不同的模块(即关注点(Concern),一段特定的逻辑功能)。几乎所有的编程思想都涉及代码功能的分类,将各个关注点封装成独立的抽象模块(如函数、过程、模块、类以及方法等),后者又可供进一步实现、封装和重写。部分关注点“横切”程序代码中的数个模块,即在多个模块中都有出现,它们即被称作“横切关注点(Cross-cutting concerns, Horizontal concerns)”。

日志功能即是横切关注点的一个典型案例,因为日志功能往往横跨系统中的每个业务模块,即“横切”所有有日志需求的类及方法体。而对于一个信用卡应用程序来说,存款、取款、帐单管理是它的核心关注点,日志和持久化将成为横切整个对象结构的横切关注点。

二、AOP相关术语

  • Joinpoint(连接点): 所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的 连接点。
  • Pointcut(切入点): 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。
  • Advice(通知/增强): 所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
  • Introduction(引介): 引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方 法或 Field。
  • Target(目标对象): 代理的目标对象。
  • Weaving(织入): 是指把增强应用到目标对象来创建新的代理对象的过程。 spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
  • Proxy(代理): 一个类被 AOP 织入增强后,就产生一个结果代理类。-
  • Aspect(切面): 是切入点和通知(引介)的结合。

三、使用注解实现spring AOP

首先是我们的业务逻辑类

public class MathCalculator {

    public int div(int i,int j){
        System.out.println("MathCalculator...div...");
        return i/j;
    }

}

接着是我们的切面类

/**
 * 切面类
 * @author lfy
 *
 * @Aspect: 告诉Spring当前类是一个切面类
 *
 */
@Aspect
public class LogAspects {

    //抽取公共的切入点表达式
    //1、本类引用
    //2、其他的切面引用
    @Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
    public void pointCut(){};

    //@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
    }

    @After("com.atguigu.aop.LogAspects.pointCut()")
    public void logEnd(JoinPoint joinPoint){
        System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
    }

    //JoinPoint一定要出现在参数表的第一位
    @AfterReturning(value="pointCut()",returning="result")
    public void logReturn(JoinPoint joinPoint,Object result){
        System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
    }

    @AfterThrowing(value="pointCut()",throwing="exception")
    public void logException(JoinPoint joinPoint,Exception exception){
        System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
    }

        /*@Around(value="pointCut()")
    public void myAround(ProceedingJoinPoint joinPoint) {
        // 方法之前,前置通知
        System.out.println("《方法之前:前置通知");
        try {
            // 方法执行时
            joinPoint.proceed(); // 执行方法
            // 方法执行之后:后置通知
            System.out.println("《方法执行之后:后置通知");
        } catch (Throwable e) {
            // 发生异常时
            System.out.println("《发生异常时:异常通知");
        } finally {
            // 最终通知
            System.out.println("《最终通知");
        }
    }*/

}

接着是我们的配置类:

/**
 * AOP:【动态代理】
 *      指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;
 *
 * 1、导入aop模块;Spring AOP:(spring-aspects)
 * 2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
 * 3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行;
 *      通知方法:
 *          前置通知(@Before):logStart:在目标方法(div)运行之前运行
 *          后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
 *          返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
 *          异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
 *          环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
 * 4、给切面类的目标方法标注何时何地运行(通知注解);
 * 5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
 * 6、必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)
 * [7]、给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
 *      在Spring中很多的 @EnableXXX;
 *
 * 三步:
 *  1)、将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)
 *  2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
 *  3)、开启基于注解的aop模式;@EnableAspectJAutoProxy
 */
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {

    //业务逻辑类加入容器中
    @Bean
    public MathCalculator calculator(){
        return new MathCalculator();
    }

    //切面类加入到容器中
    @Bean
    public LogAspects logAspects(){
        return new LogAspects();
    }
}

最后是我们的测试类:

public class IOCTest_AOP {

    @Test
    public void test01(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);

        //1、不要自己创建对象
//      MathCalculator mathCalculator = new MathCalculator();
//      mathCalculator.div(1, 1);
        MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);

        mathCalculator.div(1, 1);

        applicationContext.close();
    }

}

控制台打印结果:

div运行。。。@Before:参数列表是:{[1, 1]}
MathCalculator...div...
div结束。。。@After
div正常返回。。。@AfterReturning:运行结果:{1}

注释中已经解释的很详细了,不再赘述。


四、环绕通知

环绕通知的功能比较强大,它可以实现其他四种通知

具体代码也很同意理解,放开LogAspects中的myAround方法,为方便观察,可以注释掉其他四种通知.

我们写个测试方法测试一下。

这次我们除以0试试

mathCalculator.div(1, 0);

打印:

《方法之前:前置通知
MathCalculator...div...
《发生异常时:异常通知
《最终通知

注意:环绕通知需要执行目标方法,参数使用ProceedingJoinPoint joinPoint,其父类没有这个joinPoint.proceed();/方法。

原文地址:https://www.cnblogs.com/heliusKing/p/11421135.html

时间: 2024-10-01 03:06:14

spring AOP注解实现的相关文章

Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解

原创整理不易,转载请注明出处:Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解 代码下载地址:http://www.zuidaima.com/share/1772661373422592.htm 本文介绍了使用Spring注解注入属性的方法.使用注解以前,注入属性通过类以及配置文件来实现.现在,注入属性可以通过引入@Autowired注解,或者@Resource,@Qualifi

Spring AOP 注解配置实例

Spring AOP注解例子 一:导入相关jar包. 首先导入Spring的相关包(这里就不多说了,我这里是3.2.4版本的) 然后导入AOP注解的相关包(不是spring的包)aspectjrt-1.6.7.jar和aspectjweaver-1.6.8.jar和aopalliance.jar (注意这里最好是1.6.7以上的版本,不然容易出错,折腾了我好久,最后才发现是包的版本问题. 所以这里一定要注意,spring 2.0以后的最好是用1.6.7的版本) 二: 建一个class类作为切入面

Spring AOP注解方式实现

简介 上文已经提到了Spring AOP的概念以及简单的静态代理.动态代理简单示例,链接地址:https://www.cnblogs.com/chenzhaoren/p/9959596.html 本文将介绍Spring AOP的常用注解以及注解形式实现动态代理的简单示例. 常用注解 @aspect:定义切面 @pointcut:定义切点 @Before:前置通知,在方法执行之前执行 @After:后置通知,在方法执行之后执行 @AfterRunning:返回通知,在方法返回结果之后执行 @Aft

转:Spring AOP 注解方式实现的一些“坑”

使用过Spring AOP的注解方式实现,也入过不少坑,现在做一下记录,希望有同样需求的朋友可以少走弯路 使用之前还是先过一下官方文档吧,至少可以少走弯路,不用担心英文读不懂,其实只看代码例子就能理解很多问题! 1. SpringBoot如何获得Aspect支持? 看这里:Spring Boot 开启AOP的方法 2. 我按照上面的方法开启了AOP支持,为什么始终是不走切入点方法呢? 首先仔细检查一下,Aspect类是不是少了@Component注解(这一点很重要!),只有一个@Aspect注解

spring Aop 注解

个人理解: spring Aop 是什么:面向切面编程,类似于自定义拦截操作,支持拦截之前操作@Before,拦截之后操作@After,拦截环绕操作@Around. 什么情况下使用spring Aop:举例如下 当需要统计某些方法 or 指定xx开头的方法名 or 指定xx结尾的方法名 or 某些类下的方法 or 某些包下的方法 or 所有的方法的耗时统计或添加日志信息时,使用spring Aop 切面编程可以不用修改任何需要统计或添加日志的方法,只需很少一部分代码实现需要做的操作. 某交易系统

Spring aop 注解参数说明

在spring AOP中,需要使用AspectJ的切点表达式语言来定义切点. 关于Spring AOP的AspectJ切点,最重要的一点是Spring仅支持AspectJ切点指示器(pointcut designator)的一个子集. AspectJ指示器 描述 arg() 限制连接点匹配参数为指定类型的执行方法 @arg() 限制连接点匹配参数由指定注解标注的执行方法 execution() 用于匹配是连接点的执行方法 this() 限制连接点匹配AOP代理的Bean引用为指定类型的类 tar

Spring AOP 注解形式

AspectOriented Programing,面向切面编程.   AOP主要用于日志记录,性能统计,安全控制(权限控制),事务处理,异常处理等.将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码.  Spring AOP织入增强(Advice)的方式有两种 如果连接点实现了接口采用jdk自带的动态代理的形式实现织入,如果连接点没有实现接口则采用动态

Spring AOP注解形式简单实现

实现步骤: 1:导入类扫描的注解解析器 命名空间:xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-2.5.xsd" xml配置文件如下配置

日志异常处理-spring aop注解

spring aop 可以在不破坏我们程序代码的前提下很好的对程序异常进行打印,网上也有很多这样的例子,我这里写的比较简单,只是针对程序出异常时进行见到的日志打印,代码比较简单. 异常日志处理类 package com.apt.study.exception; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation