Spring-AOP
Spring AOP
基于动态代理实现(动态生成插入方法invoke)
术语
连接点(Join point): 能够拦截(插入方法)的地方
切点(Poincut): 具体定位的连接点
增强/通知(Advice):表示添加到切点的一段逻辑代码,并定位连接点的方位信息。
Spring AOP提供了5种Advice类型给我们:前置
@Before
、后置@After
、返回@AfterReturning
、异常@AfterThrowing
、环绕@Around
给我们使用!织入(Weaving):将
增强/通知
添加到目标类的具体连接点上的过程引入/引介(Introduction):允许我们向现有的类添加新方法或属性。是一种特殊的增强!
切面(Aspect):切面由切点和
增强/通知
组成,它既包括了横切逻辑的定义、也包括了连接点的定义。
切入点定义
execution
表达式eg:
@Pointcut("execution(public * com.exxk.aop..*Controller.*(..))")
*
代表任意值aop..
表示aop包下面的任何子包和自己(..)
表示任何参数@annotation
注解eg:
@annotation(com.willson.common.annotation.Log)
注解类名字解释
@Target
:
说明了Annotation所修饰的对象范围,eg@Target({ ElementType.PARAMETER, ElementType.METHOD })
其中ElementType
的取值有
CONSTRUCTOR
:用于描述构造器FIELD
:用于描述域LOCAL_VARIABLE
:用于描述局部变量METHOD
:用于描述方法PACKAGE
:用于描述包PARAMETER
:用于描述参数TYPE
:用于描述类、接口(包括注解类型) 或enum声明
@Retention
定义了该Annotation被保留的时间长短,eg@Retention(RetentionPolicy.RUNTIME)
,其中Retention
取值有
SOURCE
:在源文件中有效(即源文件保留)CLASS
:在class文件中有效(即class保留)RUNTIME
:在运行时有效(即运行时保留)
@Documented
用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
springboot aop log实战
引入依赖
org.springframework.boot:spring-boot-starter-aop
定义一个接口作为测试
1
2
3
4
5
6
7
8
9
10
11
12package com.exxk.aop;
public class AopController {
private Logger logger=Logger.getLogger(String.valueOf(getClass()));
//@Log(tag = "我是注解")
public String aop(){
logger.info("业务代码执行中...");
return "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
public class LogAspect {
private Logger logger=Logger.getLogger(String.valueOf(getClass()));
//定义切入点,切入点定义注意,某些类不能动态代理
public void pointCut(){}
//切入点前插入的内容
public void doBefore(JoinPoint joinPoint){
logger.info("切入点前执行的内容:");
ServletRequestAttributes attributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request=attributes.getRequest();
logger.info("URL:"+request.getRequestURL().toString());
}
}
public void doAfterReturning(Object ret){
logger.info("切点运行完之后执行的内容:");
logger.info("response:"+ret);
}
}调用接口之后打印日志
1
2
3
4
5com.exxk.aop.LogAspect : 切入点前执行的内容:
com.exxk.aop.LogAspect : URL:http://127.0.0.1:8080/aop/test
com.exxk.aop.AopController : 业务代码执行中...
com.exxk.aop.LogAspect : 切点运行完之后执行的内容:
com.exxk.aop.LogAspect : response返回:aop 测试添加自定义注解类
1
2
3
4
5
public Log {
String tag() default "";
}如果要使用注解格式修改切入点为注解
1
2
3
4
5//定义切入点
//@Pointcut("execution(public * com.exxk.aop..*Controller.*(..))")
//@Pointcut("execution(public * com.exxk.aop.AopController.aop())")
public void pointCut(){}在接口上添加注解
@Log(tag = "我是注解")
在切入点,eg:
doBefore
添加获取注解的内容1
2
3
4
5
6//获取注解
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
Log log= method.getAnnotation(Log.class);
logger.info("获取注解内容:"+log.tag());最后访问测试,打印日志如下
1
2
3
4
5
6com.exxk.aop.LogAspect : 切入点前执行的内容:
com.exxk.aop.LogAspect : URL:http://127.0.0.1:8080/aop/test
com.exxk.aop.LogAspect : 获取注解内容:我是注解
com.exxk.aop.AopController : 业务代码执行中...
com.exxk.aop.LogAspect : 切点运行完之后执行的内容:
com.exxk.aop.LogAspect : response返回:aop 测试
优化注解
CGLIB实现AOP在
application.properties
配置文件添加1
2spring.aop.auto=true
spring.aop.proxy-target-class=false