刚才学习SpringAop的时候觉得好强大
演示代码
演示效果
- 启动代码
docker-run curl http://localhost:9003/aop/
{"code":"200"}%
- Console
[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是编译器增强。
@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注解
@Aspect //定义切面:切面由切点和增强(引介)组成(可以包含多个切点和多个增强),它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的链接点中。
@Pointcut //定义切点:切点是一组连接点的集合。AOP通过“切点”定位特定的连接点。通过数据库查询的概念来理解切点和连接点的关系再适合不过了:连接点相当于数据库中的记录,而切点相当于查询条件。
@Before // 在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可。
@AfterReturning //在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值。
@Afterthrowing //主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名来访问目标方法中所抛出的异常对象。
@After //在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式。
@Around //环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint。
pom依赖
<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>
代码
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;
}
}