JAVA注解处理
<h1 id="元注解">元注解</h1><h2 id="jdk元注解">JDK元注解</h2>
<h3 id="target">@Target</h3>
<p>指定注解可以应用的目标(如类、方法、字段等)。</p>
<p><strong>常用取值</strong>(<code>ElementType</code> 枚举):</p>
<ul>
<li><code>TYPE</code>:类、接口、枚举</li>
<li><code>FIELD</code>:字段</li>
<li><code>METHOD</code>:方法</li>
<li><code>PARAMETER</code>:方法参数</li>
<li><code>CONSTRUCTOR</code>:构造函数</li>
<li><code>ANNOTATION_TYPE</code>:注解(用于定义元注解)</li>
</ul>
<p><strong>示例</strong>:</p>
<pre><code class="language-java">@Target(ElementType.METHOD) // 只能用在方法上
public @interface MyAnnotation {}
</code></pre>
<hr>
<h3 id="retention">@Retention</h3>
<p>指定注解的生命周期(源码、编译期、运行时)。<br>
<strong>常用取值</strong>(<code>RetentionPolicy</code> 枚举):</p>
<ul>
<li><code>SOURCE</code>:仅源码保留(如 <code>@Override</code>,编译后丢弃)</li>
<li><code>CLASS</code>:编译期保留(默认,但运行时不可见)</li>
<li><code>RUNTIME</code>:运行时保留(可通过反射读取)</li>
</ul>
<p><strong>示例</strong>:</p>
<pre><code class="language-java">@Retention(RetentionPolicy.RUNTIME) // 运行时可通过反射获取
public @interface MyAnnotation {}
</code></pre>
<hr>
<h3 id="documented">@Documented</h3>
<p>标记注解是否包含在 JavaDoc 中。<br>
<strong>示例</strong>:</p>
<pre><code class="language-java">@Documented // 生成的 JavaDoc 会显示此注解
public @interface MyAnnotation {}
</code></pre>
<hr>
<h3 id="inherited">@Inherited</h3>
<p>允许子类继承父类的注解(仅对 <code>@Target(ElementType.TYPE)</code> 有效)。<br>
<strong>示例</strong>:</p>
<pre><code class="language-java">@Inherited // 子类会继承父类的此注解
public @interface MyAnnotation {}
@MyAnnotation
class Parent {}
class Child extends Parent {} // Child 也拥有 @MyAnnotation
</code></pre>
<hr>
<h3 id="repeatablejava-8">@Repeatable(Java 8+)</h3>
<p>允许同一注解在同一个位置重复使用。<br>
<strong>示例</strong>:</p>
<pre><code class="language-java">@Repeatable(MyAnnotations.class) // 可重复使用
public @interface MyAnnotation {
String value();
}
@MyAnnotation("A")
@MyAnnotation("B") // 合法
class MyClass {}
</code></pre>
<hr>
<h3 id="nativejava-8">@Native(Java 8+)</h3>
<p>用于指示某个字段可能被本地代码(如 JNI)引用。</p>
<p><strong>用法</strong>:</p>
<ul>
<li>不强制约束:@Native 仅是一个标记,不改变字段的访问权限或行为。</li>
<li>非运行时注解:编译后会被丢弃,无法通过反射获取。</li>
<li>仅限字段:不能用于方法、类或其他目标。</li>
</ul>
<p><strong>示例</strong>:</p>
<pre><code class="language-java">public class NativeExample {
@Native
public static final int BUFFER_SIZE = 1024; // 可能被本地代码使用
static {
System.loadLibrary("nativeLib"); // 加载本地库
}
public native void nativeMethod(); // 本地方法声明
}
</code></pre>
<hr>
<h2 id="spring-扩展的元注解">Spring 扩展的元注解</h2>
<h3 id="aliasfor">@AliasFor</h3>
<p>定义注解属性的别名(如 <code>@RequestMapping.path</code> 和 <code>@RequestMapping.value</code>)。<br>
<strong>示例</strong>:</p>
<pre><code class="language-java">public @interface MyAnnotation {
@AliasFor("path") // value 和 path 是别名
String value() default "";
@AliasFor("value")
String path() default "";
}
</code></pre>
<h3 id="component间接元注解">@Component(间接元注解)</h3>
<p>标记一个类为 Spring 组件(<code>@Service</code>、<code>@Controller</code> 等均元标注了 <code>@Component</code>)。<br>
<strong>示例</strong>:</p>
<pre><code class="language-java">@Component // @Service 元标注了 @Component
public @interface Service {}
</code></pre>
<h3 id="indexedspring-5">@Indexed(Spring 5+)</h3>
<p>加速类路径扫描,提升启动性能。<br>
<strong>示例</strong>:</p>
<pre><code class="language-java">@Indexed // 标记为可索引的组件
@Component
public class MyComponent {}
</code></pre>
<h1 id="spring工具类">Spring工具类</h1>
<h2 id="annotatedelementutils">AnnotatedElementUtils</h2>
<h3 id="findmergedannotationannotatedelement-class">findMergedAnnotation(AnnotatedElement, Class)</h3>
<p>这个方法完全支持<code>@AliasFor</code>。例如<code>@PostMapping</code>中嵌套了<code>@RequestMapping</code>注解,并且各属性依赖于它的属性。通过以下代码可以获取<code>@PostMapping</code>的path属性,且path和value的值互通。</p>
<p><strong>示例</strong>:</p>
<pre><code class="language-java">RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(clazz, RequestMapping.class);
System.out.println(Arrays.toString(requestMapping.path()));
</code></pre>
<p>参考来源:<code>org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder#getClassMapping</code></p>
<pre><code class="language-java">private static String getClassMapping(Class<?> controllerType) {
Assert.notNull(controllerType, "'controllerType' must not be null");
RequestMapping mapping = AnnotatedElementUtils.findMergedAnnotation(controllerType, RequestMapping.class);
if (mapping == null) {
return "/";
}
String[] paths = mapping.path();
if (ObjectUtils.isEmpty(paths) || !StringUtils.hasLength(paths)) {
return "/";
}
if (paths.length > 1 && logger.isTraceEnabled()) {
logger.trace("Using first of multiple paths on " + controllerType.getName());
}
return paths;
}
</code></pre>
<h2 id="annotationutils">AnnotationUtils</h2>
<h3 id="getannotationannotation-class">getAnnotation(Annotation, Class)</h3>
<p>对于元注解的支持没有<code>AnnotatedElementUtils</code>强大,不支持元注解<code>@AliasFor</code>在嵌套注解中属性的关联,仅能获取当前注解的<code>@AliasFor</code>关联属性。以下代码可以获取<code>@RequestMapping</code>的path属性,且path和value的值互通。但不能通过获取<code>@RequestMapping</code>来获取<code>@PostMapping</code>中配置的path属性值。</p>
<p>示例:</p>
<pre><code class="language-java">RequestMapping requestMapping = AnnotationUtils.getAnnotation(clazz, RequestMapping.class);
System.out.println(Arrays.toString(requestMapping.path()));
</code></pre>
<blockquote>
<p>不支持递归父级,递归处理需使用 <code>findAnnotation(...)</code>相关的方法</p>
</blockquote>
<h3 id="findannotationannotatedelement-class">findAnnotation(AnnotatedElement, Class)</h3>
<p>若指定的方法或者类上没有找到对应的注解,则会递归查找父类或者接口对应的元素上有无该注解。</p>
<hr><br><br>
来源:https://www.cnblogs.com/yywf/p/19007967
頁:
[1]