AspectJ通知

前置通知

@Before 前面已经实例过了,略

后置通知

后置通知方法实现切面功能:
1.公共方法
2.方法没有返回值
3.方法名称自定义
4.方法可以有参数,推荐是Object,参数名称自定义

@AfterReturning后置通知
属性:
1、value切入点表达式
2、returning自定义的变量,表示目标方法的返回值的
自定义变量名必须和通知方法的形参一样

特点:
1、在目标方法后执行
2、能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
3、可以修改这个返回值

    @AfterReturning(
            value = "execution(public void org.example.Hello.sayHello(String))",
            returning = "res"
    )
    public void after(Object res){
    
    
        //Object res:是目标方法执行后的返回值,根据返回值做你的切面的功能处理

        //功能代码
        System.out.println("切面功能,执行之后"+new Date());
    }

在这里插入图片描述

后置通知修改目标方法返回值

@AfterReturning
如果要用JoinPoint也可以,但必须写在第一个参数
此时给hello一个返回值

 public String sayHello(String name){
    
    
        System.out.println(name+":pasaki");
        return name;
    }

在切面方法中利用后置通知修改返回值

    @AfterReturning(
            value = "execution(public String org.example.Hello.sayHello(String))",
            returning = "res"
    )
    public void after(Object res){
    
    
        //Object res:是 目标方法执行后的返回值,根据返回值做你的切面的功能处理
        if(res!=null){
    
    
            res="yongen";
        }
        //功能代码
        System.out.println("切面功能,执行之后"+new Date());
    }

测试

//1、指定spring配置文件的名称
        String config="spring_total" + ".xml";
        //2、创建表示spring容器的对象,ApplicationContext
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config);
        //3、通过容器获取对象
        HelloInterface hello = (HelloInterface) context.getBean("hello");
        String result=hello.sayHello("yasuo");
        System.out.println(result);

在这里插入图片描述
然后我们发现他并没有变!!!!
因为这个执行相当于是执行
hello.sayHello(String name)
然后把name当作参数传递到我的 after(String name)

name是一个String类型
如果参数是一个对象的引用类呢?

假设有个Student对象

public class Student {
    
    
    private String name;
    private int age;

    public Student() {
    
    
    }

    public Student(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }
}

现在在Hello里创建一个学生把他作为返回对象

    public Student sayHello(String name){
    
    
        Student riven=new Student("riven",18);

        System.out.println(name+":pasaki");
        return riven;
    }

在切面类中修改返回对象

    @AfterReturning(
            value = "execution(public Student org.example.Hello.sayHello(String))",
            returning = "res"
    )
    public void myBefore(Object res){
    
    
        //Object res:是 目标方法执行后的返回值,根据返回值做你的切面的功能处理
        if(res!=null){
    
    
            ((Student) res).setName("liliya");
            ((Student) res).setAge(23);
        }
        //功能代码
        System.out.println("切面功能,执行之后"+new Date());
    }

测试

        //1、指定spring配置文件的名称
        String config="spring_total" + ".xml";
        //2、创建表示spring容器的对象,ApplicationContext
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config);
        //3、通过容器获取对象
        HelloInterface hello = (HelloInterface) context.getBean("hello");
        Student result=hello.sayHello("yasuo");
        System.out.println(result);

在这里插入图片描述
变成liliya了,嘿嘿!

综上:
我们的String没有改变是因为String类型是不可变的,变的是引用,改变了后不是同一个对象
但是!!!
把对象引用作为参数后,他们的引用指向同一个对象,修改后,那当然原对象被修改啦,也就能看到改变

环绕通知

环绕通知方法实现切面功能:
1.公共方法
2.方法必须有返回值,推荐使用Object
3.方法名称自定义
4.方法可以有参数,固定参数ProceedingJoinPoint

特点:
1、是功能最强的通知
2、在目标方法的前后都能增强功能
3、控制目标方法是否被调用执行
4、修改原来的目标方法的执行结果。影响最后的调用结果

环绕通知等用于Jdk的动态代理,invocationHandler接口
参数: ProceedingJoinPoint等同于Method
返回值: 目标方法的执行结果,可以修改

    @Around(value = "execution(public Student org.example.Hello.sayHello(String))")
    public Object around(ProceedingJoinPoint point) throws Throwable {
    
    
        Object result=null;
        System.out.println("环绕通知:在方法执行之前:"+new Date());
        //1、目标方法调用
        result=point.proceed();//method.invoke
        System.out.println("环绕通知:在方法执行之后:"+new Date());
        //修改
        ((Student)result).setName("liliya");
        return result;
    }

在这里插入图片描述
环绕通知强大之处在于可以决定切面方法在什么情况下需要执行,什么情况下不需要执行
例如用ProceedingJoinPoint获取到方法的参数,通过参数判断是否需要执行目标方法。

    @Around(value = "execution(public Student org.example.Hello.sayHello(String))")
    public Object around(ProceedingJoinPoint point) throws Throwable {
    
    
        String name="";
        //获取第一个参数值
        Object args[]=point.getArgs();
        if(args!=null && args.length>=1){
    
    
            Object arg=args[0];
            name=(String)arg;
        }
        System.out.println(name);
        Object result=null;
        System.out.println("环绕通知:在方法执行之前:"+new Date());
        //判断是否需要目标方法调用
        if(name.equals("yasuo")){
    
    
            result=point.proceed();//method.invoke
        }

        System.out.println("环绕通知:在方法执行之后:"+new Date());

        return result;
    }

这个时候只有参数是"yasuo"的时候才能调用目标方法。

环绕通知修改返回值

环绕通知强大在可以修改String

    public String sayHello(String name){
    
    
        System.out.println(name+":pasaki");
        return name;
    }

修改result

    @Around(value = "execution(public String org.example.Hello.sayHello(String))")
    public Object around(ProceedingJoinPoint point) throws Throwable {
    
    
        Object result=null;
        System.out.println("环绕通知:在方法执行之前:"+new Date());
        //1、目标方法调用
        result=point.proceed();//method.invoke
        result="hhhhhhhhhhhhhh";
        System.out.println("环绕通知:在方法执行之后:"+new Date());

        return result;
    }
    public void shouldAnswerWithTrue()
    {
    
    
        //1、指定spring配置文件的名称
        String config="spring_total" + ".xml";
        //2、创建表示spring容器的对象,ApplicationContext
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config);
        //3、通过容器获取对象
        HelloInterface hello = (HelloInterface) context.getBean("hello");
        String  result=hello.sayHello("yasuo");
        System.out.println(result);
    }

在这里插入图片描述
==这里调用的sayHello实际上被代理替换成了around方法,所以最后得到的是around里的result,区别于AfterReturning ==

异常通知

异常通知:发生异常时才执行,不发生异常不执行
相当于执行try{ ……}catch{……}

异常通知方法实现切面功能:
1.公共方法
2.没有返回值
3.方法名称自定义
4.方法可以没有参数,有就是JpinPoint

@AfterThrowing异常通知
属性:
1、value切入点表达式
2、throwing:自定义变量,表示目标方法抛出的异常对象
变量名必须和方法的参数名一样

特点:
1、在目标方法抛出异常时执行的
2、可以做异常的监控程序,监控目标方法执行时是不是有异常。
如果有异常,可以发送邮件,短信进行通知

在目标方法中抛出一个异常

    public String sayHello(String name){
    
    
        System.out.println(name+":pasaki"+10/0);
        return name;
    }

异常通知接收异常

    @AfterThrowing(value = "execution(public String org.example.Hello.sayHello(String))",throwing="ex")
    public void afterThrowing(Exception ex){
    
    
        System.out.println("异常通知:方法发生异常时执行"+ex.getMessage());

    }

在这里插入图片描述

最终通知

最终通知方法实现切面功能:
1.公共方法
2.没有返回值
3.方法名称自定义
4.方法可以没有参数,有就是JpinPoint

特点:
1、总会执行(无论是否有异常)
2、在目标方法之后执行的
相当于try{}catch{}finally{}

一般做资源的清除工作

    @After(value = "execution(public String org.example.Hello.sayHello(String))")
    public void after(){
    
    
        System.out.println("最终通知");

    }

复用切入点表达式

@Pointcut: 定义和管理切入点的,项目中有多个切入点表达式需要复用
特点:
当使用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名
其他通知中,value属性就可以使用这个方法名称,代替切入点表达式了

 //此时cut就是切入点表达式的别名
    @Pointcut("execution(public String org.example.Hello.sayHello(String))\"")
    public void cut(){
    
    }

    @After(value = "cut()")
    public void after(){
    
    
        System.out.println("最终通知");

    }

    @Before(value = "cut()")
    public void before(){
    
    
        System.out.println("前置通知");

    }

猜你喜欢

转载自blog.csdn.net/qq_36976201/article/details/109055486