写点什么

Java 自定义注解(二)

发布于: 3 小时前
Java 自定义注解(二)

系列文章:

Java 自定义注解


一 简介

上一篇,我们已经介绍了 Java 注解的概念,基本架构,和几个主干类,以及定义注解方法。本篇中,我们降给出一个注解定义的示例,作为实战入门的初步内容。

二 相关接口 &基本注解

除了五个基本注解,还有几个是本篇的基础,需要先做了解。

2.1 @interface

当我们用 @interface 来定义注解时,意味着它实现了 java.lang.annotation.Annotation 接口,即该注解就是一个 Annotation。定义 Annotation 时,@interface 是必须的。有一点需要注意:它和我们通常的 implemented 实现接口的方法不同。Annotation 接口的实现细节都由编译器完成。通过 @interface 定义注解后,该注解不能继承其他的注解或接口。

2.2 @Documented       

类和方法的 Annotation 在缺省情况下是不出现在 javadoc 中的。如果我们想让注解也出现在 javadoc 中,就必须使用 @Documented 注解来修饰该 Annotation。       

定义 Annotation 时,@Documented 不是必须的;若没有定义,则 Annotation 不会出现在 javadoc 中。

2.3 @Target

ElementType 是 Annotation 的类型属性。而 @Target 的作用,就是来指定 Annotation 的类型属性。      @Target(ElementType.TYPE) 是指该 Annotation 的类型是 ElementType.TYPE。表示我们的注解,是来修饰“类、接口(包括注释类型)或枚举声明”的注解。      

定义 Annotation 时,@Target 也不是必须的。如果有 @Target,那么这个 Annotation 只能用于它所指定的位置;若没有 @Target,则该 Annotation 可以用于任何地方。

2.4 @Retention

RetentionPolicy 是 Annotation 的策略属性,@Retention 的作用就是指定 Annotation 的策略属性。      @Retention(RetentionPolicy.RUNTIME) ,是指定该 Annotation 的策略是 RetentionPolicy.RUNTIME。这表示编译器会将该 Annotation 信息保留在.class 文件中,并且能被虚拟机读取。      

定义注解时,@Retention 也非必须。如果没有设置 @Retention,那么默认是 RetentionPolicy.CLASS。

2.5 @Inherited

这个注解所标注的 Annotation 具有继承性。例如我们定义了某个注解,名为 Annotation1,并且被标注为 @Inherited。某个类 ClassB 使用了 Annotation1,则 ClassB 具有了“具有了注解 Annotation1”;现在,Sub 继承了 ClassB,由于 Annotation1 是 @Inherited 的(具有继承性),所以,Sub 也“具有了注解 Annotation1”。

三 注解作用

说了这么多,似乎漏掉了一项重要内容,注解到底有哪些作用?简单来说,Annotation 是一个辅助类,它广泛用于 Junit、Struts、Spring 等工具和框架。

如果简单一点来做个整理,那么其作用包括以下几点:

  1. 编译检查:@SuppressWarnings, @Deprecated 和 @Override 都具有编译检查作用

  2. 反射中使用 Annotation;

  3. 根据 Annotation 生成帮助文档;如上面所说,注解加上 @Documented 标签,能使该 Annotation 标签出现在 javadoc 中;

  4. 方便查看代码;通过 @Override, @Deprecated 等注解,我们能很方便的了解程序的大致结构。

四 示例

本节,我们将通过 Springboot 下定义一个注解来进行练习。

4.1 依赖引入

主要是引入 spring-boot-starter-aop。

<dependencies>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-web</artifactId>    </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
</dependencies>
复制代码

如果有发生注解不生效的情况,可能还需要增加 aspectjweaver 和 aspectjrt。

<dependency>    <groupId>org.aspectj</groupId>    <artifactId>aspectjweaver</artifactId>    <version>1.9.4</version></dependency><dependency>    <groupId>org.aspectj</groupId>    <artifactId>aspectjrt</artifactId>    <version>1.8.9</version></dependency>
复制代码

4.2 注解定义

用我们常说的示例,就是记录日志,可以定义注解如下:

package com.flamingskys.spring.annotation;
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import java.lang.annotation.Documented;
/** * @Author : flamingskys * @CreateTime : 2021/11/2 * @Description : **/
@Documented@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface LogTrack { String value() default "logTracking";}
复制代码

4.3 Aspect

package com.flamingskys.spring.annotation;
import com.flamingskys.commont.util.IpUtil;import com.flamingskys.commont.util.JsonUtil;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.*;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.ArrayList;import java.util.Arrays;import java.util.Date;import java.util.List;
/** * @Author : flamingskys * @CreateTime : 2021/11/2 * @Description : **/
@Component@Aspectpublic class LogTrackAspect { private static final Logger log = LoggerFactory.getLogger(LogTrackAspect.class); //切点,路径一定要写正确了 @Pointcut(value = "@annotation(com.flamingskys.spring.annotation.LogTrack)") public void access() {
}
//进来切点世界,先经过的第一个站 @Before("access()") public void doBefore(JoinPoint joinPoint) throws Throwable { System.out.println("-aop 日志记录启动-" + new Date()); } //环绕增强,是在before前就会触发 @Around("@annotation(logTrack)") public Object around(ProceedingJoinPoint pjp, LogTrack logTrack) throws Throwable { System.out.println("-aop 日志环绕阶段-" + new Date()); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest();
// GET 请求其实可以从request里获取出参数// Map<String,String[]> map=request.getParameterMap();// System.out.println("获取参数:"+map.get("username")[0])
String url = request.getRequestURL().toString(); String ip = IpUtil.getIpAddr(request); String logTrackValue = logTrack.value(); Object[] pipArrary = pjp.getArgs(); if (pipArrary.length>1){ //多参,不是Map/JsonObject方式 List<Object> argList = new ArrayList<>(); for (Object arg : pjp.getArgs()) { // request/response无法使用toJSON if (arg instanceof HttpServletRequest) { argList.add("request"); } else if (arg instanceof HttpServletResponse) { argList.add("response"); } else { argList.add(JsonUtil.objToStr(arg)); } } Signature signature = pjp.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; // 参数名数组 String[] parameterNames = ((MethodSignature) signature).getParameterNames(); System.out.println("参数名数组:"+new ArrayList(Arrays.asList(parameterNames))); System.out.println("参数是:"+argList.toString()); System.out.println("logTrackValue:"+logTrackValue); System.out.println("url:"+url); System.out.println("ip:"+ip); return pjp.proceed();
}
Object param = pipArrary[0]; System.out.println("logTrackValue:"+logTrackValue); System.out.println("url:"+url); System.out.println("ip:"+ip); System.out.println("param:"+param.toString()); return pjp.proceed();
}

//方法正常运行结束后 @After("access()") public void after(JoinPoint joinPoint) { System.out.println("-aop 日志记录结束-" + new Date()); }
}
复制代码


发布于: 3 小时前阅读数: 4
用户头像

磨炼中成长,痛苦中前行 2017.10.22 加入

微信公众号【程序员架构进阶】。多年项目实践,架构设计经验。曲折中向前,分享经验和教训

评论

发布
暂无评论
Java 自定义注解(二)