一、注解的作用
java的反射技术很强大,可以在程序运行时动态获取类信息、字段、方法等,再执行各种想要的操作。
但是,有时我们还希望对一些信息提前描述,以便在使用反射时,区别性地进行处理,使得处理更加灵活,这时候就需要用到注解了。
二、如何自定义注解
- 语法: 修饰符 + @interface +注解名
- 成员变量的类型会有限制,仅限以下:基本数据类型、String、Class、enum、Annotation 以及它们对应的数组。
- 需要4个元注解,分别是
@Target —— 指定此注解使用的对象,包括类、字段、方法等
@Retention —— 指定保存的周期,包括源代码、运行时等
@Documented —— 此注解可用于javadoc生成文档
@Inherited —— 解释挺拗口,个人理解是,带有这个元注解的注解,它的属性很“霸道”,不仅修饰直接修饰的类,还会修饰它的子类
上面三个注解比较好理解,就最后一个不太懂,因此用了一个例子执行了一下。
// 自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyClassAnno {
String name() default "";
}
// 被自定义注解修饰的类
@MyClassAnno
public class BeAnnoed {
}
// 继承被注解修饰的类
public class BeAnnoedSon extends BeAnnoed{
}
// 测试类
public class Client {
public static void main(String[] args) {
Annotation[] annotations = BeAnnoedSon.class.getAnnotations();
for(Annotation annotation: annotations){
System.out.println("BeAnnoedSon注解为:"+annotation.annotationType());
}
}
}
当不使用@Inherited时, 结果毛都没有
当自定义注解使用@Inherited修饰,可以看到,子类已经被自定义注解修饰。因为子类有这个注解,所以子类的子类也会被此注解修饰,“子子孙孙无穷匮也”
三、 使用场景
如果注解没有成员变量,作用会相对比较局限,只能用来做标记。但如果加上成员变量,我们可以做更多的事情。比如可以自定义日志注解,配合切面,这样就可以在任何想要加日志处理的地方,灵活地配合注解参数,进行处理。
(偷个懒,以下代码摘自某开源项目,不得不感叹一句,人家写的代码就是好看呀)
1.先自定义一个日志注解
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
/**
* 模块
*/
public String title() default "";
/**
* 功能
*/
public BusinessType businessType() default BusinessType.OTHER;
/**
* 操作人类别
*/
public OperatorType operatorType() default OperatorType.MANAGE;
/**
* 是否保存请求的参数
*/
public boolean isSaveRequestData() default true;
}
2.比如在一个保存字典值的方法处记录日志
@Log(title = "字典数据", businessType = BusinessType.INSERT)
@RequiresPermissions("system:dict:add")
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(@Validated SysDictData dict)
{
3.编写切面类
// 配置织入点
@Pointcut("@annotation(com.**.common.annotation.Log)")
public void logPointCut()
{
}
// 比如记录成功的日志
@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
{
handleLog(joinPoint, null, jsonResult);
}
// handleLog中通过切点,获取注解
protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)
{
try
{
// 获得注解
Log controllerLog = getAnnotationLog(joinPoint);
}
}