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. 【Android Studio安装部署系列】二十七、Android studio修改项目名称和包名

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 实际项目开发中可能碰到项目名称写错了或者需要修改,而且包名可能也想要修改,那么如何操作呢. 本文是在Android Studio3. ...

  2. 前后端同学,必会的Linux常用基础命令

    无论是前端还是后端同学,一些常用的linux命令还是必须要掌握的.发布版本.查看日志等等都会用到.以下是我简单的总结了一些简单又常用的命令,欢迎大家补充.希望能帮助到大家 本文首发于公众号 程序员共成 ...

  3. kubernetes系列08—service资源详解

    本文收录在容器技术学习系列文章总目录 1.认识service 1.1 为什么要使用service Kubernetes Pod 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结 ...

  4. Reactive Extensions 相见恨晚的Rx.Net

    何为Reactive Extensions(Rx) Rx是一个遵循函数式编程的类库,它引用观察者以及迭代器设计模式对可观察对象产生的数据进行异步消费.使用Rx, 开发人员将使用LINQ运算符操作异步数 ...

  5. .NET运行时中的监测和可观测性

    今年5月份的时候研究分布式追踪的问题知道了的拦截方式比较零散, 刚好8月份的时候看到这篇文章,这个文章总结的比较完整.存档了很久,趁今天有空翻译给大家.原文地址,校验:张蘅水 .NET是一个托管运行时 ...

  6. Js-函数式编程

    前言 JavaScript是一门多范式语言,即可使用OOP(面向对象),也可以使用FP(函数式),由于笔者最近在学习React相关的技术栈,想进一步深入了解其思想,所以学习了一些FP相关的知识点,本文 ...

  7. python的小技巧 让你的代码更美观

    持续更新.. 1,活用lambda表达式 匿名函数 lambda 可以提供很多便利.下面是举例. dic = {1:lambda a,b : a+b} 2,代码一行化. 当逻辑语句后只有一行代码的时候 ...

  8. WPF 自定义 ImageButton

    控件源码: public class ImageButton : Button    {        public ImageButton() {        } public string No ...

  9. .net core 使用MD5加密解密字符串

    /// <summary> /// 加密 /// </summary> /// <param name="Text">要加密的文本</pa ...

  10. js将一个数组分成多个数组

    1,将数组array分成长度为subGroupLength的小数组并返回新数组 function group(array, subGroupLength) { let index = 0; let n ...