AOP - 2 实例(SpringBoot 注解方式)
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 注解方式)的更多相关文章
- (转)Spring使用AspectJ进行AOP的开发:注解方式
http://blog.csdn.net/yerenyuan_pku/article/details/69790950 Spring使用AspectJ进行AOP的开发:注解方式 之前我已讲过Sprin ...
- Spring学习4-面向切面(AOP)之aspectj注解方式
一.简介 1.AOP用在哪些方面:AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理.日志管理.权限控制,异常处理等,封装起来,便于减少系统的重复代码,降低模块间的耦合 ...
- Spring的AOP基于AspectJ的注解方式开发2
参考自黑马培训机构 上一篇博客提到了在配置文件中开启aop的注解开发,以及简单使用了@Before,@Aspect 这是为了告诉spring为前置通知和切面类 接下来介绍aop的注解的通知类型,和切入 ...
- Spring的AOP基于AspectJ的注解方式开发1
参考自黑马培训机构 创建项目,引入jar包 编写目标类,切面类并完成配置 package spring.day2_aop2; /* * 编写目标类 */ public class OrderDao { ...
- Java SpringBoot注解方式开启异步支持
package task.demo.controller; import org.springframework.beans.factory.annotation.Autowired; import ...
- Spring的AOP基于AspectJ的注解方式开发3
上上偏博客介绍了@Aspect,@Before 上篇博客介绍了spring的AOP开发的注解通知类型:@Before,@AfterThrowing,@After,@AfterReturning,@Ar ...
- spring AOP (使用AspectJ的注解方式 的aop实现) (6)
目录 一.在 Spring 中启用 AspectJ 注解支持 二.AspectJ 支持 5 种类型的通知注解: 2.1.使用之前的 计算器接口和实现类 ArithmeticCalculator.jav ...
- springboot注解方式使用redis缓存
引入依赖库 在pom中引入依赖库,如下 <dependency> <groupId>org.springframework.boot</groupId> <a ...
- mybatis+druid+springboot 注解方式配置多个数据源
1\数据库配置 #test数据源 spring.datasource.test.url=jdbc:mysql:///db?useUnicode= spring.datasource.test.user ...
随机推荐
- Fiddler原理~知多少?
首先我们学习Fidder这个工具,我们就应该去了解它的基本东西,比如这个单词的意思.Fiddler叫:小提琴.骗子的意思. 那么它是干什么的呢? Fiddler是一个http协议调试代理工具,它能够记 ...
- 聊聊在AOP模式下的缓存方案
面向方法的数据集缓存 使用了autofac做为ioc容器,使用Autofac.Extras.DynamicProxy2作为方法拦截器,缓存面向方法,直接在方法上添加CachingAttribute特性 ...
- vue的父子组件间的相互传参props及props数据的多种验证机制
感觉自己即将完全步入前端大军,后台老板都不需要我弄了,塞翁失马...时间会告诉我们是好是坏 好了言归正传,最近vue是搞的不亦乐乎啊,下面来总结一下vue组件间的各种使用方法以及一些技巧 ------ ...
- PyCharm:选择性忽略 PEP8 警告
PyCharm 是个很强大的 python IDE,PEP 8 的告警提示也很好用,但是函数名不能包含大写字母等少数几个规范真心觉得不好,作为一名处女座强迫症患者,代码下面的波浪线这种东西是绝对不允许 ...
- Springboot 系列(八)动态Banner与图片转字符图案的手动实现
使用过 Springboot 的对上面这个图案肯定不会陌生,Springboot 启动的同时会打印上面的图案,并带有版本号.查看官方文档可以找到关于 banner 的描述 The banner tha ...
- EffectiveJava阅读笔记(一)
考虑用静态工厂方法代替构造器 一.概述 二.使用静态工厂的优势 获取类对象的两种方式: 使用公有构造方法 静态工厂方法 1.介绍 有名称 不必每次调用时创建一个新对象 可以返回原类型的任何子类型对象 ...
- 二进制数据的序列化反序列化和Json的序列化反序列化的重要区别
前言:最近一个一个很奇怪的问题,很明白的说,就是没看懂,参照下面的代码: /// <summary> /// 反序列化对象 /// </summary> /// <typ ...
- [转]Node.js 应用:Koa2 使用 JWT 进行鉴权
本文转自:https://www.cnblogs.com/linxin/p/9491342.html 前言 在前后端分离的开发中,通过 Restful API 进行数据交互时,如果没有对 API 进行 ...
- Flask实战第3天:url_for使用
我们之前是通过url来找到对应的视图函数 / => hello_world 那么url_for则是通过视图函数找到url hello world => / 演示如下 #c ...
- ASP.NET MVC 5 實作 GridView 分頁
本文用 ASP.NET MVC 5 實作一個 GridView,功能包括: 分頁(paging).關鍵字過濾(filtering).排序(sorting).AJAX 非同步執行,外觀上亦支援 Resp ...