1 自定义注解
1.1 创建自定义注解
从java5开始就可以利用 @interface 来定义自定义注解
技巧01:注解不能直接干扰程序代码的运行(即:注解的增加和删除操作后,代码都可以正常运行)
技巧02:@Retention 用来声明注解的保留期限
/** Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.*********************/package java.lang.annotation;/*** Annotation retention policy. The constants of this enumerated type* describe the various policies for retaining annotations. They are used* in conjunction with the {@link Retention} meta-annotation type to specify* how long annotations are to be retained.** @author Joshua Bloch* @since 1.5*/ public enum RetentionPolicy {/*** Annotations are to be discarded by the compiler.*/SOURCE,/*** Annotations are to be recorded in the class file by the compiler* but need not be retained by the VM at run time. This is the default* behavior.*/CLASS,/*** Annotations are to be recorded in the class file by the compiler and* retained by the VM at run time, so they may be read reflectively.** @see java.lang.reflect.AnnotatedElement*/RUNTIME }
技巧03:@Target 用来声明使用该注解的目标类型
/** Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.*********************/package java.lang.annotation;/*** The constants of this enumerated type provide a simple classification of the* syntactic locations where annotations may appear in a Java program. These* constants are used in {@link Target java.lang.annotation.Target}* meta-annotations to specify where it is legal to write annotations of a* given type.** <p>The syntactic locations where annotations may appear are split into* <em>declaration contexts</em> , where annotations apply to declarations, and* <em>type contexts</em> , where annotations apply to types used in* declarations and expressions.** <p>The constants {@link #ANNOTATION_TYPE} , {@link #CONSTRUCTOR} , {@link* #FIELD} , {@link #LOCAL_VARIABLE} , {@link #METHOD} , {@link #PACKAGE} ,* {@link #PARAMETER} , {@link #TYPE} , and {@link #TYPE_PARAMETER} correspond* to the declaration contexts in JLS 9.6.4.1.** <p>For example, an annotation whose type is meta-annotated with* {@code @Target(ElementType.FIELD)} may only be written as a modifier for a* field declaration.** <p>The constant {@link #TYPE_USE} corresponds to the 15 type contexts in JLS* 4.11, as well as to two declaration contexts: type declarations (including* annotation type declarations) and type parameter declarations.** <p>For example, an annotation whose type is meta-annotated with* {@code @Target(ElementType.TYPE_USE)} may be written on the type of a field* (or within the type of the field, if it is a nested, parameterized, or array* type), and may also appear as a modifier for, say, a class declaration.** <p>The {@code TYPE_USE} constant includes type declarations and type* parameter declarations as a convenience for designers of type checkers which* give semantics to annotation types. For example, if the annotation type* {@code NonNull} is meta-annotated with* {@code @Target(ElementType.TYPE_USE)}, then {@code @NonNull}* {@code class C {...}} could be treated by a type checker as indicating that* all variables of class {@code C} are non-null, while still allowing* variables of other classes to be non-null or not non-null based on whether* {@code @NonNull} appears at the variable's declaration.** @author Joshua Bloch* @since 1.5* @jls 9.6.4.1 @Target* @jls 4.1 The Kinds of Types and Values*/ public enum ElementType {/** Class, interface (including annotation type), or enum declaration */TYPE,/** Field declaration (includes enum constants) */FIELD,/** Method declaration */METHOD,/** Formal parameter declaration */PARAMETER,/** Constructor declaration */CONSTRUCTOR,/** Local variable declaration */LOCAL_VARIABLE,/** Annotation type declaration */ANNOTATION_TYPE,/** Package declaration */PACKAGE,/*** Type parameter declaration** @since 1.8*/TYPE_PARAMETER,/*** Use of a type** @since 1.8*/TYPE_USE }
坑01:自定义注解允许定义成员,但是这里的成员在进行声明时必须是无入参、无抛出异常的方式进行声明;而且成员只能是方法
坑02:在给成员指定默认值是必须使用default关键字
package cn.test.demo.base_demo.annotations;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface NeedTest {boolean value() default true; }
1.2 使用注解
1.2.1 创建一个SrpingBoot项目
下载地址:点击前往
1.2.2 新建一个自定义注解类
package cn.test.demo.base_demo.annotations;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface NeedTest {boolean value() default true; }
1.2.3 新建一个服务类
在该服务类的方法中使用刚刚创建的自定义注解
package cn.test.demo.base_demo.service;import cn.test.demo.base_demo.annotations.NeedTest; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service;/*** @author 王杨帅* @create 2018-04-29 21:31* @desc 学生服务类**/ @Service @Slf4j public class StudentService {private final String className = getClass().getName();@NeedTest()public void insert() {log.info("===/" + className + "/insert===新增操作");}@NeedTest(value = false)public void delete() {log.info("===/" + className + "/delete===删除操作");}}
1.2.4 访问注解
从Java5开始包、类、构造器、方法、字段等都反射对象都开始支持访问注解信息的方法
/*** {@inheritDoc}* @throws NullPointerException {@inheritDoc}* @since 1.5*/public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {return super.getAnnotation(annotationClass);}
package cn.test.demo.base_demo.service;import cn.test.demo.base_demo.annotations.NeedTest; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner;import java.lang.reflect.Method;import static org.junit.Assert.*;@RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class StudentServiceTest {private final String className = getClass().getName();@Testpublic void test01() {Class cla = StudentService.class;Method[] methods = cla.getDeclaredMethods();log.info("===/" + className + "/test01===方法数量为:{}", methods.length);for (Method method : methods) {NeedTest nt = method.getAnnotation(NeedTest.class);if (nt.value()) {log.info("===" + method.getName() + "()需要测试");} else {log.info("===" + method.getName() + "()不需要进行测试");}}}@Testpublic void insert() throws Exception {}@Testpublic void delete() throws Exception {}}