1、创建Spring Boot项目

  创建一个Spring Boot 项目,然后pom中引入web 模块与AOP相关依赖。

        <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.0.1.RELEASE</version>
</dependency> <dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>

其中: 
aspectjweaver是与aspectj相关的包,用来支持切面编程的; 
aspectjweaver是aspectj的织入包;

2、实现一个web请求,数据通过接口获取(使用POJO类传参与返回值)

@RestController
@RequestMapping("/aop")
public class AopController { @Autowired
private AopService aopService; @GetMapping(value = "getResult")
public ResultVO sayHello(ParamVO paramVO) {
ParamDTO paramDTO = new ParamDTO();
BeanUtils.copyProperties(paramVO, paramDTO);
ResultDTO resultDTO = aopService.getResult(paramDTO);
ResultVO resultVO = new ResultVO();
BeanUtils.copyProperties(resultDTO, resultVO);
return resultVO;
}
}

  

列出一个POJO类,其他类似。返回给前端的统一使用VO,业务逻辑层之间的传递使用DTO,映射数据库的使用Domain:

public class ParamVO {

    private String name;

    private Integer age;

    public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} @Override
public String toString() {
return "ParamVO{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

3、web请求对应的接口

import cn.latiny.modules.aopone.model.ParamDTO;
import cn.latiny.modules.aopone.model.ResultDTO; public interface AopService { ResultDTO getResult(ParamDTO param);
}
@Service
public class AopServiceImpl implements AopService { @Override
public ResultDTO getResult(ParamDTO param) {
ResultDTO result = new ResultDTO();
result.setId(1001);
result.setMessage(param.toString());
result.setData(Arrays.asList("Latiny", "30", "20000"));
return result;
}
}

  4、定义一个切面类,实现对Service方法进行切面

把一个类变成切面类,需要两步: 
① 在类上使用 @Component 注解 把切面类加入到IOC容器中 
② 在类上使用 @Aspect 注解 使之成为切面类

/**
* @description AopService切面类
*/
@Aspect
@Component
public class AopServiceAspect { private final Logger logger = LoggerFactory.getLogger(AopService.class);
}

  (1) 定义一个切入点

  这里我们对AopService的getResult() 方法进行切面编程。

    /**
* 定义一个切入点
*/
@Pointcut("execution(* cn.latiny.modules.aopone.service.AopService.getResult(..))")
public void pointCut() { }

  

  (2) 定义一个前置通知

    /**
* 前置通知
* @param joinPoint
* @param name
*/
@Before("pointCut() && args(name)")
public void before(JoinPoint joinPoint, String name) {
Object[] parameters = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName + "方法 Before通知,方法的参数: " + name);
}

我们通过注解@Before结合切入点完成对getResult() 方法的切面,在before() 方法里,我们可以在getResult() 执行前做任何想做的事。在这个方法里,我们通过JoinPoint可以得到对应切入点的目标对象的所有信息,类名,方法名,方法参数名以及传递的值。

  (3) 其他通知的定义

    /**
* 后置通知,异常时不执行
* @param joinPoint
* @param name
*/
@AfterReturning(value = "pointCut() && args(name)", returning = "result")
public void afterReturning(JoinPoint joinPoint, String result, String name) {
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName + "方法 AfterReturning通知,方法的参数: " + name + ", 方法返回值:" + result);
} /**
* 后置通知,不管对应的连接点方法是否正常执行,都会执行此通知
* @param joinPoint
* @param name
*/
@After(value = "pointCut() && args(name)")
public void after(JoinPoint joinPoint, String name) {
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName + "方法 After通知,方法的参数: " + name);
} /**
* 环绕通知,在不修改原来方法的前提下,可以在方法执行前修改方法的入参,也可以在方法执行之后修改方法的返回值。
* 环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
* 环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
* @param joinPoint
* @return
*/
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName() + "方法 Around通知开始");
processInputArg(joinPoint.getArgs());
try {
Object obj = joinPoint.proceed();
processOutputObj(obj);
if(obj instanceof ResultDTO) {
ResultDTO resultDTO = (ResultDTO) obj;
System.out.println("修改后的返回值:" + resultDTO.toString());
}
System.out.println(joinPoint.getSignature().getName() + "方法 Around通知结束");
return obj;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println(joinPoint.getSignature().getName() + "方法 Around通知结束");
return null; } /**
* 处理输入参数
*/
private void processInputArg(Object[] args) {
for(Object arg: args) {
System.out.println("参数原来的值为:" + arg.toString());
if (arg instanceof ParamDTO) {
ParamDTO param = (ParamDTO)arg;
param.setAge(18);
param.setName("Nowesiki");
}
System.out.println("参数修改的值为:" + arg.toString());
}
} /**
* 返回值处理
* @param obj
*/
private void processOutputObj(Object obj) {
if(obj instanceof ResultDTO) {
ResultDTO result = (ResultDTO) obj;
result.setId(1002);
result.setMessage(result.getMessage());
result.setData(Arrays.asList("Nowesike", "40", "1000000000"));
}
}

  5、测试

  这里测试一下环绕通知,其他的通知暂时注释掉,启动项目之后,直接在浏览器访问AopController接口即可。

  这里前端传的参数是,name = 马云,age = 44

  

  最后的结果是:

getResult方法 Around通知开始
参数原来的值为:ParamVO{name=马云, age=44}
参数修改的值为:ParamVO{name=Nowesiki, age=18}
修改后的返回值:ResultDTO{id=1002, message='ParamVO{name=Nowesiki, age=18}', data=[Nowesike, 40, 1000000000]}
getResult方法 Around通知结束

  环绕通知里不仅可以获取到目标对象的所有信息,还能改变目标对象的入参与返回值,功能非常强大。

  

AOP - 2 实例(SpringBoot 注解方式)的更多相关文章

  1. (转)Spring使用AspectJ进行AOP的开发:注解方式

    http://blog.csdn.net/yerenyuan_pku/article/details/69790950 Spring使用AspectJ进行AOP的开发:注解方式 之前我已讲过Sprin ...

  2. Spring学习4-面向切面(AOP)之aspectj注解方式

    一.简介    1.AOP用在哪些方面:AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理.日志管理.权限控制,异常处理等,封装起来,便于减少系统的重复代码,降低模块间的耦合 ...

  3. Spring的AOP基于AspectJ的注解方式开发2

    参考自黑马培训机构 上一篇博客提到了在配置文件中开启aop的注解开发,以及简单使用了@Before,@Aspect 这是为了告诉spring为前置通知和切面类 接下来介绍aop的注解的通知类型,和切入 ...

  4. Spring的AOP基于AspectJ的注解方式开发1

    参考自黑马培训机构 创建项目,引入jar包 编写目标类,切面类并完成配置 package spring.day2_aop2; /* * 编写目标类 */ public class OrderDao { ...

  5. Java SpringBoot注解方式开启异步支持

    package task.demo.controller; import org.springframework.beans.factory.annotation.Autowired; import ...

  6. Spring的AOP基于AspectJ的注解方式开发3

    上上偏博客介绍了@Aspect,@Before 上篇博客介绍了spring的AOP开发的注解通知类型:@Before,@AfterThrowing,@After,@AfterReturning,@Ar ...

  7. spring AOP (使用AspectJ的注解方式 的aop实现) (6)

    目录 一.在 Spring 中启用 AspectJ 注解支持 二.AspectJ 支持 5 种类型的通知注解: 2.1.使用之前的 计算器接口和实现类 ArithmeticCalculator.jav ...

  8. springboot注解方式使用redis缓存

    引入依赖库 在pom中引入依赖库,如下 <dependency> <groupId>org.springframework.boot</groupId> <a ...

  9. mybatis+druid+springboot 注解方式配置多个数据源

    1\数据库配置 #test数据源 spring.datasource.test.url=jdbc:mysql:///db?useUnicode= spring.datasource.test.user ...

随机推荐

  1. Nginx安装与代理

    1.第一步 - 添加Nginx存储库 要添加CentOS 7 EPEL存储库,请打开终端并使用以下命令: sudo yum install epel-release 2.第二步 - 安装Nginx 现 ...

  2. 《前端之路》之 operator 操作符的优先级

    Github传送门,欢迎 Star - - Github地址,欢迎 Star

  3. TabLayoutViewPagerDemo【TabLayout+ViewPager可滑动】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 使用TabLayout搭配ViewPager实现可滑动的顶部选项卡效果. 效果图 代码分析 1.演示常规的设置. 2.通过自定义Vi ...

  4. springcloud~服务注册与发现Eureka的使用

    服务注册与发现是微服务里的概念,也是一个基本的组件,负责服务组件的认证,即实现『你是谁』的功能,在服务注册与发现里,存在两种模式,即服务端发现和客户端发现,咱们今天说的eureka属于客户端发现! 下 ...

  5. Linux framebuffer测试程序

    Linux framebuffer的框架非常简单, 对于应用程序就是操作一块内存(俗称帧缓存), 当然也有可能是双缓存, 一般用于高帧率场景, 一块帧在填充数据时, 另一块在显示, 接着对调过来, 那 ...

  6. 1分钟解决VS每次运行都显示“正在还原nuget程序包”问题

    VS一直停留在“正在还原nuget程序包” 在开发中,运行不同版本的vs会显示还原nuget程序包,还原需要不短的时间,并且不一定还原成功. 或者其他什么原因导致需要还原nuget程序包,这样很烦的有 ...

  7. c++性能测试工具:google benchmark入门(一)

    如果你正在寻找一款c++性能测试工具,那么这篇文章是不容错过的. 市面上的benchmark工具或多或少存在一些使用上的不便,那么是否存在一个使用简便又功能强大的性能测试工具呢?答案是google/b ...

  8. DS控件库 DS开放式下拉列表

    在一些场合中,需要使用组合式下拉列表控件,比如带treeivew的combobox,但是代码较多,使用不便.为此,本人制作了一个超级易用的DS开放式下拉列表. 以下演示使用过程. Private Su ...

  9. javascript中的typeof和类型判断

    typeof ECMAScript 有 5 种原始类型(primitive type),即 Undefined.Null.Boolean.Number 和 String.我们都知道可以使用typeof ...

  10. AI产品的商业模式

    AI产品的商业模式 ------------------------------------------------------------------------------------------ ...