使用注解实现AOP功能

时间:2021-12-19 20:34:41

最近做项目,需要使用注解绑定一个切面去实现一个需求,讲真的本人菜鸟,可能之前就没有写多少切面,更不要说用注解的形式去实现了,现学现卖,希望写点东西,随着理解的深入可能我会修改这篇博客。闲话少说,首先是些注解的编写:
一.注解(Annotation):
编写注解必须要了解元注解的概念,其实就是定义注解的注解,meta-Annotation,Java1.5以后一共定义了四个元注解,
    1.@Target,
    2.@Retention,
    3.@Documented,
    4.@Inherited
1.@Target:这个元注解比较常用,作用是定义注解可以用在什么地方。
而ElementType是定义其作用范围的参数, 取值(ElementType)有:

    1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

@Target(ElementType.METHOD) //作用于方法
@Target(ElementType.TYPE) //作用于类
@Target({ElementType.METHOD,ElementType.TYPE})//或者作用于方法和类

2.@Retention:这个注解也是比较常用的注解,
这是一个描述什么时候有效的注解,有三中描述参数:
    1.SOURCE:在源文件中有效
    2.CLASS:在class文件中有效
    3.RUNTIME:在运行时有效
前两个比较特殊,也不常见,我们常常使用的这个RUNTIME,
还有@Documented和@Inherited这两个参数,比较不常用,基本我这里用不到,感兴趣,大家可以自己了解一下。
这里注意,我们自己定义的注解自动继承,java.lang.annotation.Annotation接口,
例:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SystemLog{ //SystemLog是注解名称
String module() default "默认模块";
}

好了,让我们看看如何让注解和切面绑定到一起,

    package com.demo;
@Aspect
@Component //这两个注解必须要有,项目跑起来时候,这两个注解会被扫描到,告诉容器这是一个切面 组件
public class LogAspect {

@Around("@annotation(com.demo.SystemLog)") //没错 这里是重点
public void afterLogService(JoinPoint point){
//获得当前访问的类
Class<?> className = point.getTarget().getClass();
//获得当前的方法名
String methodName = point.getSignature().getName();
//得到方法的参数类型
Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
//默认的
String module = "默认的模块";
try {
//得到访问的方法对象
Method method = className.getMethod(methodName,argClass);
//如果这个方法上有我的注解
if (method.isAnnotationPresent(SystemLog.class)) {
//那就获取我的这个注解
SystemLog log = method.getAnnotation(SystemLog.class);
module = log.module();
logService.insertLog(module,operation);
}
}

}

这里基本就处理完毕了,你可以在省略部分写你自己的业务逻辑了,使用的时候在你想切的方法或者类上,写上这个注解就可以了。
这里简单的说一下JoinPoint ,切入点这里面有提供了不少的方法,包含可以点击进去看一下,源码注解写的很详细,感兴趣可以看一下。这里比较常用的可能是

Object getThis(); 
Object getTarget(); //返回当前执行的对象
Object[] getArgs(); //返回当前执行的数组对象