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. 死磕 java集合之ConcurrentSkipListMap源码分析——发现个bug

    前情提要 点击链接查看"跳表"详细介绍. 拜托,面试别再问我跳表了! 简介 跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表. 跳表在原有的有序链表上面增加了多级 ...

  2. eclipse升级Android SDK Tool版本到25.2.5后运行项目报错Unable to build: the file dx.jar was not loaded from the SDK folder

    概述 由于最近通过SDK-Manager更新了build-tools,当要用到dx.jar这个包时,自动调用最新版本Android SDK build-tools中dx.jar,但是运行android ...

  3. springboot~zuul实现网关

    网关在微服务里的角色 在微服务架构体系里,网关是非常重要的一个环节,它主要实现了一些功能的统一处理,包括了: 统一授权 统一异常处理 路由导向 跨域处理 限流 实践一下 1 添加依赖 dependen ...

  4. HandlerInterceptor里@Autowired对象为空的解决方法

    That's because Spring isn't managing your PagePopulationInterceptor instance. You are creating it yo ...

  5. Java进阶篇设计模式之一 ----- 单例模式

    前言 在刚学编程没多久就听说过设计模式的大名,不过由于当时还是个彻彻底底的菜鸟,并没有去触碰.直到在开始工作中对简单的业务代码较为熟悉之后,才正式的接触设计模式.当时最早接触的设计模式是工厂模式,不过 ...

  6. 云HBase发布全文索引服务,轻松应对复杂查询

    云HBase发布了“全文索引服务”功能,自2019年01月25日后创建的云HBase实例,可以在控制台免费开启此“全文索引服务”功能.使用此功能可以让用户在HBase之上构建功能更丰富的搜索业务,不再 ...

  7. 深入解析ThreadLocal 详解、实现原理、使用场景方法以及内存泄漏防范 多线程中篇(十七)

    简介 从名称看,ThreadLocal 也就是thread和local的组合,也就是一个thread有一个local的变量副本 ThreadLocal提供了线程的本地副本,也就是说每个线程将会拥有一个 ...

  8. 创建简单的npm脚手架

    前言 vue-cli, webpack-cli 等脚手架是不是用起来爱不释手?自己写了个模版每次来回复制粘贴代码是不是很难维护?如果你是对前端.Node操作有一定的了解,同时也存在以上疑问,那就请尽情 ...

  9. 【经典案例】Python详解设计模式:策略模式

    完成一项任务往往有多种方式,我们将其称之为策略. 比如,超市做活动,如果你的购物积分满1000,就可以按兑换现金抵用券10元,如果购买同一商品满10件,就可以打9折,如果如果购买的金额超过500,就可 ...

  10. 【转】IIS上的反向代理

    http://blog.csdn.net/yuanguozhengjust/article/details/23576033 一直说在IIS上做反向代理,由于沉迷在nginx一行指令完事的美好情景当中 ...