title: SpringBoot之神秘的注解 tags:
- SpringBoot
- 注解
- 元注解
- 组合注解 categories: springboot date: 2017-11-27 23:28:37
背景
- 大量的XML让开发者厌恶,因此Spring提供了许多注解来完成各种功能。
- 大量的注解让开发者厌恶 ,因此Spring提供了组合注解来完成各种功能。
举例
- 最典型的SpringMVC中我们使用如下注解 @Controller
事实上我们接触到Controller时都会如下说明Controller Service Repository事实上和Component 没有差别 但是Spring后期可能可能条件不同的语义 因此注意使用
/**
* Indicates that an annotated class is a "Controller" (e.g. a web controller).
*
* <p>This annotation serves as a specialization of {@link Component @Component},
* allowing for implementation classes to be autodetected through classpath scanning.
* It is typically used in combination with annotated handler methods based on the
* {@link org.springframework.web.bind.annotation.RequestMapping} annotation.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @since 2.5
* @see Component
* @see org.springframework.web.bind.annotation.RequestMapping
* @see org.springframework.context.annotation.ClassPathBeanDefinitionScanner
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any
*/
String value() default "";
}
复制代码
复制代码
- 我们把修饰其他注解的注解称之为Meta Annotation【元注解】
A meta-annotation is an annotation that is declared on another annotation. An annotation is therefore meta-annotated if it is annotated with another annotation. For example, any annotation that is declared to be documented is meta-annotated with@Documented
from thejava.lang.annotation
package. - 当我们业务越发复杂的情况下我们会大量的使用注解进行组合 比如
@RestController
@RequestMapping("user")
public class TbUserController extends AbstractRestController<TbUserVo, TbUserSo, BigInteger> {
@Resource
private TbUserService tbUserService;
}
复制代码
这个注解还比较少,但是对于SpringBoot 来说可能注解的量会直线上升,比如
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
复制代码
4. 那么由于如上的问题带来了一个问题 可能一个简单的类中的代码比注解还要少! 5. 我们通过组合注解的方式来解决此问题
我们声明如下
复制代码
@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 {
}
复制代码
复制代码
Spring注解编程模型
对于Spring来说通常定义的注解是要适配原有的功能 比如Controller注解可以声明Bean的名称
但是一旦定义的组合注解的名称相同自然就会存在如下的问题【覆盖】
Spring提供了AliasFor注解来完成别名的转换 比如
@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 {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
String[] excludeName() default {};
/**
* Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
* for a type-safe alternative to String-based package names.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
/**
* Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
* scan for annotated components. The package of each class specified will be scanned.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
复制代码
通过如上方式可以指定到元注解的属性【比如SpringBootApplication的scanBasePackageClasses ===》ComponentScan的basePackageClasses】