一、前言
这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战 。听说有人不会自定义注解?不会写还不会 Copy ? ☞ 【ExcelUtil】二次封装,注解驱动,用起来不要太舒服! - 掘金 (juejin.cn) ,好了不开玩笑了,今天帅小伙就带着大伙梳理一遍注解也就是
@interface
正确的打开方式,除此之外,结合AOP
切面统一打印出入参日志,对于每个访问注解绑定的接口方法的请求都一目了然,不仅方便接口的调试,还能给你一个优雅、整齐且大方的控制台日志记录。
二、效果演示
2.1 访问接口
2.2 控制台日志输出
三、如何设计一个注解
3.1 概念
知其然,要知其所以然,所以我们先来康康官方对注解的描述是什么:
An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.
翻译过来的大意是:
注释是一种元数据的形式,可以添加到Java源代码中。类,方法,变量,参数和包可以注释。注释对他们注释的代码的操作没有直接影响。
综上来说,注解其实相当于 Java
的一种特殊的数据类型,也可以把它当做一个可以自定义的标记去理解,和类、接口、枚举类似,可以使用在很多不同的地方并且对原有的操作代码没有任何影响,仅做中间收集和处理。
3.2 小试牛刀
1 | java复制代码 |
说明(从上往下):
- 使用该注解在程序运行时被
JVM
保留,并且被编译器记录到class
文件中,所以能够通过Java
反射机制读取到注解中的属性等 - 该注解仅能使用在字段上,不能用在类、方法、变量上
- 该注解有两个属性,一个是
name
另一个是sort
属性,属性?你可能就会问了后边不是带一对圆括号嘛,不应该是方法吗?看似接口中定义的抽象方法,实则看没看到default
关键字,官方管定义在注解内的是 注解类型元素 ,不过我习惯管它们叫属性,因为在使用注解时,总是以键值对的形式传参 - 访问修饰符必须为
public
,不写默认为public
- 圆括号不是定义方法参数的地方,也不能在括号中定义任何参数,这仅仅是一个特殊的写法罢了
default
表示未设置该属性时的默认值,值需和类型保持一致- 如果没有
default
默认值,表示该类型元素必须在后续赋值
3.3 注解注解的注解类
此外,在 JDK
中提供了 4 个标准的用来对注解类型进行注解的注解类(元注解),分别是:
@Target
是专门用来限定某个自定义注解能够被应用在哪些Java
元素上
1 | java复制代码 |
@Retention
该注解有 “保留”、“保持” 之义,用来定义注解的留存策略,可指定的留存策略只有 3 个:
1 | java复制代码 |
一般使用无特殊需要,使用 RetentionPolicy.RUNTIME
就够了。
@Documented
是被用来指定自定义注解是否能随着被定义的Java
文件生成到JavaDoc
文档当中@Inherited
是指定某个自定义注解如果写在了父类的声明部分,那么子类的声明部分也能自动拥有该注解
注意:@Inherited
注解只对那些 @Target
被定义为 ElementType.TYPE
的自定义注解起作用。
3.4 使用流程
四、代码实现
4.1 第一步
编写设计注解:
1 | java复制代码 |
这步没什么好讲的,上面的概念理解掌握了,轻轻松松写出这个注解应该是没有什么问题!
4.2 第二步
使用切面注解进行标记,因为是对请求相关的日志打印,所以我们随便写一个控制层接口方法进行测试:
1 | java复制代码 |
4.3 第三步
最后一步也是最关键的一步,在运行时解析注解执行切面操作,所以对应地写一个切面类:
新建切面类后,考虑到日志的打印,这段代码必不可少:
1 | java复制代码 |
@Aspect
和 @Component
注解必不可少,@Component
大伙应该在熟悉不过了,将该类注入到 Spring
容器中;而另一个 @Aspect
注解的作用是把当前类标识成一个切面供容器去读取。
注意: 打印日志推荐使用的包是 slf4j.Logger
。
1 | java复制代码 |
配置织入点,切到所有被 @MyAnnotation
注解修饰的方法,不需要再方法体内编写实际的代码!
1 | java复制代码 |
pjp
连接点对象,JoinPoint
的子接口,可以获取当前切入的方法的参数、代理类等信息,因此可以记录一些信息、验证一些信息等,它有两个重要的方法:
Object proceed() throws Throwable
执行目标方法Object proceed(Object[] var1) throws Throwable
传入的新的参数去执行目标方法
整个代码都有注解,这里就不赘述代码逻辑了!
4.4 扩展
除了上面用到的 @PointCut
和 @Around
注解,还有另外 4 个使用 AOP
常用的注解:
@Before
:前置增强,在切点之前织入相关代码@After
:final
增强,不管是抛出异常或者正常退出都会执行@AfterReturning
:后置增强,方法正常退出时执行@AfterThrowing
:异常抛出增强,切点方法抛出异常时执行
执行顺序:@Around
=> @Before
=> 执行接口方法中的代码 => @After
=> @AfterReturning
有兴趣的同学,可以环绕增强中的代码拆分到前置和后置增强中,以便更好地理解这四个常用注解使用场景! (๑•̀ㅂ•́)و✧
结尾
撰文不易,欢迎大家点赞、评论,你的关注、点赞是我坚持的不懈动力,感谢大家能够看到这里!Peace & Love。
本文转载自: 掘金