服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|编程技术|正则表达式|C/C++|

服务器之家 - 编程语言 - JAVA教程 - 详解SpringBoot之集成Spring AOP

详解SpringBoot之集成Spring AOP

2020-11-26 14:33木叶之荣 JAVA教程

本篇文章主要介绍了详解SpringBoot之集成Spring AOP,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

在开始之前,我们先把需要的jar包添加到工程里。新增maven依赖如下:

?
1
2
3
4
<dependency>
  <groupid>org.springframework.boot</groupid>
  <artifactid>spring-boot-starter-aop</artifactid>
</dependency>

 接下来,我们进入正题。这里的涉及的通知类型有:前置通知、后置最终通知、后置返回通知、后置异常通知、环绕通知,下面我们就具体的来看一下怎么在springboot中添加这些通知。

首先我们先创建一个aspect切面类:

?
1
2
3
4
5
@component
@aspect
public class webcontrolleraop {
 
}

指定切点:

?
1
2
3
4
5
//匹配com.zkn.learnspringboot.web.controller包及其子包下的所有类的所有方法
@pointcut("execution(* com.zkn.learnspringboot.web.controller..*.*(..))")
public void executeservice(){
 
}

接着我们再创建一个controller请求处理类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.zkn.learnspringboot.web.controller;
 
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;
 
/**
 * created by zkn on 2016/11/19.
 */
@restcontroller
@requestmapping("/aop")
public class aoptestcontroller {
 
}

前置通知

配置前置通知:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
 * 前置通知,方法调用前被调用
 * @param joinpoint
 */
@before("executeservice()")
public void dobeforeadvice(joinpoint joinpoint){
  system.out.println("我是前置通知!!!");
  //获取目标方法的参数信息
  object[] obj = joinpoint.getargs();
  //aop代理类的信息
  joinpoint.getthis();
  //代理的目标对象
  joinpoint.gettarget();
  //用的最多 通知的签名
  signature signature = joinpoint.getsignature();
  //代理的是哪一个方法
  system.out.println(signature.getname());
  //aop代理类的名字
  system.out.println(signature.getdeclaringtypename());
  //aop代理类的类(class)信息
  signature.getdeclaringtype();
  //获取requestattributes
  requestattributes requestattributes = requestcontextholder.getrequestattributes();
  //从获取requestattributes中获取httpservletrequest的信息
  httpservletrequest request = (httpservletrequest) requestattributes.resolvereference(requestattributes.reference_request);
  //如果要获取session信息的话,可以这样写:
  //httpsession session = (httpsession) requestattributes.resolvereference(requestattributes.reference_session);
  enumeration<string> enumeration = request.getparameternames();
  map<string,string> parametermap = maps.newhashmap();
  while (enumeration.hasmoreelements()){
    string parameter = enumeration.nextelement();
    parametermap.put(parameter,request.getparameter(parameter));
  }
  string str = json.tojsonstring(parametermap);
  if(obj.length > 0) {
    system.out.println("请求的参数信息为:"+str);
  }
}

注意:这里用到了joinpoint和requestcontextholder。通过joinpoint可以获得通知的签名信息,如目标方法名、目标方法参数信息等。通过requestcontextholder来获取请求信息,session信息。

接下来我们在controller类里添加一个请求处理方法来测试一下前置通知:

?
1
2
3
4
5
@requestmapping("/testbeforeservice.do")
public string testbeforeservice(string key,string value){
 
  return "key="+key+" value="+value;
}

前置通知拦截结果如下所示:

详解SpringBoot之集成Spring AOP

后置返回通知

配置后置返回通知的代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * 后置返回通知
 * 这里需要注意的是:
 *   如果参数中的第一个参数为joinpoint,则第二个参数为返回值的信息
 *   如果参数中的第一个参数不为joinpoint,则第一个参数为returning中对应的参数
 * returning 限定了只有目标方法返回值与通知方法相应参数类型时才能执行后置返回通知,否则不执行,对于returning对应的通知方法参数为object类型将匹配任何目标返回值
 * @param joinpoint
 * @param keys
 */
@afterreturning(value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))",returning = "keys")
public void doafterreturningadvice1(joinpoint joinpoint,object keys){
 
  system.out.println("第一个后置返回通知的返回值:"+keys);
}
 
@afterreturning(value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))",returning = "keys",argnames = "keys")
public void doafterreturningadvice2(string keys){
 
  system.out.println("第二个后置返回通知的返回值:"+keys);
}

controller里添加响应的请求处理信息来测试后置返回通知:

?
1
2
3
4
5
6
7
8
9
10
@requestmapping("/testafterreturning.do")
public string testafterreturning(string key){
 
  return "key=: "+key;
}
@requestmapping("/testafterreturning01.do")
public integer testafterreturning01(integer key){
 
  return key;
}

当发送请求为:http://localhost:8001/aop/testafterreturning.do?key=testsss&value=855sss时,处理结果如图所示:

详解SpringBoot之集成Spring AOP

当发送请求为:http://localhost:8001/aop/testafterreturning01.do?key=55553&value=855sss时,处理结果如图所示:

详解SpringBoot之集成Spring AOP

后置异常通知

后置异常通知的配置方式如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * 后置异常通知
 * 定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;
 * throwing 限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行,
 *   对于throwing对应的通知方法参数为throwable类型将匹配任何异常。
 * @param joinpoint
 * @param exception
 */
@afterthrowing(value = "executeservice()",throwing = "exception")
public void doafterthrowingadvice(joinpoint joinpoint,throwable exception){
  //目标方法名:
  system.out.println(joinpoint.getsignature().getname());
  if(exception instanceof nullpointerexception){
    system.out.println("发生了空指针异常!!!!!");
  }
}

controller里配置响应的请求处理类:

?
1
2
3
4
5
@requestmapping("/testafterthrowing.do")
public string testafterthrowing(string key){
 
  throw new nullpointerexception();
}

后置异常通知方法的处理结果如下所示:

详解SpringBoot之集成Spring AOP

后置最终通知

后置最终通知的配置方式如下:

?
1
2
3
4
5
6
7
8
9
/**
 * 后置最终通知(目标方法只要执行完了就会执行后置通知方法)
 * @param joinpoint
 */
@after("executeservice()")
public void doafteradvice(joinpoint joinpoint){
 
  system.out.println("后置通知执行了!!!!");
}

controller类配置相应的请求处理类:

?
1
2
3
4
5
6
7
8
9
10
@requestmapping("/testafter.do")
public string testafter(string key){
 
  throw new nullpointerexception();
}
@requestmapping("/testafter02.do")
public string testafter02(string key){
 
  return key;
}

当发送请求为:http://localhost:8001/aop/testafter.do?key=55553&value=855sss

详解SpringBoot之集成Spring AOP

当发送请求为:http://localhost:8001/aop/testafter02.do?key=55553&value=855sss

详解SpringBoot之集成Spring AOP

环绕通知

环绕通知的配置方式如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * 环绕通知:
 *  环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
 *  环绕通知第一个参数必须是org.aspectj.lang.proceedingjoinpoint类型
 */
@around("execution(* com.zkn.learnspringboot.web.controller..*.testaround*(..))")
public object doaroundadvice(proceedingjoinpoint proceedingjoinpoint){
  system.out.println("环绕通知的目标方法名:"+proceedingjoinpoint.getsignature().getname());
  try {
    object obj = proceedingjoinpoint.proceed();
    return obj;
  } catch (throwable throwable) {
    throwable.printstacktrace();
  }
  return null;
}

controller对应的请求处理类如下:

?
1
2
3
4
5
@requestmapping("/testaroundservice.do")
public string testaroundservice(string key){
 
  return "环绕通知:"+key;
}

当发送请求为:http://localhost:8001/aop/testaroundservice.do?key=55553

详解SpringBoot之集成Spring AOP

当发送请求为:http://localhost:8001/aop/testafter02.do?key=55553&value=855sss时,不符合环绕通知的切入规则,所以环绕通知不会 执行。

完整的aop配置代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package com.zkn.learnspringboot.aop;
 
import com.alibaba.fastjson.json;
import com.google.common.collect.maps;
import org.aspectj.lang.joinpoint;
import org.aspectj.lang.proceedingjoinpoint;
import org.aspectj.lang.signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.component;
import org.springframework.web.context.request.requestattributes;
import org.springframework.web.context.request.requestcontextholder;
 
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpsession;
import java.util.enumeration;
import java.util.map;
 
/**
 * created by zkn on 2016/11/18.
 */
@component
@aspect
public class webcontrolleraop {
 
  //匹配com.zkn.learnspringboot.web.controller包及其子包下的所有类的所有方法
  @pointcut("execution(* com.zkn.learnspringboot.web.controller..*.*(..))")
  public void executeservice(){
 
  }
 
  /**
   * 前置通知,方法调用前被调用
   * @param joinpoint
   */
  @before("executeservice()")
  public void dobeforeadvice(joinpoint joinpoint){
    system.out.println("我是前置通知!!!");
    //获取目标方法的参数信息
    object[] obj = joinpoint.getargs();
    //aop代理类的信息
    joinpoint.getthis();
    //代理的目标对象
    joinpoint.gettarget();
    //用的最多 通知的签名
    signature signature = joinpoint.getsignature();
    //代理的是哪一个方法
    system.out.println(signature.getname());
    //aop代理类的名字
    system.out.println(signature.getdeclaringtypename());
    //aop代理类的类(class)信息
    signature.getdeclaringtype();
    //获取requestattributes
    requestattributes requestattributes = requestcontextholder.getrequestattributes();
    //从获取requestattributes中获取httpservletrequest的信息
    httpservletrequest request = (httpservletrequest) requestattributes.resolvereference(requestattributes.reference_request);
    //如果要获取session信息的话,可以这样写:
    //httpsession session = (httpsession) requestattributes.resolvereference(requestattributes.reference_session);
    enumeration<string> enumeration = request.getparameternames();
    map<string,string> parametermap = maps.newhashmap();
    while (enumeration.hasmoreelements()){
      string parameter = enumeration.nextelement();
      parametermap.put(parameter,request.getparameter(parameter));
    }
    string str = json.tojsonstring(parametermap);
    if(obj.length > 0) {
      system.out.println("请求的参数信息为:"+str);
    }
  }
 
  /**
   * 后置返回通知
   * 这里需要注意的是:
   *   如果参数中的第一个参数为joinpoint,则第二个参数为返回值的信息
   *   如果参数中的第一个参数不为joinpoint,则第一个参数为returning中对应的参数
   * returning 限定了只有目标方法返回值与通知方法相应参数类型时才能执行后置返回通知,否则不执行,对于returning对应的通知方法参数为object类型将匹配任何目标返回值
   * @param joinpoint
   * @param keys
   */
  @afterreturning(value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))",returning = "keys")
  public void doafterreturningadvice1(joinpoint joinpoint,object keys){
 
    system.out.println("第一个后置返回通知的返回值:"+keys);
  }
 
  @afterreturning(value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))",returning = "keys",argnames = "keys")
  public void doafterreturningadvice2(string keys){
 
    system.out.println("第二个后置返回通知的返回值:"+keys);
  }
 
  /**
   * 后置异常通知
   * 定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;
   * throwing 限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行,
   *   对于throwing对应的通知方法参数为throwable类型将匹配任何异常。
   * @param joinpoint
   * @param exception
   */
  @afterthrowing(value = "executeservice()",throwing = "exception")
  public void doafterthrowingadvice(joinpoint joinpoint,throwable exception){
    //目标方法名:
    system.out.println(joinpoint.getsignature().getname());
    if(exception instanceof nullpointerexception){
      system.out.println("发生了空指针异常!!!!!");
    }
  }
 
  /**
   * 后置最终通知(目标方法只要执行完了就会执行后置通知方法)
   * @param joinpoint
   */
  @after("executeservice()")
  public void doafteradvice(joinpoint joinpoint){
 
    system.out.println("后置通知执行了!!!!");
  }
 
  /**
   * 环绕通知:
   *  环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
   *  环绕通知第一个参数必须是org.aspectj.lang.proceedingjoinpoint类型
   */
  @around("execution(* com.zkn.learnspringboot.web.controller..*.testaround*(..))")
  public object doaroundadvice(proceedingjoinpoint proceedingjoinpoint){
    system.out.println("环绕通知的目标方法名:"+proceedingjoinpoint.getsignature().getname());
    try {//obj之前可以写目标方法执行前的逻辑
      object obj = proceedingjoinpoint.proceed();//调用执行目标方法
      return obj;
    } catch (throwable throwable) {
      throwable.printstacktrace();
    }
    return null;
  }
}

完整的controller类代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.zkn.learnspringboot.web.controller;
 
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;
 
/**
 * created by zkn on 2016/11/19.
 */
@restcontroller
@requestmapping("/aop")
public class aoptestcontroller {
 
  @requestmapping("/testbeforeservice.do")
  public string testbeforeservice(string key,string value){
 
    return "key="+key+" value="+value;
  }
  @requestmapping("/testafterreturning.do")
  public string testafterreturning(string key){
 
    return "key=: "+key;
  }
  @requestmapping("/testafterreturning01.do")
  public integer testafterreturning01(integer key){
 
    return key;
  }
  @requestmapping("/testafterthrowing.do")
  public string testafterthrowing(string key){
 
    throw new nullpointerexception();
  }
  @requestmapping("/testafter.do")
  public string testafter(string key){
 
    throw new nullpointerexception();
  }
  @requestmapping("/testafter02.do")
  public string testafter02(string key){
 
    return key;
  }
  @requestmapping("/testaroundservice.do")
  public string testaroundservice(string key){
 
    return "环绕通知:"+key;
  }
}

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

原文链接:http://blog.csdn.net/zknxx/article/details/53240959

延伸 · 阅读

精彩推荐
  • JAVA教程java冒泡排序简单实例

    java冒泡排序简单实例

    本文主要介绍了JSONjava冒泡排序实例与思路分析。具有一定的参考价值,下面跟着小编一起来看下吧 ...

    夏日的微笑4812020-07-28
  • JAVA教程java计算时间差的方法

    java计算时间差的方法

    这篇文章主要介绍了java计算时间差的方法,涉及java针对时间的转换与计算相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下 ...

    答复哈2672019-12-27
  • JAVA教程mybatis查询匹配机制图文详解

    mybatis查询匹配机制图文详解

    这篇文章主要给大家介绍了关于mybatis查询匹配机制的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    时光斑驳了记忆3292020-08-28
  • JAVA教程10个经典的Java main方法面试题

    10个经典的Java main方法面试题

    这篇文章主要为大家分享了10个经典的Java main方法面试题,与其说是Java面试题,其实也是Java的一些最基础知识问题,感兴趣的小伙伴们可以参考一下 ...

    世勋SeHun3882020-03-23
  • JAVA教程JavaWeb文件上传下载功能深入分析(二)

    JavaWeb文件上传下载功能深入分析(二)

    这篇文章主要为大家详细解析了JavaWeb文件上传与下载功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 ...

    小平果1183372020-05-22
  • JAVA教程老生常谈java中的Future模式

    老生常谈java中的Future模式

    下面小编就为大家带来一篇老生常谈java中的Future模式。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    Java教程网1872020-11-19
  • JAVA教程Spring Boot Log4j2的配置使用详解

    Spring Boot Log4j2的配置使用详解

    本篇文章主要介绍了Spring Boot Log4j2的配置使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    Kylin3242020-09-29
  • JAVA教程Spring Batch入门教程篇

    Spring Batch入门教程篇

    这篇文章主要给大家介绍了Spring Batch入门的相关资料,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编一起来学习学习...

    翟永超1552020-11-12