0、前言

1、什么是AOP

  AOP(面向切面编程),是一种横切技术,是对OOP的补充和完善;

  使用AOP的横切,可以对系统进行无侵入性的日志监听、事务、权限管理等;

  思想上跟拦截器其实类似;拦截器是对action进行拦截处理,AOP是对切面进行拦截处理,其实切面也属于一种action集合;

  AOP可以很好解耦;

2、AOP的组成

  Aspect:切面;

  Join point:连接点;

  Advice:通知,在切入点上执行的操作;

  Poincut:带有通知的连接点;

  target:被通知的对象;

  AOP proxy;AOP代理;

其中,Advice(通知)分为以下几种:

  • before(前置通知): 在方法开始执行前执行
  • after(后置通知): 在方法执行后执行
  • afterReturning(返回后通知): 在方法返回后执行
  • afterThrowing(异常通知): 在抛出异常时执行
  • around(环绕通知): 在方法执行前和执行后都会执行

通知的执行顺序:

around > before > around > after > afterReturning

一、实现示例

  光看理论和定义,很多人可能都觉得很难理解,其实用法比较简单,不难的,

  我们先来个简单的例子,看完例子你可能就豁然开朗了,

  所谓程序员,好看书不如多动手:

  实现:

1、添加依赖

        <!-- 8、集成AOP  -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2、添加切面类LogAspect

package com.anson.common.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest;
import java.util.Arrays; /**
* @description: AOP切面
* @author: anson
* @Date: 2019/12/20 10:11
*/ @Aspect //1、添加AOP相关注解
@Component
public class LogAspect
{
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class); //2、定义切入点(可以匹配、注解的方式,可混用)
// @Pointcut("execution(public * com.anson.controller.*.*(..))")
@Pointcut("execution(public * com.anson.controller.*.*(..)) && @annotation(com.anson.common.annotation.LogAnnotation)")
// @Pointcut("execution(public * com.anson.controller.TestController.get*()) && @annotation(com.anson.common.annotation.LogAnnotation)")
public void pointcut(){} //===========通知 多中通知可根据需要灵活选用,一般Before 、AfterReturning即可=======================
/**
* 前置通知:在连接点之前执行的通知
* @param joinPoint
* @throws Throwable
*/
@Before("pointcut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest(); // 记录下请求内容
logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
} @AfterReturning(returning = "ret",pointcut = "pointcut()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
logger.info("RESPONSE : " + ret);
}
//==============================================
@After("pointcut()")
public void commit() {
logger.info("after commit");
} @AfterThrowing("pointcut()")
public void afterThrowing() {
logger.info("afterThrowing afterThrowing rollback");
} @Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
try {
System.out.println("around");
return joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
throw e;
} finally {
logger.info("around");
}
} }

需要注意的是:上面代码注释2的地方【2、定义切入点(可以匹配、注解的方式,可混用)】;

简单点说就是通过匹配或者注解(也可两种同时使用)匹配哪些类的哪些方法;

再直白点说,就是我们要对哪些类的哪些方法执行处理,要处理的范围是哪些;

类用*作为通配符,方法用(..)表示,括号中的两点表示匹配任何参数,包括没有参数;

上面这样其实就可以完成一个切面了,

比如将切面定义那里改为:@Pointcut("execution(public * com.anson.controller.*.*(..))")
那么运行程序后,所有com.anson.controller包下的所有类的所有方法,都会执行这个切面定义的方法进行相关写日志处理了,结果如下:
around
[2019-12-20 11:19:02,205][INFO ][http-nio-8095-exec-1] URL : http://localhost:8095/user/userall (LogAspect.java:45)
[2019-12-20 11:19:02,205][INFO ][http-nio-8095-exec-1] HTTP_METHOD : GET (LogAspect.java:46)
[2019-12-20 11:19:02,206][INFO ][http-nio-8095-exec-1] IP : 0:0:0:0:0:0:0:1 (LogAspect.java:47)
[2019-12-20 11:19:02,207][INFO ][http-nio-8095-exec-1] CLASS_METHOD : com.anson.controller.UserController.getUserAll (LogAspect.java:48)
[2019-12-20 11:19:02,208][INFO ][http-nio-8095-exec-1] ARGS : [] (LogAspect.java:49)
[2019-12-20 11:19:02,510][DEBUG][http-nio-8095-exec-1] ==> Preparing: select id, userName, passWord, realName from user (BaseJdbcLogger.java:143)
[2019-12-20 11:19:02,606][DEBUG][http-nio-8095-exec-1] ==> Parameters: (BaseJdbcLogger.java:143)
[2019-12-20 11:19:02,631][DEBUG][http-nio-8095-exec-1] <== Total: 4 (BaseJdbcLogger.java:143)
[2019-12-20 11:19:02,634][INFO ][http-nio-8095-exec-1] around (LogAspect.java:77)
[2019-12-20 11:19:02,635][INFO ][http-nio-8095-exec-1] after commit (LogAspect.java:60)
[2019-12-20 11:19:02,635][INFO ][http-nio-8095-exec-1] RESPONSE : com.anson.common.result.ResultBody@6d9947d (LogAspect.java:55)
如果不用注解的话,上面就已经完成一个切面了,如果用注解来定义切面范围呢,好,也简单,我们来定义一个注解

--------------华丽丽的分割线-------------------------------
--------------增加自定义注解的方式----------------------------

3、添加一个LogAnnotation注解


package com.anson.common.annotation;

import java.lang.annotation.*;

/**
* @description: 自定义注解
* @author: anson
* @Date: 2019/12/20 10:32
*/ @Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAnnotation
{ }

这样就可以了,然后,在需要的地方,加入这个自定义注解:

    //2、获取所有用户
@ApiOperation(value = "获取所有用户", notes = "获取所有用户")
@RequestMapping(value="/userall",method= RequestMethod.GET)
@LogAnnotation //自定义注解
public ResultBody getUserAll()
{
List<User> users = userservice.getAll();
return ResultBody.success(users,"获取所有用户信息成功");
}

同时,修改切面范围的定义即可:

//2、定义切入点(可以匹配、注解的方式,可混用)--以下表示范围为:controller包下所有包含@LogAnnotation注解的方法
 @Pointcut("execution(public * com.anson.controller.*.*(..)) && @annotation(com.anson.common.annotation.LogAnnotation)") 

public void pointcut(){}

完了,就这么简单;

至于什么地方该使用AOP,以及AOP和拦截器用哪个比较好,这个就要根据业务场景灵活取舍了,掌握了思想,具体使用那就可以灵活发挥了


小白的springboot之路(十四)、AOP的更多相关文章

  1. 小白的springboot之路(四)、mybatis-generator自动生成mapper和model、dao

    0-.前言 在用mybatis开发项目中,数据库动辄上百张数据表,如果你一个一个去手动编写,比较耗费时间:还好,我们有mybatis-generator插件,只需简单几步就能自动生成mybatis的m ...

  2. 小白的springboot之路(一)、环境搭建、第一个实例

    小白的springboot之路(一).环境搭建.第一个实例 0- 前言 Spring boot + spring cloud + vue 的微服务架构技术栈,那简直是爽得不要不要的,怎么爽法,自行度娘 ...

  3. SpringBoot系列(十四)集成邮件发送服务及邮件发送的几种方式

    往期推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)web静 ...

  4. JVM菜鸟进阶高手之路十四:分析篇

    转载请注明原创出处,谢谢! 题目回顾 JVM菜鸟进阶高手之路十三,问题现象就是相同的代码,jvm参数不一样,表现的现象不一样. private static final int _1MB = 1024 ...

  5. 小白的springboot之路(十)、全局异常处理

    0.前言 任何系统,我们不会傻傻的在每一个地方进行异常捕获和处理,整个系统一般我们会在一个的地方统一进行异常处理,spring boot全局异常处理很简单: 介绍前先说点题外话,我们现在开发系统,都是 ...

  6. 小白的springboot之路(十六)、mybatis-plus 的使用

    0-前言 mybatis plus是对mybatis的增强,集成mybatis plus后,简单的CRUD和分页就不用写了,非常方便,五星推荐: 1-集成 1-1.添加依赖 <!-- .集成my ...

  7. 小白的springboot之路(十二)、集成log4j2日志

    0.前言 日志记录对系统来说必不可少,spring boot中常用的日志组件有log4j.logback.log4j2,其中logback是spring boot默认的,已自带:选用log4j2就可以 ...

  8. 小白的springboot之路(十五)、mybatis的PageHelper分页插件使用

    0.前言 用mybatis,那么分页必不可少,基本都是用PageHelper这个分页插件,好用方便: 1.实现 1.1.添加依赖: <!-- 3.集成 mybatis pagehelper--& ...

  9. 小白的springboot之路(十八)、i18n多语言支持(后端篇)

    0-前言 在有些系统中,比如网站,往往需要支持多国语言,英文版中文版什么的,这个其实也不难: 今天我们就来介绍spring boot中用i18n在后端支持多语言: 当然,也可以直接在前端用i18n直接 ...

随机推荐

  1. PHP中Session ID的实现原理分析

    ession 的工作机制: 为每个访问者创建一个唯一的 id (UID),并基于这个 UID 来存储变量.UID 存储在 cookie 中,亦或通过 URL 进行传导. PHPSESSIONID的生产 ...

  2. kali下安装mobsf

    1.查看kali版本,安装mobsf对kali版本的要求是大于3.0并且是64位 uname -a 2.安装docker,有选择的地方直接回车就好 apt-get install docker doc ...

  3. MySQL常用的查询语句回顾

    让你快速复习语句的笔记宝典. create table users(    username varchar(20) primary key,    userpwd varchar(20) ) alt ...

  4. 工作常用4种Java线程锁的特点,性能比较、使用场景

    多线程的缘由 在出现了进程之后,操作系统的性能得到了大大的提升.虽然进程的出现解决了操作系统的并发问题,但是人们仍然不满足,人们逐渐对实时性有了要求. 使用多线程的理由之一是和进程相比,它是一种非常花 ...

  5. 【Luogu P1090】合并果子

    Luogu P1090 [解题思路] 刚看到这题的时候,第一反应就是每次取两个最小,然后重新排序,再取最小.但是这样会TLE. 既然找最小的,那就可以利用单调队列了.显然输入的数据是不具有单调性的,但 ...

  6. 几行代码轻松搞定python的sqlite3的存取

    很简单: 存数据: 1.加载sqlite3驱动(只需一行代码) 2.用驱动执行查询语句(只需一行代码) 取数据: 1.加载sqlite3驱动(只需一行代码) 2.用驱动执行查询语句(只需一行代码) 乍 ...

  7. [UWP]UIElement.Clip虽然残废,但它还可以这样玩

    1. 复习一下WPF的UIElement.Clip 用了很久很久的WPF,但几乎没有主动用过它的Clip属性,我只记得它很灵活,可以裁剪出多种形状.在官方文档复习了一下,大致用法和效果如下: < ...

  8. 预分配——fallocate的前世今生

    最近比较懒,还是加班写点东西吧,不然过段时间又把这些整理的东西弄丢了. 写什么呢?写一些跟工作相关的吧!因为笔者从事多媒体录像相关的开发工作,因此常常涉及到优化写卡策略.提升写卡性能相关的方面的事情. ...

  9. 深入浅出Spring(三)

    我为大家简单介绍了一下Spring框架核心内容中的IoC,接下来我们继续讲解另一个核心AOP(Aspect Oriented Programming),即面向切面编程. 1.OOP回顾 在介绍AOP之 ...

  10. “狗屁不通文章生成器”登顶GitHub热榜,分分钟写出万字形式主义大作

    一.垃圾文字生成器介绍 最近在浏览GitHub的时候,发现了这样一个骨骼清奇的雷人项目,而且热度还特别高. 项目中文名:狗屁不通文章生成器 项目英文名:BullshitGenerator 根据作者的介 ...