AOP细节

(aop所需的jar包http://www.cnblogs.com/TYDBLOG/p/7450059.html)

1 切入点表达式

1.1 作用

通过表达式的方式定位一个或多个具体的连接点。

1.2 语法细节

1.2.1切入点表达式的语法格式


execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名]([参数列表]))

1.2.2举例说明


表达式


execution(* com.atguigu.spring.ArithmeticCalculator.*(..))


含义


ArithmeticCalculator接口中声明的所有方法。

第一个“*”代表任意修饰符及任意返回值。

第二个“*”代表任意方法。

“..”匹配任意数量、任意类型的参数。

若目标类、接口与该切面类在同一个包中可以省略包名。


表达式


execution(public * ArithmeticCalculator.*(..))


含义


ArithmeticCalculator接口的所有公有方法


表达式


execution(public double ArithmeticCalculator.*(..))


含义


ArithmeticCalculator接口中返回double类型数值的方法


表达式


execution(public double ArithmeticCalculator.*(double, ..))


含义


第一个参数为double类型的方法。

“..” 匹配任意数量、任意类型的参数。


表达式


execution(public double ArithmeticCalculator.*(double, double))


含义


参数类型为double,double类型的方法

1.2.3在AspectJ中,切入点表达式可以通过 “&&”、“||”、“!”等操作符结合起来。


表达式


execution (* *.add(int,..)) || execution(* *.sub(int,..))


含义


任意类中第一个参数为int类型的add方法或sub方法

2 通知

2.1 概述

  • 在具体的连接点上要执行的操作。
  • 一个切面可以包括一个或者多个通知。
  • 通知所使用的注解的值往往是切入点表达式。

2.2 前置通知

  • 前置通知:在方法执行之前执行的通知
  • 使用@Before注解

2.3 后置通知

  • 后置通知:后置通知是在连接点完成之后执行的,即连接点返回结果或者抛出异常的时候
  • 使用@After注解

2.4 返回通知

  • 返回通知:无论连接点是正常返回还是抛出异常,后置通知都会执行。如果只想在连接点返回的时候记录日志,应使用返回通知代替后置通知。
  • 使用@AfterReturning注解
  • 在返回通知中访问连接点的返回值
    • 在返回通知中,只要将returning属性添加到@AfterReturning注解中,就可以访问连接点的返回值。该属性的值即为用来传入返回值的参数名称
    • 必须在通知方法的签名中添加一个同名参数。在运行时Spring AOP会通过这个参数传递返回值
    • 原始的切点表达式需要出现在pointcut属性中

2.5 异常通知

  • 异常通知:只在连接点抛出异常时才执行异常通知
  • 将throwing属性添加到@AfterThrowing注解中,也可以访问连接点抛出的异常。Throwable是所有错误和异常类的顶级父类,所以在异常通知方法可以捕获到任何错误和异常。
  • 如果只对某种特殊的异常类型感兴趣,可以将参数声明为其他异常的参数类型。然后通知就只在抛出这个类型及其子类的异常时才被执行

2.6 环绕通知

  • 环绕通知是所有通知类型中功能最为强大的,能够全面地控制连接点,甚至可以控制是否执行连接点。
  • 对于环绕通知来说,连接点的参数类型必须是ProceedingJoinPoint。它是 JoinPoint的子接口,允许控制何时执行,是否执行连接点。
  • 在环绕通知中需要明确调用ProceedingJoinPoint的proceed()方法来执行被代理的方法。如果忘记这样做就会导致通知被执行了,但目标方法没有被执行。
  • 注意:环绕通知的方法需要返回目标方法执行之后的结果,即调用 joinPoint.proceed();的返回值,否则会出现空指针异常。

2.7 代码示例

      写一个类实现加减乘除,并生成 前置通知、后置通知、返回通知、异常通知 或环绕通知

  2.7.1 配置文件:

      创建文件时勾选aop bean context三个选项

      

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

    <!-- 配置扫描的包 -->
    <context:component-scan base-package="com.tyd.spring.aop"></context:component-scan>
    <!-- 使用aop要创建此标签 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

  2.7.2 创建math接口以及方法实现类:

     

package com.tyd.spring.aop;

public interface Math {
    public void add(int a,int b);
    public void sub(int a,int b);
    public void mul(int a,int b);
    public void div(int a,int b);
    public void add(int a, int b,int c);
}
package com.tyd.spring.aop;

import org.springframework.stereotype.Component;

@Component
public class MyEpressionMath implements Math{
    @Override
    public void add(int a, int b) {
        int num=a+b;
        System.out.println(a+"+"+b+"="+num);

    }

    @Override
    public void sub(int a, int b) {
        System.out.println(a+"-"+b+"="+(a-b));

    }

    @Override
    public void mul(int a, int b) {
        System.out.println(a+"*"+b+"="+(a*b));

    }

    @Override
    public void div(int a, int b) {
        System.out.println(a+"/"+b+"="+(a/b));

    }

    @Override
    public void add(int a, int b, int c) {
        System.out.println(a+"+"+b+c+"="+(a+b+c));

    }

}

  2.7.3使用前置通知、后置通知、返回通知、异常通知实现日志

package com.tyd.spring.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect  //表明是切面类
public class CaculatorAspect  {
    //value值为方法的全类名以及方法名:public void(访问权限及返回值类型)com.tyd.spring.aop.MyEpressionMath(全类名).*代表此类中所有方法(..)代表所有参数类型
    @Before(value="execution(public void com.tyd.spring.aop.MyEpressionMath.*(..))")
    public void showBegin(){
        System.out.println("【日志】【方法开始】");
    }
    @AfterReturning(value="execution(public void  com.tyd.spring.aop.MyEpressionMath.*(..))",returning="result")
    public void showAfter(){
        System.out.println("【日志】【方法正常结束】");
    }
    @AfterThrowing(value="execution(public void  com.tyd.spring.aop.MyEpressionMath.*(..))")
    public void showexception(){
        System.out.println("【日志】【方法出异常】");
    }
    @After(value="execution(public void com.tyd.spring.aop.MyEpressionMath.*(..))")
    public void showAfterRe(){
        System.out.println("【日志】【方法执行结束】");
    }
}

2.7.4环绕通知实现:

package com.tyd.spring.aop;

import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect  //表明是切面类
public class CaculatorAspect  {

    @Around(value="execution(public void com.tyd.spring.aop.MyEpressionMath.*(..))")
    public Object around(ProceedingJoinPoint joinPoint){
        //获取目标方法参数
        Object[] args = joinPoint.getArgs();
        System.out.println("args:"+args);
        //获取签名
        Signature signature = joinPoint.getSignature();
        System.out.println("signature:"+signature);
        //获取方法名
        String methodName = signature.getName();
        System.out.println("methodName:"+methodName);
        List<Object> list = Arrays.asList(args);
        Object result = null;
        try {
            try{
                //目标方法之前要执行的操作
                System.out.println("[环绕日志]【前置通知】"+methodName+"开始了,参数为:"+list);
                //调用目标方法
                result = joinPoint.proceed(args);

                //目标方法正常执行之后的操作

            }finally{
                //方法最终结束时执行的操作!
                System.out.println("[环绕日志]【后置通知】"+methodName+"结束了!");
            }
            //目标方法正常执行之后的操作
            System.out.println("[环绕日志]【返回通知】"+methodName+"返回了,返回值为:"+result);
        } catch (Throwable e) {
            //目标方法抛出异常信息之后的操作
            System.out.println("[环绕日志]【异常通知】"+methodName+"出异常了,异常对象为:"+e);
            throw new RuntimeException(e.getMessage());
        }finally{

        }
        return result;
    }

2.7.5测试代码

package com.tyd.spring.aop;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class text {

    @Test
    public void test() {

        ApplicationContext ioc=new ClassPathXmlApplicationContext("bean.xml");
        Math m=(Math) ioc.getBean("myEpressionMath");
        m.add(10, 10);
        System.out.println();
        m.div(10, 2);
        System.out.println();
        m.mul(20, 10);
        m.add(10, 10,10);
        //测试异常
        m.div(10, 0);
    }
}
时间: 2024-08-07 08:39:28

AOP细节的相关文章

Spring的AOP细节理解

什么是AOP?AOP:是面向切面编程,是对面向对象编程(oop)的一种补充,为什么需要AOP?例如在我们做一个计算器,要求我们每次运行对应的功能(也就是进行运算时)都要输出日志,以便于知道程序是怎么运行的如果在OOP中,那么肯定需要抽象出一个log(日志)类吧,然后再每个方法前调用这个new一个log(日志)类,然后调用的方法,并传入不同的参数,第一个问题,就是代码混乱吖,就是不是核心处理的代码也出现在核心的类里面,以后维护的时候,我还要去区分这个代码是什么来的,第二个问题:就是代码太分散,就是

AOP实现日志打印 基于xml配置的AOP实现 切入点表达式

前置通知,后置通知,异常通知,返回通知 使用注解需要加入 在xml中加入  <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 环绕通知(跟以上结果一样)  需要有返回值return rs: 基于xml配置的AOP实现(上面的注解全去掉,配置以下) ①切入点表达式的语法格式[参见第5章AOP细节] execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名]([参数列表])) 参见第5章AOP细节:演示验证 1.任

AOP面向切面编程笔记

1.AOP概念:Aspect Oriented Programming 面向切面编程 2.作用:本质上来说是一种简化代码的方式 继承机制 封装方法 动态代理 -- 3.情景举例 ①数学计算器接口[MathCalculator] int add(int i,int j); int sub(int i,int j); int mul(int i, int j); int div(int i,int j); ②提供简单实现[EasyImpl] ③在简单实现的基础上让每一个计算方法都能够打印日志[Log

Spring(三)--AOP【面向切面编程】、通知类型及使用、切入点表达式

1.概念:Aspect Oriented Programming 面向切面编程 在方法的前后添加方法 2.作用:本质上来说是一种简化代码的方式 继承机制 封装方法 动态代理 -- 3.情景举例 ①数学计算器接口[MathCalculator] int add(int i,int j); int sub(int i,int j); int mul(int i, int j); int div(int i,int j); 因为后面的通知方法需要返回值,所以在这里类型声明为 int 类型 public

探究Dubbo的拓展机制: 下

承接上篇, 本篇博文的主题就是认认真真捋一捋, 看一下 Dubbo是如何实现他的IOC / AOP / 以及Dubbo SPI这个拓展点的 总览: 本篇的话总体上分成两部分进行展开 第一点就是 Dubbo在启动过程中加载原生的配置文件中提供的被@SPI标记的实现类: 第二就是Dubbo加载程序员后续添加进去的被@SPI标注的接口和实现类, 进而探究 Dubbo的IOC / AOP / 以及Dubbo SPI这个拓展点机制 环境的初始化 入口程序 如下代码是追踪的起点: 我也是看了好多遍才勉强将这

使用Spring的注解方式实现AOP的细节

前面我们已经入门使用Spring的注解方式实现AOP了,现在我们再来学习使用Spring的注解方式实现AOP的一些细节.本文是建立在使用Spring的注解方式实现AOP入门的案例的基础之上的. 本文是来讲解使用Spring的注解方式实现AOP的一些细节,其实说白了就是学习如何使用各种通知而已,例如前置通知.后置通知.异常通知.最终通知.环绕通知等,之前我们已经学习了前置通知,现在就来学习剩余的通知. 我们先来看后置通知,此时须将MyInterceptor类的代码修改为: /** * 切面 * @

Spring3:AOP

AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入封装.继承.多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合.不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能.日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性.异常处理和透明的持续性也都是如此,这种散布在各

Spring AOP 实现原理(二) 使用 Spring AOP

与 AspectJ 相同的是,Spring AOP 同样需要对目标类进行增强,也就是生成新的 AOP 代理类:与 AspectJ 不同的是,Spring AOP 无需使用任何特殊 命令对 Java 源代码进行编译,它采用运行时动态地.在内存中临时生成"代理类"的方式来生成 AOP 代理. Spring 允许使用 AspectJ Annotation 用于定义方面(Aspect).切入点(Pointcut)和增强处理(Advice),Spring 框架则可识别并根据这些 Annotati

Spring框架——AOP(面向切面编程)详解

 1 AOP概述 ●AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统 OOP(Object-Oriented Programming,面向对象编程)的补充. ●AOP编程操作的主要对象是切面(aspect),而切面模块化横切关注点. ●在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能应用在哪里,以什么方式应用,并且不必修改受影响的类.这样一来横切关注点就被模块化到特殊的类里--这样的类我们通常称之为"切面".