logo头像

From zero to HERO

在Spring框架中使用自定义复合注解简化开发

1. 前言

Java 1.5 引入了注解,极大的方便了将元数据添加到 Java 代码中,简化了开发。现在很多框架都严重依赖 Java 注解,尤其是 Spring 框架,很多面试者都把这个作为 Spring 框架的一个特色,虽然不够贴切,但是也不是没有一点道理。在本文中,我们将介绍一个非常有用的 Spring 特性,该功能允许我们基于一个或多个 Spring 注解创建自己的注解。

2. 复合注解

我们在 Spring 开发中也经常用到一些注解,而且有些注解会高频率的一起使用来完成一些逻辑。我们一遍又一遍的重复使用这两个注解。我们的代码上写满了注解,看起来非常笨重。我们如何来简化对它们的使用呢?接下来我们来研究一下。

请注意本文讲的是 Spring 的特性,而不是 Java 提供的功能。如果将其他框架和库的注解添加到你自定义的复合注解中可能无法正常工作。

2.1 最简单的写法

比如我们经常使用 @Service@Transactional 组合来进行服务层的逻辑开发。事实上我们可以创建一个复合注解来把一些注解 “捆绑” 到一起。

@Service
@Transactional(rollbackFor = Exception.class,timeout=5)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface TransactionalService {
}

然后我们就能使用我们自定义的来对服务类进行标记:

@TransactionalService
public class YourService {
    //todo your business
}

跟我们使用 @Service@Transactional 一样的效果。

2.2 进阶写法

章节 2.1 提供的例子中如果我们希望 @Transactional 的另一个属性 timeout 在使用时保证多样性而不是固定的值 5 怎么办?我们来研究一下这个客观存在的需求。

Spring MVC 的都知道 @GetMapping@RequestMapping(method = {RequestMethod.GET})的缩写。

package org.springframework.web.bind.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {

    /**
     * Alias for {@link RequestMapping#name}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String name() default "";

    /**
     * Alias for {@link RequestMapping#value}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] value() default {};

    /**
     * Alias for {@link RequestMapping#path}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] path() default {};

    /**
     * Alias for {@link RequestMapping#params}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] params() default {};

    /**
     * Alias for {@link RequestMapping#headers}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] headers() default {};

    /**
     * Alias for {@link RequestMapping#consumes}.
     * @since 4.3.5
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] consumes() default {};

    /**
     * Alias for {@link RequestMapping#produces}.
     */
    @AliasFor(annotation = RequestMapping.class)
    String[] produces() default {};

}

从上面可以看到,我们通过在 @GetMapping 上声明 @RequestMappingmethod 属性,其它属性通过 @AliasFor 来进行处理(有点覆写的味道)让开发者使用时可以对其它属性进行声明。 这样就完成了一个特殊的 @RequestMapping

Spring 中我们使用这种方式的的复合注解还有 @RestController@SpringBootApplication 您可以通过查看Spring源代码中这些注释的定义来自己验证。

3. 总结

今天对 Spring 的注解组合方式进行简单讲解,某种程度上使我们的代码更加 “清爽” ,但是我们应该善用它而不要滥用它避免增加理解难度。更需要你注意的是这个是 Spring 特性 ,不是所有的类库都支持这种写法。如果你有什么看法可以通过留言告诉我,更多干货知识可通过公众号:Felordcn 来获取。

评论系统未开启,无法评论!