Spring 常用注解
Spring Core Annotations
DI-Related Annotations
-
@Autowried
可以用于构造函数、setter 方法、属性注入。
@Autowried 有一个 boolean 类型的参数
required,默认值为 true。当没有找到合适的 bean 注入时,若是 true,则抛出异常,否则,不注入。注意:如果用在构造函数上,则构造函数所有的参数都是必需的。
构造函数注入
class Car { Engine engine; @Autowired Car(Engine engine) { this.engine = engine; } }setter 方法注入
class Car { Engine engine; @Autowired void setEngine(Engine engine) { this.engine = engine; } }属性注入
class Car { @Autowired Engine engine; } -
@Bean
标记一个工厂方法。
@Bean Engine engine() { return new Engine(); }返回的bean 与工厂方法名相同,如果想设置不同的名字,可以使用带有参数的注解,参数的值就是返回 bean 的别名。
@Bean("engine") Engine getEngine() { return new Engine(); }注意:所有使用@Bean 注解的方法必须在使用@Configuration 注解的类中。
-
@Qualifier
与@Autowired 注解一起使用,消除注入的歧义性,可以使用 bean id 或者 bean name。
如下,两个 bean 实现同一个接口。
class Bike implements Vehicle {} class Car implements Vehicle {}如果 Spring 需要注入一个 Vehicle bean,将发现有多个 Vehicle 类型的 bean,我们可以使用@Qualifier 提供明确的类名。
构造函数注入
@Autowired Biker(@Qualifier("bike") Vehicle vehicle) { this.vehicle = vehicle; }setter 方法注入
@Autowired @Qualifier("bike") void setVehicle(Vehicle vehicle) { this.vehicle = vehicle; }属性注入
@Autowired @Qualifier("bike") Vehicle vehicle; -
@Required
用于标记我们想通过 xml注入的 setter 方法
@Required void setColor(String color) { this.color = color; }<bean class="com.baeldung.annotations.Bike"> <property name="color" value="green" /> </bean> -
@Value
注入属性值,可以用于构造函数、setter 方法和属性。
构造函数
Engine(@Value("8") int cylinderCount) { this.cylinderCount = cylinderCount; }setter方法
@Autowired void setCylinderCount(@Value("8") int cylinderCount) { this.cylinderCount = cylinderCount; }@Value("8") void setCylinderCount(int cylinderCount) { this.cylinderCount = cylinderCount; }属性注入
@Value("8") int cylinderCount; -
@DependsOn
Spring 在初始化这个 bean之前初始化其他 beans。一般的,这种依赖注入关系是自动的。
当存在隐式依赖关系时才需要这个注解,例如,JDBC 驱动或者 static 变量初始化。
@DependsOn("engine") class Car implements Vehicle {}@Bean @DependsOn("fuel") Engine engine() { return new Engine(); } -
@Lazy
懒加载
可以使用在
- @Bean 延迟工厂方法调用
- @Configuration 所有包含@Bean 注解的方法都将受影响
- @Component 延迟初始化
- @Autowired 注解的构造函数、setter 方法或者属性,延迟加载依赖
-
@Lookup
返回方法返回类型的实例
创建一个 prototype bean
@Component @Scope("prototype") public class SchoolNotification { // ... prototype-scoped state }创建一个单例
@Component public class StudentServices { // ... member variables, etc. @Lookup public SchoolNotification getNotification() { return null; } // ... getters and setters }@Test public void whenLookupMethodCalled_thenNewInstanceReturned() { // ... initialize context StudentServices first = this.context.getBean(StudentServices.class); StudentServices second = this.context.getBean(StudentServices.class); assertEquals(first, second); assertNotEquals(first.getNotification(), second.getNotification()); } -
@Primary
@Component @Primary class Car implements Vehicle {} @Component class Bike implements Vehicle {} @Component class Driver { @Autowired Vehicle vehicle; } @Component class Biker { @Autowired @Qualifier("bike") Vehicle vehicle; }Driver 类,spring 注入一个 Car bean,Biker 类,spring 注入一个 Bike 对象。
-
@Scope
@Scope 定义@Component 或者@Bean 定义的 bean 的范围,主要有:singleton、prototype、request、session、globalSession 或者其他自定 scope。
@Component @Scope("prototype") class Engine {}
Context Configuration Annotations
-
@Profile
用于@Component 或者@Bean
@Component @Profile("sportDay") class Bike implements Vehicle {} -
@Import
不需要组件扫描,可以使用特定的@Configuration 类。
@Import(VehiclePartSupplier.class) class VehicleFactoryConfig {} -
@ImportResource
导入 XML 配置
@Configuration @ImportResource("classpath:/annotations.xml") class VehicleFactoryConfig {} -
@PropertySource
属性文件
@Configuration @PropertySource("classpath:/annotations.properties") class VehicleFactoryConfig {}@Configuration @PropertySource("classpath:/annotations.properties") @PropertySource("classpath:/vehicle-factory.properties") class VehicleFactoryConfig {} -
@PropertySources
@Configuration @PropertySources({ @PropertySource("classpath:/annotations.properties"), @PropertySource("classpath:/vehicle-factory.properties") }) class VehicleFactoryConfig {}
Spring Web Annotations
-
@RequestMapping
使用在@Controller 注解的类中,标记 request 处理方法,可以使用以下配置:
path, or its aliases, name, and value: which URL the method is mapped to method: compatible HTTP methods params: filters requests based on presence, absence, or value of HTTP parameters headers: filters requests based on presence, absence, or value of HTTP headers consumes: which media types the method can consume in the HTTP request body produces: which media types the method can produce in the HTTP response body
@Controller class VehicleController { @RequestMapping(value = "/vehicles/home", method = RequestMethod.GET) String home() { return "home"; } }@Controller @RequestMapping(value = "/vehicles", method = RequestMethod.GET) class VehicleController { @RequestMapping("/home") String home() { return "home"; } }@GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping都是由@RequestMapping 转变而来的。
-
@RequestBody
自动封装客户端传递过来的 json 格式参数到 bean 中
@PostMapping("/save") void saveVehicle(@RequestBody Vehicle vehicle) { // ... } -
@PathVariable
@RequestMapping("/{id}") Vehicle getVehicle(@PathVariable(required = false) long id) { // ... } -
@RequestParam
@RequestMapping("/buy") Car buyCar(@RequestParam(defaultValue = "5") int seatCount) { // ... }与@RequestParam 类似的注解,还有@CookieValue 和@RequestHeader ,可以获取 cookie 和 headers。
Response Handling Annotations
-
@ResponseBody
@ResponseBody @RequestMapping("/hello") String hello() { return "Hello World!"; } -
@ExceptionHandler
自定义错误处理方法
@ExceptionHandler(IllegalArgumentException.class) void onIllegalArgumentException(IllegalArgumentException exception) { // ... } -
@ResponseStatus
@ExceptionHandler(IllegalArgumentException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) void onIllegalArgumentException(IllegalArgumentException exception) { // ... }
Other Web Annotations
-
@Controller
-
@RestController
@RestController 包含@Controller 和@ResponseBody
@Controller @ResponseBody class VehicleRestController { // ... }@RestController class VehicleRestController { // ... } -
@ModelAttribute
@ModelAttribute 可以用在方法参数或者方法上。
@ModelAttribute methods are invoked before the controller methods annotated with @RequestMapping are invoked
The View
<form:form method="POST" action="/spring-mvc-basics/addEmployee" modelAttribute="employee"> <form:label path="name">Name</form:label> <form:input path="name" /> <form:label path="id">Id</form:label> <form:input path="id" /> <input type="submit" value="Submit" /> </form:form>The Controller
@Controller @ControllerAdvice public class EmployeeController { private Map<Long, Employee> employeeMap = new HashMap<>(); @RequestMapping(value = "/addEmployee", method = RequestMethod.POST) public String submit( @ModelAttribute("employee") Employee employee, BindingResult result, ModelMap model) { if (result.hasErrors()) { return "error"; } model.addAttribute("name", employee.getName()); model.addAttribute("id", employee.getId()); employeeMap.put(employee.getId(), employee); return "employeeView"; } @ModelAttribute public void addAttributes(Model model) { model.addAttribute("msg", "Welcome to the Netherlands!"); } }The Model
@XmlRootElement public class Employee { private long id; private String name; public Employee(long id, String name) { this.id = id; this.name = name; } // standard getters and setters removed }Results View
<h3>${msg}</h3> Name : ${name} ID : ${id} -
@CrossOrigin
@CrossOrigin @RequestMapping("/hello") String hello() { return "Hello World!"; }@CrossOrigin(maxAge = 3600) @RestController @RequestMapping("/account") public class AccountController { @CrossOrigin("http://example.com") @RequestMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } }Global CORS Configuration
JavaConfig
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**"); } }XML Namespace
<mvc:cors> <mvc:mapping path="/**" /> </mvc:cors><mvc:cors> <mvc:mapping path="/api/**" allowed-origins="http://domain1.com, http://domain2.com" allowed-methods="GET, PUT" allowed-headers="header1, header2, header3" exposed-headers="header1, header2" allow-credentials="false" max-age="123" /> <mvc:mapping path="/resources/**" allowed-origins="http://domain1.com" /> </mvc:cors>
Spring Boot Annotations
-
@SpringBootApplication
@SpringBootApplication 包含@Configuration、@EnableAutoConfiguration、@ComponentScan
@SpringBootApplication class VehicleFactoryApplication { public static void main(String[] args) { SpringApplication.run(VehicleFactoryApplication.class, args); } } -
@EnableAutoConfiguration
It means that Spring Boot looks for auto-configuration beans on its classpath and automatically applies them.
注意:必须与@Configuration 注解一起使用
@Configuration @EnableAutoConfiguration class VehicleFactoryConfig {}
Auto-Configuration Conditions
-
@ConditionalOnClass and @ConditionalOnMissingClass
the annotation’s argument is present/absent
@Configuration @ConditionalOnClass(DataSource.class) class MySQLAutoconfiguration { //... } -
@ConditionalOnBean and @ConditionalOnMissingBean
the presence or absence of a specific bean
@Bean @ConditionalOnBean(name = "dataSource") LocalContainerEntityManagerFactoryBean entityManagerFactory() { // ... } -
@ConditionalOnProperty
values of properties
@Bean @ConditionalOnProperty( name = "usemysql", havingValue = "local" ) DataSource dataSource() { // ... } -
@ConditionalOnResource
a specific resource is present:
@ConditionalOnResource(resources = "classpath:mysql.properties") Properties additionalProperties() { // ... } -
@ConditionalOnWebApplication and @ConditionalOnNotWebApplication
the current application is or isn’t a web application
@ConditionalOnWebApplication HealthCheckController healthCheckController() { // ... } -
@ConditionalExpression
the SpEL expression is evaluated to true
@Bean @ConditionalOnExpression("${usemysql} && ${mysqlserver == 'local'}") DataSource dataSource() { // ... } -
@Conditional
For even more complex conditions, we can create a class evaluating the custom condition. We tell Spring to use this custom condition with @Conditional
@Conditional(HibernateCondition.class) Properties additionalProperties() { //... }
Spring Scheduling Annotations
-
@EnableAsync
定义异步执行功能,必须与@Configuration 一起使用
@Configuration @EnableAsync class VehicleFactoryConfig {}执行@Async 定义的方法
-
@EnableScheduling
必须与@Configuration 一起使用
@Configuration @EnableScheduling class VehicleFactoryConfig {}执行@Scheduled 定义的方法
-
@Async
@Async void repairCar() { // ... }使用@Async 定义的方法要遵循以下限制
- 必须是 public 方法
- 同一类中,自调用不起作用,也就是同一类中,直接调用另一个异步方法不起作用
-
@Scheduled
@Scheduled(fixedRate = 10000) void checkVehicle() { // ... }@Scheduled(fixedRate = 10000) @Scheduled(cron = "0 * * * * MON-FRI") void checkVehicle() { // ... }注意:使用@Scheduled 注解的方法返回类型应该是 void 类型的
-
@Schedules
@Schedules({ @Scheduled(fixedRate = 10000), @Scheduled(cron = "0 * * * * MON-FRI") }) void checkVehicle() { // ... }
Spring Bean Annotations
-
@ComponentScan
@Configuration @ComponentScan(basePackages = "com.baeldung.annotations") class VehicleFactoryConfig {}@Configuration @ComponentScan(basePackageClasses = VehicleFactoryConfig.class) class VehicleFactoryConfig {}@Configuration @ComponentScan(basePackages = "com.baeldung.annotations") @ComponentScan(basePackageClasses = VehicleFactoryConfig.class) class VehicleFactoryConfig {}@Configuration @ComponentScans({ @ComponentScan(basePackages = "com.baeldung.annotations"), @ComponentScan(basePackageClasses = VehicleFactoryConfig.class) }) class VehicleFactoryConfig {}使用XML方法
<context:component-scan base-package="com.baeldung" /> -
@Component
@Component class CarUtility { // ... } -
@Repository
@Repository class VehicleRepository { // ... } -
@Service
@Service public class VehicleService { // ... } -
@Controller
@Controller public class VehicleController { // ... } -
@Configuration
@Configuration class VehicleFactoryConfig { @Bean Engine engine() { return new Engine(); } }
AOP注解
@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;
}
}