转载

【如何让代码变“高级”(一)】-Spring组合注解提升代码维度(这么有趣)

【如何让代码变“高级”】-Spring组合注解提升代码维度

“致"高级"工程师(BUG工程师)

一颗折腾的心:heartpulse:

原创不易,点个赞呗:heartpulse:,支持支持

开发中这样的代码

对于每个开发人员都会遇到这样情况,代码如下:

@Api(tags = "自定义组合注解", description = "组合注解优化代码")
@StandardResult
@RequestMapping("/ccww")
@Controller
@ResponseBody
public class CombinationController{

}

在定义某个类或接口时,使用了Spring自带的注解(@Controller、@Service,@Conditional),同时又要使用公司特定的注解标注公司的业务,接着就出现了以下处理方式的那一幕。

”普通”开发人员

对于一般开发人员来说,只要功能、需求达到即可,代码也差不多就可以了,生活也就那样。 只要不出现BUG,测试人员,产品经理不找,万事大吉了,不用加班准备开溜陪女朋友了(真的有吗?:relieved:) !!!

生活就像心电图一样,一帆风顺就证明挂了,

因此我们需要一颗折腾的心

【如何让代码变“高级”(一)】-Spring组合注解提升代码维度(这么有趣)

高级”开发员(BUG工程师)

对于我们这类 “高级”开发员(BUG工程师) ,看到这样的代码,一个类上声明了五六个注解,长长的一大串注解,代码看起来就很普通,体现不出我们 “高级”开发员(BUG工程师)折腾的心:heartpulse:,BUG创造师的水平

而且注解本意是为了提供我们便捷,代码优化,作标注用。但和XML一样,过度使用就编程了一种灾难。

【如何让代码变“高级”(一)】-Spring组合注解提升代码维度(这么有趣)

于是我们持着一颗折腾的心:heartpulse:,寻找一种可以让自己看来舒服的整洁的代码修正,现在找到了使用 组合注解 的方式把需要的注解组合在一个自定义的组合注解上。

"高级”开发人员(BUG工程师)-基于组合注解方案

首先 我们持着一个折腾的心:heartpulse: ,想到平时我们常见的 SpringBoot 的启动注解 @SpringBootApplication

为什么它一个注解可以实现那么多功能呢?

怎么实现的呢?

我们怎么才能在将这个实现转化出自己所需的自定义注解呢?

接下来我们看看它的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

    @AliasFor(annotation = EnableAutoConfiguration.class)
    Class<?>[] exclude() default {};
    

    @AliasFor(annotation = EnableAutoConfiguration.class)
    String[] excludeName() default {};
    

    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};
    
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

}

@SpringBootApplication功能列表:

  • 声明 @Inherited 注解,声明了它的类的子类是可以继承它的
  • 声明 @SpringBootConfiguration 注解,可为类标注为配置类
  • 声明 @EnableAutoConfiguration 注解,声明了它的类会默认开启自动配置
  • 声明 @ComponentScan 注解,同时是 @ComponentScan 注解的容器。我们发现 scanBasePackagesscanBasePackageClasses 两个注解属性上面同样声明了 @AliasFor 注解,分别指向了 @ComponentScan注解的basePackages 注解属性和 basePackageClasses 属性。
  • 声明了 exclude() 为排除特定的自动配置类以及 excludeName() 排除特定的自动配置类名称

疑问??

@AliasFor

其实,基于 @Retention 的值可以分两时期对注解进行处理,:

  1. 编译时处理
  2. 运行时处理

@Retention的值为RetentionPolicy.CLASS时注解只存在于.class文件中,

都无法在运行时去获取注解的信息,只能在编译时处理

设定为RetentionPolicy.RUNTIME注解信息会存在.class文件中

通知单JVM加载.class文件时会把注解也加载到JVM中,所以就可在运行时获取注解的信息

运行时处理: 运行时处理是通过反射机制获取注解

再看看最原始的注解(完全由元注解组成的):

public @Interface Annotation
{

}

创建注解使用@Interface类型声明为注解,并且声明为@Interface类型的类在编译时会自动继承Annotation接口。

那什么类型的类可以继承接口呢?

自然是接口类型了,对编译器而言,注解其实就是一个接口。所以,我们在某个类上声明注解本质上等价于继承注解代表的接口。因为注解本质上是接口,就具有了相互继承的能力了。

还有(心想,这问题少年,那么多问题),在注解里声明的注解方法以及给注解属性赋值怎么处理的呢?

对了,就是JDK动态代理!编译器把我们的类翻译为实现了注解接口的类,然后用JDK动态代理的方式拦截所有该类方法的调用,如果是自定义方法就放行;如果是注解方法就拦截下来执行某些逻辑。至于我们给注解属性赋值,会以JDK动态代理类的常量的方式保存,需要时使用就可以了。我们可以看看代理注解的类是怎样的,具体的可以实现跟踪源码看看

最后,@AliasFor的作用是什么呢?

  • 用到注解 属性上,表示两个属性互相为别名,互相为别名的属性值必须相同,若设置成不同,则会报错
  • 注解是可以继承的,但是注解是不能继承父注解的属性的,也就是说,我在类扫描的时候,拿到的注解的属性值,依然是父注解的属性值,而不是你定义的注解的属性值,所以此时可以在子注解对应的属性上加上@AliasFor

手动起来,动手优化

现在该发挥我们程序员的核心本领之一 仿写 ,有什么是我们不能仿写出来的呢?

哈哈( 程序员的傲娇:smirk: ),话不多说,撸起袖子,开码,仿写@SpringBootApplication注解:

/**
*自定义组合注解
*@author Ccww
*
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
@RequestMapping
@Api
public @interface StandardResultRestControllerApi
{
    /**
    * 定义映射路径URL
     * @return
    */
   @AliasFor(annotation = RequestMapping.class, value = "path")
   String[] value() default {};

    /**
    *定义spring类名称
    *@return
    */
    @AliasFor(annotation = Controller.class, value = "value")
    String name() default "";
    /**
    *定义Api类tags属性
    *@return
    */
    @AliasFor(annotation = Api.class, attribute = "tags")
    String[] tags() default "";
    
    /**
    *定义Api类description属性
    *@return
    */
    @AliasFor(annotation = Api.class, attribute = "description")
    String description() default "";
}

优化后的代码如下

@StandardResultRestControllerApi(path="/Combination",tags = "自定义组合注解", description = "组合注解优化代码")
public class CombinationController
{
    
}

总结

经过优化后,整个类看起来轻简了很多。以后碰到类似情况,可以考虑使用组合注解来进行优化, 将多个注解作用于一个注解,用一个注解就可以来实现那多个注解的功能,使作用的元素(即方法或类等)看上去更简洁美观,当然主要还是更强大的属性覆盖功能。

但是也要视情况而定,不要盲目的使用组合注解,不然别人看起这代码就比较费劲了哈!!( “高级”程序员的微笑 )

温馨提示:不要盲目的使用组合注解

优点:

  • 代码整齐

缺点:

  • 代码可读性比较差,想使用必须理解其原意

各位看官还可以吗?喜欢的话,动动手指点个赞:heartpulse:,点个关注呗!!谢谢支持!

也欢迎关注公众号【 Ccww笔记 】,原创技术文章第一时间推出

更新文章系列:

《提升能力,涨薪可待篇》

《面试知识,工作可待篇》

《实战演练,拒绝996篇》

在工作中,在项目开发过程中,是不是需要管理有很多的任务、需求、缺陷等?遇到这些应该合理管理呢?

so easy, 【点击这了解详情】

CORNERSTONE提供敏捷、任务、需求、缺陷、测试管理、WIKI、共享文件和日历等功能模块,帮助企业完成团队协作和敏捷开发中的项目管理需求;更有甘特图、看板、思维导图、燃尽图等多维度视图,帮助企业全面把控项目情况。

原文  https://segmentfault.com/a/1190000021148743
正文到此结束
Loading...