Spring Boot常用注解

Jan 19, 2017


Spring中有大量的注解完成了很多Magic的功能。

@SpringBootApplication

此注解注解在Spring Boot的XXXApplication类(有main函数,程序启动的入口)上,其结合了三个注解: @Configuration, @EnableAutoConfiguration 和 @ComponentScan。

@SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

@Configuration

@Configuration API文档

GitHub Test Example

Spring Boot中使用AnnotationConfigApplicationContext来实现基于Java的配置类加载。在这里做个简单的使用测试:

定义TestConfiguration类并使用注解@Configuration:

@Configuration
public class TestConfiguration {

    @Bean
    public String message() {
        return "Hello,World!";
    }
}

使用AnnotationConfigApplicationContext来获取TestConfiguration中的Bean。

@Test
public void testGetBeanMessage() throws Exception {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TestConfiguration.class);
    assertEquals("Hello,World!", ctx.getBean("message"));
}

AnnotationConfigApplicationContext也可以扫描整个包。

@Test
public void testScanPackages() throws Exception {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.scan("com.example");
    ctx.refresh();
    assertEquals("Hello,World!", ctx.getBean("message"));
    //assertEquals("Hello,World!", ctx.getBean(String.class));
}

如果希望使用XML的Spring Boot配置,仍建议从@Configuration类开始,使用@ImportResouce注解加载XML配置文件。

@Configuration
@ImportResource(locations={"classpath:application-bean.xml"})
//@ImportResource(locations={"file:/configuration/application-bean1.xml"})
public class ConfigClass {
}

@EnableAutoConfiguration

Refer to Spring Boot Auto Configuration. 建议将此注解加在最主要的@Configuration类,如XXXApplication上。

Spring Boot将尝试根据项目引入的依赖来配置程序,如引入了HSQLDB,不需要手动配置任何数据库连接的类,Spring Boot会自动搞定这些。

那么问题来了,你是否怀疑自动配置的侵入性太强? 其实还好:

  • 当你定义了自己的DataSource类时,Spring Boot就不会使用默认的DataSource配置。

  • 使用exclude或excludeName来告诉SpringBoot不要自动加载某一些配置。 @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})

  • properties中设置spring.autoconfigure.exclude

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
    org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
    org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration

或者

spring.autoconfigure.exclude[0]=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
spring.autoconfigure.exclude[1]=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
spring.autoconfigure.exclude[2]=org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
spring.autoconfigure.exclude[3]=org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration

@ComponentScan

@ComponentScan Example

@ComponentScan API Doc

在@Configuration类上使用,使用如@ComponentScan("org.my.pkg")@ComponentScan(basePackages = "org.my.pkg")

@ComponentScan会打开默认的过滤开关useDefaultFilters=true, 使用默认的resourcePattern=**/*.class

如果不想让一些类被扫描到,可以使用excludeFilters, 可以使用excludeFilters属性,下面的例子是过滤注解为@Service的所有类。我们也可以过滤自定义注解,但是自定义的注解必须实现TypeFilter。

@ComponentScan(
    basePackages = {"foo.bar", "foo.baz"},
    excludeFilters = @ComponentScan.Filter(
       value= Service.class,
       type = FilterType.ANNOTATION
    )
 )

如果想让一些带有自定义注解的类被扫描到,可以使用includeFilters。

@Configuration
@ComponentScan(basePackages = { "foo.bar","foo.baz" },
        includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Custom.class),
        useDefaultFilters = false)

@RestController

Spring 4.0引入@RestController,此注解是@Controller与@ResponseBody的组合。

@Controller

@Controller类其实就是一个@Component类,只是其带有Controller的语义。

@ResponseBody

当Controller类或者Controller类中的方法注解@ResponseBody, Spring将返回值直接写入到http response中。

Spring是如何达成对@ResponseBody的支持的呢?Spring中定义了一些HttpMessageConverters,HTTPMessageConverter的职责是从将request body中的内容转换成所需的类以及根据定义的mine type返回response body。Spring会循环匹配所有的HTTPMessageConverter直到找到一个能够处理给定mime type的。

这里需要注意的是,默认是不支持将对象转换为XML的,如果需要将对象response as xml, 需要自定义XML的Converter。

@RequestMapping

简单的@RequestMapping可以如@RequestMapping("/home")

@RequestMapping 的源代码

public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}

对produces和consumes的理解:

  • consumes: 指定处理请求的提交内容类型(Content-Type),如设置其为application/json, 方法仅处理request Content-Type为application/json类型的请求。

  • produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回, 如设置为application/json, 方法仅处理request请求中Accept头中包含了application/json的请求,同时暗示了返回的内容类型为application/json

参数相关注解

与@RequestMapping有相关的注解还有 @RequestParams, @PathVariable 等。

其他

@AutoWired

AutoWired Annotation Document

此注解在Spring中是由AutowiredAnnotationBeanPostProcessor来处理的。

可以在构造函数(也可以在私有构造函数上),私有成员变量(不需要定义set方法),setter方法,也可以在任意的配置方法上。

@Autowired 还支持在集合或数组上使用,如

@Autowired
private MovieCatalog[] movieCatalogs;

@Autowired
private Set<MovieCatalog> movieCatalogSets;

@Autowired
private Map<String, MovieCatalog> movieCatalogMaps;

Spring将所有的ApplicationContext里的MovieCatalog类型注入到数据或者集合参数中。如果希望注入的类有先后顺序,可以使得MovieCatalog实现Ordered接口,或使用@Order或@Priority。

对于Map来说,key值是String类型存储Bean的类名,value里存储类型。

@Autowired 会失败当没有任何匹配上的Bean时,为了不影响程序,我们可以使用@Autowired(required=false)

@Bean

Bean Annotation Document Bean Scopes

@Bean 是一个方法级别的注解,注解上支持设置init-method, destroy-method, autowiring和name。

@Bean
public TransferService transferService() {
    return new TransferServiceImpl();
}

默认的,@Bean注解得到的实例将默认使用公有的的close或shutdown方法作为类销毁前的callback。如果类里面定义了共有的close或者shutdown方法,而你不希望在容器关闭时调用它们,可以使用@Bean(destroyMethod="")。在DataSource上一般都使用这种方式。

@Bean 有自己的@Scope,默认是singleton,意味着每一个Spring IoC容器中只有一个实例。但也可以设置为@Scope("prototype"), @Scope("request"), @Scope("session"), @Scope("application"), @Scope("websocket")等。

singleton
singleton

Spring中的单例与设计模式中的单例(一个ClassLoader中只有一个类的实例)是不同的,Spring中的单例是每一个容器每一份实例,Spring中的Bean默认都是singleton。

prototype
prototype

Scope为prototype的类每次申请这个类的时候都会创建一个新的,即在注入到另外一个类或者调用getBean()方法都会创建一个新的类。

建议带状态的类(stateful beans)使用prototype范围,无状态的类(stateless beans)使用singleton范围。

@Profiles

Profiles Annotation Document

@Profile 往往用来对不同环境配置的区别对待,如Development环境与Production环境需要不同的DataSource配置。

@Configuration
public class AppConfig {

    @Bean
    @Profile("dev")
    public DataSource devDataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .addScript("classpath:com/bank/config/sql/test-data.sql")
            .build();
    }

    @Bean
    @Profile("production")
    public DataSource productionDataSource() throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
    }
}

@Profile 支持数组参数(或的关系,意味着多种环境active的情况下都可以激活此配置)@Profile({"p1", "p2"})以及语法@Profile({"p1", "!p2"})

@Profile 还支持Default配置@Profile("default"), 以为着如果没有环境被激活,默认配置会被激活,如果有环境激活,则默认配置不生效。

@ExceptionHandler

ExceptionHandler Annotation Document

@ExceptionHandler 经常出现在Controller类中,如

@Controller
public class SimpleController {

    @ExceptionHandler(IOException.class)
    public ResponseEntity<String> handleIOException(IOException ex) {
        // prepare responseEntity
        return responseEntity;
    }
}

@ExceptionHandler 可以设置Exception数组, @ExceptionHandler 注解的方法返回值可以是String(对应到view路径), ModelAndView对象,ResponseEntity,也可以在方法上注解@ResponseBody。

Spring中还有很多注解如 @Service, @Repository, @Component, @Bean, @ConfigurationProperties, @Value, @Inject, @PostConstruct 等,以及model相关的各种注解 @Entity, @Document, @Id, @Column, @ManyToMany 等等,不在此文的讨论范围,按下不表。

参考资料