
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
上声明
@RequestMapping
的
method
属性,其它属性通过
@AliasFor
来进行处理(有点覆写的味道)让开发者使用时可以对其它属性进行声明。这样就完成了一个特殊的
@RequestMapping
。
在 Spring 中我们使用这种方式的的复合注解还有
@RestController
您可以通过查看 Spring 源代码中这些注释的定义来自己验证。
@SpringBootApplication