暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

​Java基础—注解

一十二章经 2020-06-01
267

注解是Java1.5之后出现的特性,在刚开始学习注解的时候个人觉得是一个很鸡肋的语法,但是随着接触的系统越来越多,发现一个好的系统中必然存在注解的加持。尤其是在现如今Spring全家桶统一了整个后端框架后,其通过注解的方式对外提供了大量的组件,因此注解驱动开发是系统架构优先考虑的方向

在平常的CRUD中我们很少会去关心注解,都是一个@Autowired然后一通操作。但是一旦涉及到架构层面,注解的强大功能就显现出来了。比如以下一些代码。这些代码都是属于系统代码并不是业务代码。

  1. 系统日志模块

/***
 * 日志注解
 *
 */

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RestLog {
    //操作类型
    String type();
    //实体
    Class tableName() default Object.class ;
    //操作描述
    String discription();
}

通过AOP的方式对自定义注解进行切入

@Pointcut("@annotation(xxx.xxx.xxx.RestLog)")
public void methodCachePointcut() {}

@Around("methodCachePointcut()")
public Object operationLog(ProceedingJoinPoint point) throws Throwable {
    ....
    RestLog restLog = method1.getAnnotation(RestLog.class);
    if (restLog != null){
        operType = restLog.type();
        description = restLog.discription();
    }
    ....
}


  1. 动态的向IOC中注册Bean

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ServiceReg {
    /**
     * @return 实现的接口全限定名
     */

    String serviceName();
    /**
     * @return 提供给服务注册策略的参数
     */

    String strategyParam() default "";
}

使用自定义ServiceReg注解

public ConcurrentHashMap<String, Object> getRegisteredService() {
        // 只获取被标记可用于服务DNS注册的对象
        Map<String, Object> beanMaps = SpringContextUtils.getApplicationContext().getBeansWithAnnotation(ServiceReg.class);
        ConcurrentHashMap<String, Object> beanFactory  = new ConcurrentHashMap<>(beanMaps.size());
        beanMaps.forEach((name, value) -> {
            // 获取 服务注册 注解ServiceReg
            ServiceReg serviceRegAnnotation = value.getClass().getAnnotation(ServiceReg.class);
            String serviceName = serviceRegAnnotation.serviceName();
        });
        return beanFactory;
    }

以上两个例子都是属于系统代码。

通过这两个例子其实可以很好的看到注解在系统架构层面提供了很大的帮助。

由此也能看出注解也会伴随着反射技术一起出现

注解组成部分

以案例二中自定义的注解说明注解的组成。自定义注解的格式是

[修饰符] @interface 注解名{
    // 注解属性
}

在这个注解的声明还有四个注解,这四个注解也被称为元注解,用于修饰自定注解上面;

  1. @Target({ElementType.TYPE}):作用范围,这里的作用返回TYPE表示作用在类上或接口上,另外还有METHOD表示作用在方法上

  2. @Retention(RetentionPolicy.RUNTIME) :注解的生命周期,RUNTIME表示在源码、字节码、运行阶段都生效;

  3. @Documented:JavaDoc格式的注释给被加了自定义注解的类或方法或属性注释

  4. @Inherited:自定义注解要是标记在类上,那么该类的子类也会继承这个自定义注解。如果自定义注解没有该元注解,表示此注解用在类上时,不会被子类所继承,只是针对于类来说(如果属性和方法没有被重写也还是有效果的)

自定义注解实现单元测试中@Test的功能

  • 自定义注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface EthanTest{
    String value();
    String name() default "测试";
}


  • 编写测试

public class TestAnnotation {

    @EthanTest("1111111111")
    public void test01(){
        System.out.println("test01!!!!");
    }

    @EthanTest("2222222222")
    public void test02(){
        System.out.println("test02!!!!");
    }

    @EthanTest("3333333333333")
    private void test03(){
        System.out.println("test03!!!!");
    }

    public void test04(){
        System.out.println("test04!!!!");
    }

    public static void main(String[] args) throws Exception {
        TestAnnotation testAnnotation = new TestAnnotation();
        // 获得Class对象
        Class<? extends TestAnnotation> clazz = testAnnotation.getClass();
        // 获得Class对象中所有的方法
        Method[] methods = clazz.getDeclaredMethods();
        // 遍历
        for (Method method : methods) {
            method.setAccessible(true);
            // 判断该方法有无@EthanTest注解
            if(method.isAnnotationPresent(EthanTest.class)){
                // 存在则解析输出
                EthanTest annotation = method.getAnnotation(EthanTest.class);
                System.out.println(annotation.value());
                System.out.println(annotation.name());
                // 执行方法
                method.invoke(testAnnotation);
            }
        }
    }
}


  • 运行结果

1111111111
测试
test01!!!!
2222222222
测试
test02!!!!
3333333333333
测试
test03!!!!

test01至test03都有被执行,test04没有执行符合逾期效果



文章转载自一十二章经,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论