0%

Spring-Annotation-Aop

刚才学习SpringAop的时候觉得好强大

演示代码

演示效果

  • 启动代码
1
2
3
  docker-run curl http://localhost:9003/aop/

{"code":"200"}%
  • Console
1
2
[XNIO-1 task-1] [LogsAspect.java : 50]   annotationAop value index 
[XNIO-1 task-1] [LogsAspect.java : 50] annotationAop value index

Spring Aop

AOP(Aspect-Oriented Programming:⾯向切⾯编程)能够将那些与业务⽆关,却为业务模块所共同调⽤的逻辑或责任(例如事务处理、⽇志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

  • Spring Aop是运行时增强。
  • Cglib Aop是编译器增强。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

/**
* 是否要创建基于子类 (CGLIB) 的代理,而不是创建标准的基于 Java 接口的代理。 默认值为false 。
*/
boolean proxyTargetClass() default false;

/**
* org.springframework.aop.framework.AopContext类进行检索。 默认关闭
*/
boolean exposeProxy() default false;

}

Spring注解

1
2
3
4
5
6
7
@Aspect //定义切面:切面由切点和增强(引介)组成(可以包含多个切点和多个增强),它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的链接点中。
@Pointcut //定义切点:切点是一组连接点的集合。AOP通过“切点”定位特定的连接点。通过数据库查询的概念来理解切点和连接点的关系再适合不过了:连接点相当于数据库中的记录,而切点相当于查询条件。
@Before // 在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可。
@AfterReturning //在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值。
@Afterthrowing //主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名来访问目标方法中所抛出的异常对象。
@After //在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式。
@Around //环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint。

pom依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

代码

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

package cn.z201.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* @author z201.coding@gmail.com
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationAop {

String value();

}


package cn.z201.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
* @author z201.coding@gmail.com
**/
@Component
@Aspect
@Slf4j
public class LogsAspect {

@Pointcut("@annotation(cn.z201.aop.AnnotationAop)")
private void cutMethod() {

}

/**
* 异常通知:目标方法抛出异常时执行
*/
@AfterThrowing("cutMethod()")
public void afterThrowing(JoinPoint joinPoint) {
log.info("after throwing");
}

/**
* 环绕通知:灵活自由的在目标方法中切入代码
*/
@Before("cutMethod()")
public void before(JoinPoint joinPoint) throws Throwable {
// 获取目标方法的名称
String methodName = joinPoint.getSignature().getName();
// 获取方法传入参数
Object[] params = joinPoint.getArgs();
if (null != params && params.length != 0) {
log.info(" method name {} args {}", methodName, params[0]);
}
// 执行源方法
AnnotationAop annotationAop = getDeclaredAnnotation(joinPoint);
if (null != annotationAop) {
log.info(" annotationAop value {} ", annotationAop.value());
}
}

/**
* 获取方法中声明的注解
*
* @param joinPoint
* @return
* @throws NoSuchMethodException
*/
public AnnotationAop getDeclaredAnnotation(JoinPoint joinPoint) throws NoSuchMethodException {
// 获取方法名
String methodName = joinPoint.getSignature().getName();
// 反射获取目标类
Class<?> targetClass = joinPoint.getTarget().getClass();
// 拿到方法对应的参数类型
Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
// 根据类、方法、参数类型(重载)获取到方法的具体信息
Method objMethod = targetClass.getMethod(methodName, parameterTypes);
// 拿到方法定义的注解信息
AnnotationAop annotation = objMethod.getDeclaredAnnotation(AnnotationAop.class);
// 返回
return annotation;
}

}


package cn.z201.aop;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
* @author z201.coding@gmail.com
**/
@RestController
public class AppApplicationController {

@RequestMapping(value = "")
@AnnotationAop(value = "index")
public Object index() {
Map<String, Object> data = new HashMap<>();
data.put("code", "200");
return data;
}
}

END