SpringAop配合自定义注解

SpringAop配合自定义注解

什么是AOP

AOP全称Aspect Oriented Programming,也就是面向切面编程。AOP主要实现的是针对业务处理过程中的切面进行提取,能够让我们在不影响原有业务功能的前提下,横切扩展新的功能。它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。

AOP相关术语

要理解Spring Boot整合AOP的实现,就必须先对面向切面实现的一些AOP术语有所了解。在Spring的AOP中有很多的术语,而且容易混淆,大家一定要先搞清楚这几个概念:

  • 切面(Aspect):一个关注点的模块化,由切点和通知组成。以注解@Aspect的形式放在类上方,用来声明切面。

  • 连接点(Joinpoint):在程序执行过程中某个特定的点,比如类初始化前、类初始化后,方法调用前,方法调用后。

  • 切点(Pointcut):切点就是你所切取的类中的方法,比如你横切的这个类中有两个方法,那么这两个方法都是连接点,对这两个方法的定位就称之为切点。以注解@Pointcut的形式,使用条件表达式定义切点。

  • 通知(Advice):需要完成的工作叫做通知,比如业务逻辑中的事务、日志等先定义好,然后在需要的地方去用。

    主要包括5个注解:Before、After、AfterReturning、AfterThrowing、Around。

    • @Before:前置增强,在切点方法之前执行。
    • @After:最终增强,在切点方法之后执行。
    • @AfterReturning:后置增强,在切点方法退出时执行。
    • @AfterThrowing:在切点方法抛出异常时执行。
    • @Around:环绕增强,能控制切点执行前,执行后,用这个注解后,程序抛异常,会影响@AfterThrowing这个注解。
  • 织入(Weaving):织入就是将通知逻辑添加到目标对象的过程。

  • 目标对象(Target):通知逻辑织入的目标类,就是通知逻辑植入到什么位置。

  • 引介(Introduction):一种特殊的通知,它可以在不改变一个现有类代码的情况下,为该类添加属性和方法。把切面定义的用到目标类中去。

  • 代理(Proxy):一个类被AOP织入通知后,就会产生一个结果类,他是融合了原类和通知逻辑的代理类。

引入依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

自定义注解

作用

在反射中获取注解,以取得注解修饰的类、方法或属性的相关解释。

注解代码

1
2
3
4
5
6
7
8
9
10
11
package com.istuadmission.common.annotation;

import java.lang.annotation.*;

@Target(value = {ElementType.TYPE, ElementType.METHOD})//使用位置(类,方法)
@Retention(RetentionPolicy.RUNTIME)//加载到jvm里运行
@Documented//文档化
public @interface Log {
String value() default "";//注解的属性,如果只有一个属性,一般叫value,默认值"",可以不写
String name() default "验证名称";
}

使用注解

1
2
3
4
5
@Log(value = "vale", name = "name") //与其它注解一样的使用
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String add() {
return "test";
}

创建AOP切面

作用

定义好注解后,需要解析类来实现,此处使用AOP来实现。

切面代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.istuadmission.common.aspect;

import com.istuadmission.common.annotation.Log;
import com.istuadmission.common.service.LogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;

@Aspect//定义切面
@Component
public class LogAspect {

@Resource
private LogService logService;

//定义切入点
@Pointcut("@annotation(com.istuadmission.common.annotation.Log)")
public void logPointCut() {
}

//添加环绕通知@Around
@Around("logPointCut()")
public void around(ProceedingJoinPoint point) throws Throwable {
//先执行切点方法,再执行切面方法,放到最后就是先执行切面,再执行切点
Object result = point.proceed();
//获得切点的类名
String targetName = joinPoint.getTarget().getClass().getName();
//获得切点的方法名
String methodName = joinPoint.getSignature().getName();
//获取切点方法的所有入参
Object[] args = point.getArgs();
//通过Method对象获取切点方法的关键信息,类,包
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Log log = method.getAnnotation(Log.class);
if (log != null) {
logService.insert(log.value(),log.name());
}
}
}
如果对您有帮助,可以打赏呦!