⽤AOP拦截⾃定义注解并获取注解属性与上下⽂参数(基于Springboot框架)⽬录
AOP可以⽤于⽇志的设计,这样话就少不了要获取上下⽂的信息,博主在设计⽇志模块时考虑了⼀下此法,整理了⼀下如何⽤AOP来拦截你⾃定义的注解。
⾃定义注解
⾸先先⾃定义⼀个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Axin {
/**
* 所属模块
* @return
*/
String module() default "⽇志模块";
/**
* 动作描述
* @return
*/
String desc() default "⽆动作";
}
@Documented:注解表明制作javadoc时,是否将注解信息加⼊⽂档。如果注解在声明时使⽤了@Documented,则在制作javadoc时注解信息会加⼊javadoc。
@Target:⽤来说明该注解可以被声明在那些元素之前
@Target(ElementType.TYPE) //接⼝、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //⽅法
@Target(ElementType.PARAMETER) //⽅法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
@Retention:⽤来说明该注解类的⽣命周期。
@Retention(RetentionPolicy.SOURCE) —— 这种类型的Annotations只在源代码级别保留,编译时就会被忽略
@Retention(RetentionPolicy.CLASS) —— 这种类型的Annotations编译时被保留,在class⽂件中存在,但JVM将会忽略
@Retention(RetentionPolicy.RUNTIME) —— 这种类型的Annotations将被JVM保留,所以他们能在运⾏时被JVM或其他使⽤反射机制的代码所读取和使⽤.
定义切⾯
/**
* @author Axin
*/
@Aspect
@Component
public class AxinAspect {
/**
* 这⾥定义了⼀个总的匹配规则,以后拦截的时候直接拦截log()⽅法即可,⽆须去重复写execution表达式
*/
@Pointcut("@annotation(Axin)")
public void log() {
}
@Before("log()&&@annotation(axin)")
public void doBefore(JoinPoint joinPoint,Axin axin) {
System.out.println("******拦截前的逻辑******");
System.out.println("⽬标⽅法名为:" + Signature().getName());
System.out.println("⽬标⽅法所属类的简单类名:" + Signature().getDeclaringType().getSimpleName());
System.out.println("⽬标⽅法所属类的类名:" + Signature().getDeclaringTypeName());
System.out.println("⽬标⽅法声明类型:" + Signature().getModifiers()));
//获取传⼊⽬标⽅法的参数
Object[] args = Args();
for (int i = 0; i < args.length; i++) {
System.out.println("第" + (i + 1) + "个参数为:" + args[i]);
}
System.out.println("被代理的对象:" + Target());
System.out.println("代理对象⾃⼰:" + This());
System.out.println("拦截的注解的参数:");
System.out.dule());
System.out.println(axin.desc());
}
@Around("log()&&@annotation(axin)")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint,Axin axin) throws Throwable {
System.out.println("环绕通知:");
System.out.dule());
System.out.println(axin.desc());
Object result = null;
result = proceedingJoinPoint.proceed();
return result;
}
@After("log()")
public void doAfter() {
System.out.println("******拦截后的逻辑******");
}
}
springboot原理pdf匹配规则:
//匹配AOP对象的⽬标对象为指定类型的⽅法,即DemoDao的aop的代理对象
@Pointcut("this(com.hhu.DemaoDao)")
public void thisDemo() {
...
}
通知类别:
前置通知(Before advice)- 在⽬标⽅便调⽤前执⾏通知
后置通知(After advice)- 在⽬标⽅法完成后执⾏通知
返回通知(After returning advice)- 在⽬标⽅法执⾏成功后,调⽤通知
异常通知(After throwing advice)- 在⽬标⽅法抛出异常后,执⾏通知
环绕通知(Around advice)- 在⽬标⽅法调⽤前后均可执⾏⾃定义逻辑
获取上下⽂信息JoinPoint
JoinPoint对象封装了SpringAop中切⾯⽅法的信息,在切⾯⽅法中添加JoinPoint参数,就可以获取到封装了该⽅法信息的JoinPoint对象. 注意:这⽤于⾮环绕通知
⽅法名功能
Signature getSignature();获取封装了署名信息的对象,在该对象中可以获取到⽬标⽅法名,所属类的Class等信息
Object[] getArgs();获取传⼊⽬标⽅法的参数对象
Object getTarget();获取被代理的对象
Object getThis();获取代理对象
⽅法使⽤模板:
public void doBefore(JoinPoint joinPoint) {
System.out.println("******拦截前的逻辑******");
System.out.println("⽬标⽅法名为:" + Signature().getName());
System.out.println("⽬标⽅法所属类的简单类名:" + Signature().getDeclaringType().getSimpleName());
System.out.println("⽬标⽅法所属类的类名:" + Signature().getDeclaringTypeName());
System.out.println("⽬标⽅法声明类型:" + Signature().getModifiers()));
//获取传⼊⽬标⽅法的参数
Object[] args = Args();
for (int i = 0; i < args.length; i++) {
System.out.println("第" + (i + 1) + "个参数为:" + args[i]);
}
System.out.println("被代理的对象:" + Target());
System.out.println("代理对象⾃⼰:" + This());
}
ProceedingJoinPoint
ProceedingJoinPoint对象是JoinPoint的⼦接⼝,该对象只⽤在@Around的切⾯⽅法中
⽅法名功能
Object proceed() throws Throwable执⾏⽬标⽅法
Object proceed(Object[] var1) throws Throwable传⼊的新的参数去执⾏⽬标⽅法
定义测试⽅法
/
/Service接⼝
public interface AxinService {
String axinRun(String arg1, User user);
}
//实现类
/**
* @author Axin
*/
@Component
public class AxinServiceImpl implements AxinService {
@Axin(module = "print",desc = "打印")
@Override
public String axinRun(String arg1, User user) {
String res = arg1 + Name() + Age();
return res;
}
public String axinRun(String arg1, Person person) {
String res = arg1 + Name() + Age();
return res;
}
}
//控制类
/
**
* @author Axin
*/
@RestController
public class HelloController {
@Autowired
AxinService axinService;
@RequestMapping("/hello")
public String hello() {
User user = new User();
user.setAge(10);
user.setName("张三");
String res = axinService.axinRun("Test:", user);
return "Hello Spring Boot!<br>"+res;
}
}
测试结果
环绕通知:
print
打印
******拦截前的逻辑******
⽬标⽅法名为:axinRun
⽬标⽅法所属类的简单类名:AxinService
⽬标⽅法所属类的类名:com.axin.springboot.service.AxinService
⽬标⽅法声明类型:public abstract
第1个参数为:Test:
第2个参数为:User(id=null, name=张三, age=10, date=null)
被代理的对象:com.axin.springboot.service.AxinServiceImpl@ac2ddcc
代理对象⾃⼰:com.axin.springboot.service.AxinServiceImpl@ac2ddcc
拦截的注解的参数:
print
打印
******拦截后的逻辑******
⼩结
通过上述的代码演⽰,我们可以⾃定义⼀个注解,然后配置切⾯来拦截有注解的⽅法,同时也可以获得⽅法传⼊的参数来完成你的业务需求。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论