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