Spring Boot 50个常用注解(Annotations)

Spring Boot使用Annotations保持应用干净明晰。

Spring Boot Annotations

org.springframework.boot.autoconfigure
org.springframework.boot.autoconfigure.condition

@SpringBootApplication

标记Spring Boot应用程序的主类(入口)。

@SpringBootApplication封装了以下三个注解:

@Configuration
@EnableAutoConfiguration
@ComponentScan

@EnableAutoConfiguration

启用自动配置,Spring Boot在类路径中寻找auto-configuration bean,并应用它们。

注:此注释必须与@Configuration一起使用。

Auto-Configuration Conditions

编写自定义auto-configurations时,希望Spring有条件地使用它们。

@ConditionalOnClass

当指定的类存在时,才使用此注解标记的类。

@Configuration

@ConditionalOnClass(DataSource.class)
class MySQLAutoconfiguration {}

@ConditionalOnMissingClass

仅当指定的类在类路径上找不到时,才使用此注解标记的类。

@ConditionalOnBean

当指定的对象存在时,使用此注解标记的类。

@Bean
@ConditionalOnBean(name = "dataSource")
LocalContainerEntityManagerFactoryBean entityManagerFactory() {}
@ConditionalOnMissingBean

当指定的对象不存在时,使用此注解标记的类。

@ConditionalOnProperty

为属性的值设置条件

@Bean
@ConditionalOnProperty(
  name = "usemysql", 
  havingValue = "local"
)
DataSource dataSource() {}

如果application.properties存在usemysql属性,属性值不为空且等于local,此注解标记的类或方法将生效。

注:usemysql属性,不一定来自单一的配置文件。

@ConditionalOnResource

指定的Resource存在时才使用。

@ConditionalOnResource(resources = "classpath:mysql.properties")
Properties additionalProperties() {}

@ConditionalOnWebApplication

基于当前应用程序是否是Web应用程序创建对象。

@ConditionalOnNotWebApplication

不是Web应用程序时生效。

@ConditionalExpression

当SpEL表达式返回true时,Spring使用此注解标记的条件:

@Bean
@ConditionalOnExpression("${usemysql} && ${mysqlserver == 'local'}")
DataSource dataSource() {}

@Conditional

对于复杂的条件,使用自定义的condition。

@Conditional(HibernateCondition.class)
Properties additionalProperties() {}

注:自定义condition需实现Condition接口。

org.springframework.context.annotation.Condition

Spring Web Annotations

org.springframework.web.bind.annotation

@Controller

标记Controller类。

@RequestMapping

标记处理请求的方法。

@RequestBody
@PostMapping("/save")
void saveVehicle(@RequestBody Vehicle vehicle) {}

@PostMapping("/request")
public ResponseEntity postController(
 @RequestBody LoginForm loginForm) {
  
  exampleService.fakeAuthenticate(loginForm);
  return ResponseEntity.ok(HttpStatus.OK);
}

将HTTP请求的参数(主体)映射到对象。

@PathVariable

从一个URI模板变量中获取方法的参数。

@RequestMapping("/{pid}")
Vehicle getVehicle(@PathVariable("pid") long id) {}

或者

@RequestMapping("/{id}")
Vehicle getVehicle(@PathVariable long id) {}

或者

@RequestMapping("/{id}")
Vehicle getVehicle(@PathVariable(required = false) long id) {}

@RequestParam

获取HTTP请求参数。拥有与@PathVariable注解相同的配置项。

@RequestMapping
Vehicle getVehicleByParam(@RequestParam("id") long id) {}

或者指定为空时的默认值。

@RequestMapping("/buy")
Car buyCar(@RequestParam(defaultValue = "5") int seatCount) {}

注:使用@CookieValue、@RequestHeader获取其他HTTP请求参数。

@ResponseBody

将方法的返回值视为响应本身。

@ResponseBody
@RequestMapping("/hello")
String hello() {
  return "Hello World!";
}

注:此注解也可放置在类上。

@ExceptionHandler

自定义错误处理方法。

@ExceptionHandler(IllegalArgumentException.class)
void onIllegalArgumentException(IllegalArgumentException exception) {}

@ResponseStatus

指定响应的HTTP状态。使用code或value参数声明状态码,reason参数声明原因。

@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
void onIllegalArgumentException(IllegalArgumentException exception) {}

@RestController

等价于@Controller和@ResponseBody联合使用。

@ModelAttribute

使用指定的key值,获取Model中的元素。此注解放置在方法上,表明在调用Controller的方法前,先调用此注解标记的方法。

@PostMapping("/assemble")
void assembleVehicle(@ModelAttribute("vehicle") Vehicle vehicleInModel) {}

或者

@PostMapping("/assemble")
void assembleVehicle(@ModelAttribute Vehicle vehicle) {}

注:参数与属性同名时可不作声明。

@ModelAttribute("vehicle")
Vehicle getVehicle() {}

此注解放置在方法上,Spring会将返回值自动放入Model中。

或者

@ModelAttribute()
Vehicle getVehicle() {}

注:同名属性可不必声明。

@Controller
@ControllerAdvice
public class EmployeeController {
@RequestMapping(value = "/addEmployee", method = RequestMethod.POST)
  public String addEmployee(){}

@ModelAttribute
  public void addAttributes(Model model) {
    model.addAttribute("msg", "Welcome to the Netherlands!");
}
}

调用addEmployee方法前,在model中放置一个参数。

@CrossOrigin

启用跨域处理,允许所有来源的请求访问此注解标记的方法。

@CrossOrigin
@RequestMapping("/hello")
String hello() {
  return "Hello World!";
}

注:详情参考spring doc

@CrossOrigin(origins = "http://example.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {}

限定跨域请求的来源。maxAge对应HTTP Access-Control-Max-Age参数,单位为秒。

注:浏览器在执行跨域请求时,会使用OPTIONS方法向服务发起一次预检请求,如果服务允许跨域,则发起实际请求。Access-Control-Max-Age参数控制预检请求的有效时间,有效期间内,浏览器不会对跨域请求发起预检。

Spring Scheduling Annotations

@EnableAsync

开启异步调用。

@Async

标记异步执行的方法。

@EnableScheduling

启用调度。

注:需与@Configuration一起使用。

@Scheduled

定义调度的方法。

@Scheduled(fixedRate = 10000)
void checkVehicle() {}

@Schedules

指定多个@Scheduled规则,定时时间表。

@Schedules({ 
 @Scheduled(fixedRate = 10000), 
 @Scheduled(cron = "0 * * * * MON-FRI")
})
void checkVehicle() {}

Spring Core Annotations

@Autowired

注入依赖。

@Qualifier

与@Autowired一起使用,引入指定的bean对象。

@Autowired
Biker(@Qualifier("bike") Vehicle vehicle) {
  this.vehicle = vehicle;
}

@DependsOn

声明依赖对象,被此注解标记的类,创建时会晚于依赖的对象。解决隐式依赖问题。

@DependsOn("engine")
class Car implements Vehicle {}

或者

@Bean
@DependsOn("fuel")
Engine engine() {
  return new Engine();
}

@Lookup

Spring在调用此注解标记的方法时,会以返回值类型创建一个实例,解决在单例中调用多例时的问题。

public abstract class SingletonBean {
 public void print() {
    PrototypeBean bean = methodInject();
    bean.say();
 }

@Lookup
 protected abstract PrototypeBean methodInject();
}

此注解的方法需满足以下条件:

<public|protected> [abstract] <return-type> theMethodName(no-arguments);

Spring Bean Annotations

@ComponentScan

使用注释配置要扫描类的应用程序包。

@Configuration
@ComponentScan(basePackages = "com.baeldung.annotations")
@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
或者
@Configuration
@ComponentScans({ 
 @ComponentScan(basePackages = "com.baeldung.annotations"), 
 @ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
})
class VehicleFactoryConfig {}

注:Java 8支持重复注解功能。

@Component

类级别的通用注解。

@Repository

定义数据库持久化层,此注解会自动将持久化异常,转换为Spring DataAccessExeption子类。

@Service

声明业务逻辑层。

@Aspect

构造切入点。

@Aspect
@Component
public class PerformanceAspect {
  @Pointcut("within(@org.springframework.stereotype.Repository *)")
  public void repositoryClassMethods() {};
 
  @Around("repositoryClassMethods()")
  public Object measureMethodExecutionTime(ProceedingJoinPoint joinPoint) 
   throws Throwable {
    long start = System.nanoTime();
    Object returnValue = joinPoint.proceed();
    long end = System.nanoTime();
    String methodName = joinPoint.getSignature().getName();
    System.out.println("Execution of " + methodName + " took " + 
     TimeUnit.NANOSECONDS.toMillis(end - start) + " ms");
    return returnValue;
  }
}

该切入点针对放置了@Repository注解的类,对类中所有方法进行匹配。@Around advice针对切入点进行拦截,获取方法的执行时间。