SpringBoot之集成Spring AOP
在开始之前,我们先把需要的jar包添加到工程里。新增Maven依赖如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
接下来,我们进入正题。这里的涉及的通知类型有:前置通知、后置最终通知、后置返回通知、后置异常通知、环绕通知,下面我们就具体的来看一下怎么在SpringBoot中添加这些通知。
首先我们先创建一个Aspect切面类:
@Component @Aspect public class WebControllerAop { }
指定切点:
//匹配com.zkn.learnspringboot.web.controller包及其子包下的所有类的所有方法 @Pointcut("execution(* com.zkn.learnspringboot.web.controller..*.*(..))") public void executeService(){ }
接着我们再创建一个Controller请求处理类:
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 { }
前置通知
配置前置通知:
/** * 前置通知,方法调用前被调用 * @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类里添加一个请求处理方法来测试一下前置通知:
@RequestMapping("/testBeforeService.do") public String testBeforeService(String key,String value){ return "key="+key+" value="+value; }
前置通知拦截结果如下所示:
后置返回通知
配置后置返回通知的代码如下:
/** * 后置返回通知 * 这里需要注意的是: * 如果参数中的第一个参数为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里添加响应的请求处理信息来测试后置返回通知:
@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时,处理结果如图所示:
当发送请求为:http://localhost:8001/aop/testAfterReturning01.do?key=55553&value=855sss时,处理结果如图所示:
后置异常通知
后置异常通知的配置方式如下:
/** * 后置异常通知 * 定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法; * 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里配置响应的请求处理类:
@RequestMapping("/testAfterThrowing.do") public String testAfterThrowing(String key){ throw new NullPointerException(); }
后置异常通知方法的处理结果如下所示:
后置最终通知
后置最终通知的配置方式如下:
/** * 后置最终通知(目标方法只要执行完了就会执行后置通知方法) * @param joinPoint */ @After("executeService()") public void doAfterAdvice(JoinPoint joinPoint){ System.out.println("后置通知执行了!!!!"); }
Controller类配置相应的请求处理类:
@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
当发送请求为:http://localhost:8001/aop/testAfter02.do?key=55553&value=855sss
环绕通知
环绕通知的配置方式如下:
/** * 环绕通知: * 环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。 * 环绕通知第一个参数必须是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对应的请求处理类如下:
@RequestMapping("/testAroundService.do") public String testAroundService(String key){ return "环绕通知:"+key; }
当发送请求为:http://localhost:8001/aop/testAroundService.do?key=55553
当发送请求为:http://localhost:8001/aop/testAfter02.do?key=55553&value=855sss时,不符合环绕通知的切入规则,所以环绕通知不会 执行。
完整的AOP配置代码如下:
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类代码如下:
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://lib.csdn.net/article/microservice/60453?knId=1899

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Hystrix降级技术解析-Fallback
一、降级 所谓降级,就是指在在Hystrix执行非核心链路功能失败的情况下,我们如何处理,比如我们返回默认值等。如果我们要回退或者降级处理,代码上需要实现HystrixCommand.getFallback()方法或者是HystrixObservableCommand. HystrixObservableCommand()。 publicclassCommandHelloFailureextendsHystrixCommand<String>{ privatefinalStringname; publicCommandHelloFailure(Stringname){ super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")); this.name=name; } @Override protectedStringrun(){ thrownewRuntimeException("thiscommandalwaysfails"); } @Override protectedStringgetFallback(){ r...
- 下一篇
基于Hadoop大数据分析应用场景与实战
为了满足日益增长的业务变化,京东的京麦团队在京东大数据平台的基础上,采用了Hadoop等热门的开源大数据计算引擎,打造了一款为京东运营和产品提供决策性的数据类产品-北斗平台。 一、Hadoop的应用业务分析 大数据是不能用传统的计算技术处理的大型数据集的集合。它不是一个单一的技术或工具,而是涉及的业务和技术的许多领域。 目前主流的三大分布式计算系统分别为:Hadoop、Spark和Strom: Hadoop当前大数据管理标准之一,运用在当前很多商业应用系统。可以轻松地集成结构化、半结构化甚至非结构化数据集。 Spark采用了内存计算。从多迭代批处理出发,允许将数据载入内存作反复查询,此外还融合数据仓库,流处理和图形计算等多种计算范式。Spark构建在HDFS上,能与Hadoop很好的结合。它的RDD是一个很大的特点。 Storm用于处理高速、大型数据流的分布式实时计算系统。为Hadoop添加了可靠的实时数据处理功能 Hadoop是使用Java编写,允许分布在集群,使用简单的编程模型的计算机大型数据集处理的Apache的开源框架。 Hadoop框架应用工程提供跨计算机集群的分布式存储和计...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2全家桶,快速入门学习开发网站教程
- Docker安装Oracle12C,快速搭建Oracle学习环境
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7,CentOS8安装Elasticsearch6.8.6