本文主要介绍Spring中一些常见注解的部分属性配置介绍以及一些不常用注解的简单介绍。下面让我们直接进入主题吧。
@RequestMapping
@RequestMapping可以说是SpringMVC以及OpenFeign中最常用的注解,其主要用于映射Web请求。
produces属性配置
当前主流服务大部分都是使用JSON作为数据交换格式,即通过配置MappingJackson2HttpMessageConverter或者GsonHttpMessageConverter定义数据交换时使用JSON进行格式转换。这时候默认的响应数据格式就是application/json,如果想要让RequestMapping请求返回text/html或者其他非application/json数据。那么RequestMapping#produces就可以派上用场了。
produces属性配置可以调整数据响应格式,比如下面这段代码:
@RequestMapping(value = "/html", produces = {MediaType.TEXT_HTML_VALUE})
public String html() {
return "html>\n" +
"\n" +
" \n" +
" \n" +
" HTML\n" +
" \n" +
" \n" +
" Hello World!
\n" +
" \n" +
"\n";
}

这时候请求该页面返回的数据格式就是text/html;charset=UTF-8了。如果我们不添加produces配置,那么由于我们也配置了StringHttpMessageConverter,并且配置的StringHttpMessageConverter执行顺序早于MappingJackson2HttpMessageConverter等JSON消息转换器,那么这时候返回的数据格式就是text/plain;charset=UTF-8。具体看各自应用的消息转换器配置情况。
consumes属性配置
既然有produces属性可以配置数据的响应格式,那么当然也有对应的consumes配置用来限定请求映射的数据格式。如下面这段代码:
@PostMapping(value = "/htmlReq", consumes = {MediaType.TEXT_HTML_VALUE})
public R htmlReq(@RequestBody String html) {
log.info("html: {}", html);
return R.status(true);
}
@PostMapping("/htmlReq")
public R htmlReqNoConsumes(@RequestBody String html) {
log.info("html: {}", html);
return R.status(true);
}
这里我们定义了两个同样的请求映射/htmlReq,其中一个通过consumes限定了请求映射的数据格式必须是text/html,另一个不限定数据映射格式。


可以看到请求的数据格式如果是text/html,那么将会被映射到htmlReq方法。其他格式则被映射到htmlReqNoConsumes方法。
produces和consumes属性通常用于与外部的对接,使用频率较低,有时候外部对接文档不完善,这时候我们就要通过直接发送请求确认他们的请求响应数据格式要求,然后相应的使用produces和consumes进行调整。
派生注解
说到@RequestMapping,就不得不提及它的派生注解:@GetMapping、@PostMapping、@DeleteMapping等注解。这些注解首先都标注了@RequestMapping,即他们本身都是@RequestMapping注解,然后通过@AliasFor注解将注解的属性别名映射到@RequestMapping的属性上。最后使用的使用通过AnnotationUtils和AnnotatedElementUtils进行别名配置合并或者同义化处理,注意派生注解在Spring框架注解中用的相当多,我们可以通过派生注解的方法进一步增强@RequestMapping,比如添加版本号映射功能等。这些后续有机会再讲。
@Ordered 和 @Priority
@Ordered注解和@Priority注解以及org.springframework.core.Ordered接口都可以定义Bean的实例化顺序,同时Spring提供了org.springframework.core.annotation.AnnotationAwareOrderComparator工具类让我们可以对特定的Bean数组或者列表依照从小到大进行排序。如下代码:
public interface XxHandler {
}
@Component
@Priority(1)
public class AHandler implements XxHandler {
}
@Component
@Priority(3)
public class BHandler implements XxHandler {
}
@Component
@Order(2)
public class CHandler implements XxHandler {
}
@Component
@Priority(1)
public class DHandler implements XxHandler, Ordered {
@Override
public int getOrder() {
return 4;
}
}
那么启动容器后,通过AnnotationAwareOrderComparator#sort方法排序所有XxHandler实例的时候,将能够得到ACBD处理器有序列表。

@EnableAutoConfiguration
@EnableAutoConfiguration注解用于激活Spring的自动配置,在SpringBoot项目可能看得比较少,因为实际上该注解已经默认组合到@SpringBootApplication注解了。该注解的主要作用简单理解就是搜索所有classpath路径下的META-INF/spring.factories配置文件中的org.springframework.boot.autoconfigure.EnableAutoConfiguration配置项中定义的类完全限定名,然后将这些类统一作为配置类交给Spring进行自动配置。搜索可以发现classpath下有很多的spring.factories配置文件:

spring.factories配置文件的org.springframework.boot.autoconfigure.EnableAutoConfiguration配置项是自定义SpringBootStarter的核心,通过该配置项和@EnableAutoConfiguration我们可以实现高度可插拔的SpringBootStarter,这个有机会可以另外开篇讲解。
@Import
@Import注解是一个比较有趣的注解,它既可以自由选择需要加载的配置类,也可以高度自由地定义Bean的注册。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
* or regular component classes to import.
*/
Class>[] value();
}
它只有一个必填属性value,具体有三种用法:
导入配置类
这种方法导入的类通常标注有@Configuration,当然这不是硬性要求。比如Druid的数据源自动配置:
@Configuration
@ConditionalOnClass(DruidDataSource.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})
@Import({DruidSpringAopConfiguration.class,
DruidStatViewServletConfiguration.class,
DruidWebStatFilterConfiguration.class,
DruidFilterConfiguration.class})
public class DruidDataSourceAutoConfigure {
private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);
@Bean(initMethod = "init")
@ConditionalOnMissingBean
public DataSource dataSource() {
LOGGER.info("Init DruidDataSource");
return new DruidDataSourceWrapper();
}
}
选择性加载配置类
这种方式导入的类必须实现org.springframework.context.annotation.ImportSelector接口,通过该接口的selectImports(AnnotationMetadata importingClassMetadata)方法确定导入的配置类。比如:@CacheAutoConfiguration。
动态注册Bean
这种方式导入的类必须实现org.springframework.context.annotation.ImportBeanDefinitionRegistrar接口,通过registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)方法动态注册SpringBean。比如:MyBatis的@MapperScan注解导入的MapperScannerRegistrar。是自
@Import通常会结合@EnableXxx(Spring的自动配置类)注解使用。算是自动化配置的一个核心类。
@Role
这个注解应该说大部分人没见过,即使见过应该也不会用到。这个注解主要用户标注SpringBean的角色。总共有三种角色:
ROLE_APPLICATION
简单理解就是这个Bean属于用户,是应用大部分Bean的角色。通常我们的Bean默认就是这种。
ROLE_SUPPORT
指示Bean同样属于用户,但是一般是外部配置的比较复杂的Bean。
ROLE_INFRASTRUCTURE
指示Bean不属于用户,属于Spring内部的基础设施Bean,通常给Spring内部工作使用。
这个注解在高度自定义校验器(抽离成独立依赖并提供给其他服务集成使用,而不是在各个应用中单独配置)的时候会用到,如果你自己注册到Spring的LocalValidatorFactoryBean没有添加@Role(BeanDefinition.ROLE_INFRASTRUCTURE)注解,那么运行时将直接报错。默认的ValidationAutoConfiguration自动配置如下:
public class ValidationAutoConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnMissingBean(Validator.class)
public static LocalValidatorFactoryBean defaultValidator() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
return factoryBean;
}
}
目前该角色的Bean主要由org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator进行判断是否生成自动代理切面。
限于篇幅原因,本文不少注解没有实例讲解,后续有机会我们会单独开篇讲解。如有勘误,欢迎斧正!