Java 常用注解
·
本文档按框架分类整理了Java开发中最常用的注解,涵盖Spring、Spring Boot、Redis、MySQL/JPA等框架,每个注解都配有详细说明和使用示例。
一、Spring Framework 核心注解
1.1 组件声明注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@Component |
通用组件注解,标记类为Spring管理的Bean | 类 |
@Service |
标记业务逻辑层组件,语义更明确 | 类 |
@Repository |
标记数据访问层组件,自动转换持久层异常 | 类 |
@Controller |
标记Web控制器,用于MVC模式 | 类 |
@RestController |
组合注解(@Controller + @ResponseBody),用于RESTful API | 类 |
@Configuration |
标记配置类,相当于XML配置文件 | 类 |
示例:
@Service
public class UserService {
public User findById(Long id) {
// 业务逻辑
return userRepository.findById(id).orElse(null);
}
}
@Repository
public class UserRepository {
// 数据访问逻辑,自动转换SQL异常为Spring的DataAccessException
}
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
}
1.2 依赖注入注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@Autowired |
按类型自动装配Bean | 字段、构造器、Setter方法 |
@Qualifier |
指定具体Bean名称,配合@Autowired使用 | 字段、参数 |
@Resource |
JSR-250标准注解,默认按名称注入 | 字段、Setter方法 |
@Value |
注入配置属性值或SpEL表达式 | 字段、参数 |
@Inject |
JSR-330标准注解,类似@Autowired | 字段、构造器、方法 |
示例:
@Service
public class OrderService {
// 构造器注入(推荐方式)
private final UserRepository userRepository;
private final PaymentService paymentService;
@Autowired
public OrderService(UserRepository userRepository,
@Qualifier("alipayService") PaymentService paymentService) {
this.userRepository = userRepository;
this.paymentService = paymentService;
}
@Value("${app.name:defaultName}")
private String appName;
@Value("#{systemProperties['java.home']}")
private String javaHome;
}
// JSR-250 示例
public class NotificationService {
@Resource(name = "emailService")
private MessageService messageService;
}
1.3 作用域与生命周期注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@Scope |
指定Bean作用域(singleton/prototype/request/session) | 类 |
@PostConstruct |
标记初始化方法,在依赖注入后执行 | 方法 |
@PreDestroy |
标记销毁方法,在容器关闭前执行 | 方法 |
@Lazy |
延迟初始化Bean | 类、字段 |
@DependsOn |
指定Bean初始化顺序依赖 | 类 |
示例:
@Component
@Scope("prototype") // 每次请求创建新实例
@DependsOn("databaseConfig") // 确保databaseConfig先初始化
public class PrototypeBean {
@PostConstruct
public void init() {
System.out.println("Bean初始化完成");
}
@PreDestroy
public void destroy() {
System.out.println("Bean即将销毁");
}
}
1.4 AOP相关注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@Aspect |
标记切面类 | 类 |
@Pointcut |
定义切点表达式 | 方法 |
@Before |
前置通知 | 方法 |
@After |
后置通知 | 方法 |
@AfterReturning |
返回通知 | 方法 |
@AfterThrowing |
异常通知 | 方法 |
@Around |
环绕通知 | 方法 |
示例:
@Aspect
@Component
public class LoggingAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
@Before("serviceLayer()")
public void logBefore(JoinPoint joinPoint) {
System.out.println("调用方法: " + joinPoint.getSignature().getName());
}
@Around("serviceLayer()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - start;
System.out.println("方法执行耗时: " + duration + "ms");
return result;
}
}
二、Spring Boot 专属注解
2.1 启动与配置注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@SpringBootApplication |
组合注解(@Configuration + @EnableAutoConfiguration + @ComponentScan) | 主类 |
@EnableAutoConfiguration |
启用自动配置机制 | 类 |
@ComponentScan |
配置组件扫描路径 | 类 |
@SpringBootConfiguration |
标记Spring Boot配置类 | 类 |
@EnableConfigurationProperties |
启用@ConfigurationProperties配置类 | 类 |
示例:
@SpringBootApplication(
scanBasePackages = {"com.example", "com.shared"},
exclude = {DataSourceAutoConfiguration.class} // 排除特定自动配置
)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.2 属性配置注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@ConfigurationProperties |
批量绑定配置属性到POJO | 类 |
@PropertySource |
指定自定义属性文件 | 类 |
@PropertySources |
指定多个属性文件 | 类 |
@Profile |
指定环境配置(dev/test/prod) | 类、方法 |
示例:
// application.yml
# aliyun:
# oss:
# endpoint: oss-cn-hangzhou.aliyuncs.com
# accessKeyId: your-id
# accessKeySecret: your-secret
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class OssProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
// getters and setters
}
// 使用
@Service
public class OssService {
@Autowired
private OssProperties ossProperties;
}
// 多环境配置
@Configuration
@Profile("production")
public class ProductionConfig {
// 生产环境特定配置
}
2.3 条件装配注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@ConditionalOnProperty |
当配置属性满足条件时生效 | 类、方法 |
@ConditionalOnClass |
当类路径存在指定类时生效 | 类、方法 |
@ConditionalOnMissingClass |
当类路径不存在指定类时生效 | 类、方法 |
@ConditionalOnBean |
当容器中存在指定Bean时生效 | 类、方法 |
@ConditionalOnMissingBean |
当容器中不存在指定Bean时生效 | 类、方法 |
@ConditionalOnWebApplication |
当是Web应用时生效 | 类、方法 |
@Conditional |
自定义条件判断 | 类、方法 |
示例:
@Configuration
public class ConditionalConfig {
@Bean
@ConditionalOnProperty(name = "feature.cache.enabled", havingValue = "true")
public CacheService cacheService() {
return new RedisCacheService();
}
@Bean
@ConditionalOnClass(name = "com.mysql.jdbc.Driver")
@ConditionalOnMissingBean(DataSource.class)
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
三、Spring Web MVC 注解
3.1 请求映射注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@RequestMapping |
通用请求映射,可指定路径、方法、参数等 | 类、方法 |
@GetMapping |
处理GET请求 | 方法 |
@PostMapping |
处理POST请求 | 方法 |
@PutMapping |
处理PUT请求 | 方法 |
@DeleteMapping |
处理DELETE请求 | 方法 |
@PatchMapping |
处理PATCH请求 | 方法 |
示例:
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
@GetMapping // GET /api/v1/users
public List<User> listUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return userService.findAll(page, size);
}
@GetMapping("/{id}") // GET /api/v1/users/123
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping // POST /api/v1/users
public ResponseEntity<User> createUser(@Valid @RequestBody UserDTO userDTO) {
User user = userService.create(userDTO);
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(user.getId())
.toUri();
return ResponseEntity.created(location).body(user);
}
@PutMapping("/{id}") // PUT /api/v1/users/123
public User updateUser(@PathVariable Long id, @RequestBody UserDTO userDTO) {
return userService.update(id, userDTO);
}
@DeleteMapping("/{id}") // DELETE /api/v1/users/123
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteUser(@PathVariable Long id) {
userService.delete(id);
}
}
3.2 请求参数处理注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@PathVariable |
从URL路径中提取变量 | 参数 |
@RequestParam |
从查询参数中获取值 | 参数 |
@RequestBody |
将请求体JSON/XML绑定到对象 | 参数 |
@ResponseBody |
将返回值序列化为JSON/XML | 类、方法 |
@RequestHeader |
获取请求头信息 | 参数 |
@CookieValue |
获取Cookie值 | 参数 |
@ModelAttribute |
将表单数据绑定到模型对象 | 参数 |
@SessionAttribute |
获取Session属性 | 参数 |
示例:
@PostMapping("/upload")
public ResponseEntity<String> uploadFile(
@RequestParam("file") MultipartFile file,
@RequestParam(required = false, defaultValue = "false") boolean overwrite,
@RequestHeader("X-Request-ID") String requestId,
@CookieValue(value = "sessionId", required = false) String sessionId) {
// 处理文件上传
return ResponseEntity.ok("File uploaded");
}
@GetMapping("/search")
public List<Product> search(
@RequestParam Map<String, String> allParams, // 获取所有查询参数
@RequestParam MultiValueMap<String, String> multiParams) { // 支持多值参数
// 处理搜索逻辑
return productService.search(allParams);
}
3.3 响应处理注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@ResponseStatus |
指定响应状态码 | 类、方法、异常 |
@ExceptionHandler |
处理特定异常 | 方法 |
@ControllerAdvice |
全局异常处理类 | 类 |
@RestControllerAdvice |
组合注解(@ControllerAdvice + @ResponseBody) | 类 |
@CrossOrigin |
配置跨域访问 | 类、方法 |
示例:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return errors;
}
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleResourceNotFound(ResourceNotFoundException ex) {
return new ErrorResponse(ex.getMessage(), LocalDateTime.now());
}
}
@RestController
@CrossOrigin(origins = "http://localhost:3000", maxAge = 3600)
public class ProductController {
// 控制器方法
}
四、数据验证注解(Bean Validation)
4.1 常用验证注解
| 注解 | 作用 | 适用类型 |
|---|---|---|
@NotNull |
值不能为null | 任意 |
@NotEmpty |
字符串/集合不能为空(null或空) | String, Collection, Map, Array |
@NotBlank |
字符串不能为空白(去空格后长度>0) | String |
@Size |
长度/大小在指定范围内 | String, Collection, Map, Array |
@Min |
数值最小值 | Number |
@Max |
数值最大值 | Number |
@Range |
数值在指定范围内 | Number |
@DecimalMin |
十进制最小值 | BigDecimal, BigInteger等 |
@DecimalMax |
十进制最大值 | BigDecimal, BigInteger等 |
@Positive |
正数(>0) | Number |
@PositiveOrZero |
非负数(>=0) | Number |
@Negative |
负数(<0) | Number |
@NegativeOrZero |
非正数(<=0) | Number |
@Digits |
整数和小数位数限制 | Number |
@Past |
过去日期 | Date, LocalDate等 |
@Future |
未来日期 | Date, LocalDate等 |
@Pattern |
正则表达式匹配 | String |
@Email |
邮箱格式验证 | String |
@AssertTrue |
必须为true | Boolean |
@AssertFalse |
必须为false | Boolean |
@Valid |
级联验证嵌套对象 | 对象 |
@Validated |
分组验证(Spring扩展) | 类、方法、参数 |
示例:
public class UserDTO {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度必须在3-20之间")
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母、数字和下划线")
private String username;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
@NotNull(message = "年龄不能为空")
@Min(value = 18, message = "年龄必须大于等于18岁")
@Max(value = 120, message = "年龄必须小于等于120岁")
private Integer age;
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
@DecimalMin(value = "0.00", inclusive = false, message = "余额必须大于0")
@Digits(integer = 10, fraction = 2, message = "余额格式不正确")
private BigDecimal balance;
@Valid // 级联验证
@NotNull(message = "地址信息不能为空")
private AddressDTO address;
@NotEmpty(message = "至少选择一个角色")
private List<String> roles;
}
// 控制器中使用
@RestController
public class UserController {
@PostMapping("/users")
public ResponseEntity<?> createUser(
@Valid @RequestBody UserDTO userDTO, // @Valid触发验证
BindingResult bindingResult) { // 获取验证结果
if (bindingResult.hasErrors()) {
List<String> errors = bindingResult.getFieldErrors()
.stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage())
.collect(Collectors.toList());
return ResponseEntity.badRequest().body(errors);
}
// 保存用户
return ResponseEntity.ok("用户创建成功");
}
// 分组验证示例
@PutMapping("/users/{id}")
public User updateUser(
@PathVariable Long id,
@Validated(UpdateGroup.class) @RequestBody UserDTO userDTO) {
return userService.update(id, userDTO);
}
}
// 验证分组接口
public interface UpdateGroup {}
public interface CreateGroup {}
五、Spring Data JPA 注解(MySQL等关系型数据库)
5.1 实体映射注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@Entity |
标记类为JPA实体 | 类 |
@Table |
指定映射的数据库表名及约束 | 类 |
@Id |
标记主键字段 | 字段 |
@GeneratedValue |
指定主键生成策略 | 字段 |
@Column |
指定列属性(名称、长度、非空等) | 字段 |
@Transient |
标记字段不持久化到数据库 | 字段 |
@Enumerated |
指定枚举存储方式(STRING/ORDINAL) | 字段 |
@Temporal |
指定日期类型映射(DATE/TIME/TIMESTAMP) | 字段 |
@Lob |
标记大对象字段(BLOB/CLOB) | 字段 |
@Basic |
基本映射配置,可指定延迟加载 | 字段 |
示例:
@Entity
@Table(
name = "sys_user",
uniqueConstraints = {
@UniqueConstraint(columnNames = {"username"}, name = "uk_username"),
@UniqueConstraint(columnNames = {"email"}, name = "uk_email")
},
indexes = {
@Index(columnList = "created_time", name = "idx_created_time"),
@Index(columnList = "status,username", name = "idx_status_username")
}
)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // MySQL自增
private Long id;
@Column(name = "username", nullable = false, length = 50)
private String username;
@Column(name = "email", nullable = false, length = 100)
private String email;
@Column(name = "age", nullable = true)
private Integer age;
@Enumerated(EnumType.STRING) // 以字符串形式存储枚举
@Column(name = "status", length = 20)
private UserStatus status;
@Column(name = "created_time", updatable = false)
@CreationTimestamp // Hibernate自动填充创建时间
private LocalDateTime createdTime;
@Column(name = "updated_time")
@UpdateTimestamp // Hibernate自动填充更新时间
private LocalDateTime updatedTime;
@Lob
@Column(name = "avatar", columnDefinition = "LONGBLOB")
private byte[] avatar;
@Transient // 不保存到数据库
private String tempToken;
// 枚举定义
public enum UserStatus {
ACTIVE, INACTIVE, SUSPENDED
}
}
5.2 关系映射注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@OneToOne |
一对一关系 | 字段 |
@OneToMany |
一对多关系 | 字段 |
@ManyToOne |
多对一关系 | 字段 |
@ManyToMany |
多对多关系 | 字段 |
@JoinColumn |
指定外键列 | 字段 |
@JoinTable |
指定关联表(多对多) | 字段 |
@MappedBy |
指定关系的拥有方 | 字段 |
@Fetch |
指定加载策略(EAGER/LAZY) | 字段 |
@Cascade |
指定级联操作 | 字段 |
示例:
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "dept_name")
private String name;
// 一对多关系:一个部门有多个员工
@OneToMany(mappedBy = "department", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Employee> employees = new ArrayList<>();
}
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "emp_name")
private String name;
// 多对一关系:多个员工属于一个部门
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "dept_id", foreignKey = @ForeignKey(name = "fk_emp_dept"))
private Department department;
// 一对一关系
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "profile_id")
private EmployeeProfile profile;
// 多对多关系:员工参与多个项目
@ManyToMany
@JoinTable(
name = "employee_project",
joinColumns = @JoinColumn(name = "employee_id"),
inverseJoinColumns = @JoinColumn(name = "project_id")
)
private Set<Project> projects = new HashSet<>();
}
5.3 Spring Data Repository 注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@Repository |
标记数据访问层 | 接口 |
@Query |
自定义JPQL或原生SQL查询 | 方法 |
@Param |
指定方法参数名称 | 参数 |
@Modifying |
标记修改操作(update/delete) | 方法 |
@Transactional |
声明事务 | 方法、类 |
@Procedure |
调用存储过程 | 方法 |
@Lock |
指定悲观锁模式 | 方法 |
示例:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 方法名派生查询
List<User> findByUsernameContainingAndStatus(String username, UserStatus status);
// 自定义JPQL查询
@Query("SELECT u FROM User u WHERE u.email = :email AND u.status = :status")
Optional<User> findByEmailAndStatus(@Param("email") String email,
@Param("status") UserStatus status);
// 原生SQL查询
@Query(value = "SELECT * FROM sys_user WHERE created_time > ?1", nativeQuery = true)
List<User> findRecentUsers(LocalDateTime date);
// 更新操作
@Modifying
@Transactional
@Query("UPDATE User u SET u.status = :newStatus WHERE u.id = :userId")
int updateStatus(@Param("userId") Long userId, @Param("newStatus") UserStatus newStatus);
// 分页查询
@Query("SELECT u FROM User u WHERE u.age >= :minAge")
Page<User> findByMinAge(@Param("minAge") int minAge, Pageable pageable);
}
六、Spring Cache + Redis 注解
6.1 缓存核心注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@EnableCaching |
启用Spring缓存抽象 | 配置类 |
@Cacheable |
触发缓存读取,不存在则执行方法并缓存 | 方法 |
@CachePut |
更新缓存(不检查缓存,直接执行方法) | 方法 |
@CacheEvict |
删除缓存 | 方法 |
@Caching |
组合多个缓存操作 | 方法 |
@CacheConfig |
类级别的缓存配置(统一指定cacheNames等) | 类 |
示例:
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10)) // 默认过期时间10分钟
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.withCacheConfiguration("users",
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1))) // users缓存1小时
.transactionAware()
.build();
}
}
@Service
@CacheConfig(cacheNames = "users", keyGenerator = "customKeyGenerator")
public class UserService {
// 查询缓存,key为"users::userId"
@Cacheable(key = "'user:' + #userId", unless = "#result == null")
public User getUserById(Long userId) {
return userRepository.findById(userId).orElse(null);
}
// 更新缓存
@CachePut(key = "'user:' + #user.id")
public User updateUser(User user) {
return userRepository.save(user);
}
// 删除缓存
@CacheEvict(key = "'user:' + #userId")
public void deleteUser(Long userId) {
userRepository.deleteById(userId);
}
// 组合操作:更新用户同时删除用户列表缓存
@Caching(
put = @CachePut(key = "'user:' + #user.id"),
evict = {
@CacheEvict(cacheNames = "userList", allEntries = true),
@CacheEvict(cacheNames = "statistics", key = "'userStats'")
}
)
public User saveAndRefresh(User user) {
return userRepository.save(user);
}
// 条件缓存:仅当用户状态为ACTIVE时缓存
@Cacheable(key = "'activeUsers'", condition = "#status.name() == 'ACTIVE'")
public List<User> findByStatus(UserStatus status) {
return userRepository.findByStatus(status);
}
}
6.2 Redis特定注解(Spring Data Redis)
| 注解 | 作用 | 使用位置 |
|---|---|---|
@RedisHash |
标记实体为Redis Hash存储 | 类 |
@Id |
标记Redis实体ID | 字段 |
@Indexed |
标记字段创建二级索引 | 字段 |
@TimeToLive |
指定过期时间(秒) | 字段 |
@Reference |
引用其他Redis实体 | 字段 |
示例:
@RedisHash("products") // 存储在Redis的Hash中,key前缀为"products"
public class Product {
@Id
private String id;
@Indexed // 创建索引,支持通过name查询
private String name;
@Indexed
private String category;
private BigDecimal price;
@TimeToLive // 过期时间(秒)
private Long expiration;
}
@Repository
public interface ProductRepository extends CrudRepository<Product, String> {
// 自动实现通过索引字段的查询
List<Product> findByCategory(String category);
List<Product> findByNameContaining(String name);
}
七、事务管理注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@Transactional |
声明式事务管理 | 类、方法 |
@Propagation |
指定事务传播行为(REQUIRED/REQUIRES_NEW等) | 方法 |
@Isolation |
指定事务隔离级别 | 方法 |
@Rollback |
测试方法后回滚事务 | 测试方法 |
@Commit |
测试方法后提交事务 | 测试方法 |
示例:
@Service
@Transactional(readOnly = true) // 类级别默认只读
public class OrderService {
@Transactional(
propagation = Propagation.REQUIRED, // 默认传播行为
isolation = Isolation.READ_COMMITTED, // 隔离级别
timeout = 30, // 超时时间(秒)
rollbackFor = {BusinessException.class}, // 指定回滚异常
noRollbackFor = {IllegalArgumentException.class} // 指定不回滚异常
)
public Order createOrder(OrderDTO dto) {
// 1. 扣减库存
inventoryService.deduct(dto.getProductId(), dto.getQuantity());
// 2. 创建订单
Order order = orderRepository.save(convertToEntity(dto));
// 3. 扣减余额
paymentService.charge(dto.getUserId(), dto.getAmount());
return order;
}
// 需要新事务,挂起当前事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog(OrderLog log) {
logRepository.save(log);
}
// 不支持事务,以非事务方式执行
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public Order queryOrder(Long orderId) {
return orderRepository.findById(orderId).orElse(null);
}
}
// 测试中使用
@SpringBootTest
@Transactional // 测试后回滚
public class OrderServiceTest {
@Autowired
private OrderService orderService;
@Test
@Rollback(false) // 不回滚,保留测试数据
public void testCreateOrder() {
// 测试代码
}
}
八、Spring Security 注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@EnableWebSecurity |
启用Spring Security | 配置类 |
@EnableMethodSecurity |
启用方法级安全控制 | 配置类 |
@PreAuthorize |
方法执行前权限验证(SpEL表达式) | 方法 |
@PostAuthorize |
方法执行后权限验证 | 方法 |
@PreFilter |
方法执行前过滤集合参数 | 方法 |
@PostFilter |
方法执行后过滤返回值 | 方法 |
@Secured |
JSR-250角色验证 | 方法、类 |
@RolesAllowed |
JSR-250角色允许 | 方法、类 |
@PermitAll |
允许所有访问 | 方法、类 |
@DenyAll |
拒绝所有访问 | 方法、类 |
@AuthenticationPrincipal |
获取当前认证用户 | 参数 |
示例:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig {
// 安全配置
}
@RestController
public class AdminController {
// 需要ADMIN角色
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin/users")
public List<User> listAllUsers() {
return userService.findAll();
}
// 需要ADMIN或MANAGER角色,且IP限制
@PreAuthorize("hasAnyRole('ADMIN', 'MANAGER') and hasIpAddress('192.168.1.0/24')")
@PostMapping("/admin/users")
public User createUser(@RequestBody UserDTO dto) {
return userService.create(dto);
}
// 基于权限的细粒度控制
@PreAuthorize("hasAuthority('user:write') or (hasAuthority('user:read') and #id == authentication.principal.id)")
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id,
@AuthenticationPrincipal UserDetails currentUser) {
return userService.findById(id);
}
// 方法执行后验证:只能查看自己的订单详情
@PostAuthorize("returnObject.userId == authentication.principal.id or hasRole('ADMIN')")
@GetMapping("/orders/{orderId}")
public Order getOrder(@PathVariable Long orderId) {
return orderService.findById(orderId);
}
// 过滤返回结果:只能看到同部门的数据
@PostFilter("filterObject.departmentId == authentication.principal.departmentId")
@GetMapping("/employees")
public List<Employee> listEmployees() {
return employeeService.findAll();
}
// JSR-250注解
@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
@DeleteMapping("/admin/users/{id}")
public void deleteUser(@PathVariable Long id) {
userService.delete(id);
}
}
九、测试相关注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@SpringBootTest |
集成测试,加载完整应用上下文 | 类 |
@WebMvcTest |
测试Web层,仅加载Controller相关组件 | 类 |
@DataJpaTest |
测试数据访问层,仅加载JPA组件 | 类 |
@MockBean |
创建Mock对象替换Spring容器中的Bean | 字段 |
@SpyBean |
创建Spy对象包装真实Bean | 字段 |
@AutoConfigureMockMvc |
自动配置MockMvc | 类 |
@TestPropertySource |
指定测试配置文件 | 类 |
@ActiveProfiles |
激活特定Profile | 类 |
@Sql |
测试前执行SQL脚本 | 方法、类 |
@DirtiesContext |
测试后清理Spring上下文 | 类、方法 |
@Timed |
限制方法执行时间 | 方法 |
@RepeatedTest |
重复执行测试 | 方法 |
@ParameterizedTest |
参数化测试 | 方法 |
示例:
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
@TestPropertySource(locations = "classpath:application-test.properties")
public class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private EmailService emailService; // Mock外部服务
@Test
@Sql(scripts = "/test-data.sql") // 测试前插入数据
@DirtiesContext // 测试后清理上下文
public void testCreateUser() throws Exception {
UserDTO dto = new UserDTO("test", "test@example.com");
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(dto)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.username").value("test"));
// 验证Mock对象被调用
verify(emailService).sendWelcomeEmail(anyString());
}
}
// Web层单元测试
@WebMvcTest(UserController.class)
public class UserControllerUnitTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
public void testGetUser() throws Exception {
when(userService.findById(1L)).thenReturn(new User("test"));
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username").value("test"));
}
}
// JPA测试
@DataJpaTest
public class UserRepositoryTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository userRepository;
@Test
public void testFindByEmail() {
User user = new User("test", "test@example.com");
entityManager.persist(user);
Optional<User> found = userRepository.findByEmail("test@example.com");
assertThat(found).isPresent();
}
}
十、异步与定时任务注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@EnableAsync |
启用异步方法支持 | 配置类 |
@Async |
标记方法异步执行 | 方法 |
@EnableScheduling |
启用定时任务 | 配置类 |
@Scheduled |
标记定时任务方法 | 方法 |
@Scheduled(fixedRate) |
固定频率执行 | 方法 |
@Scheduled(fixedDelay) |
固定延迟执行 | 方法 |
@Scheduled(cron) |
Cron表达式执行 | 方法 |
示例:
@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfig implements AsyncConfigurer {
@Override
@Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("async-");
executor.initialize();
return executor;
}
}
@Service
public class NotificationService {
// 异步发送邮件,使用默认线程池
@Async
public void sendEmailAsync(String to, String subject, String content) {
// 异步执行
emailClient.send(to, subject, content);
}
// 使用指定线程池
@Async("taskExecutor")
public CompletableFuture<List<Notification>> fetchNotifications(Long userId) {
List<Notification> notifications = notificationRepository.findByUserId(userId);
return CompletableFuture.completedFuture(notifications);
}
}
@Component
public class ScheduledTasks {
// 每5秒执行一次
@Scheduled(fixedRate = 5000)
public void reportCurrentTime() {
System.out.println("当前时间: " + LocalDateTime.now());
}
// 上次执行完成后延迟2秒再执行
@Scheduled(fixedDelay = 2000)
public void processQueue() {
// 处理队列任务
}
// 每天凌晨2点执行
@Scheduled(cron = "0 0 2 * * ?")
public void dailyCleanup() {
// 清理过期数据
}
// 工作日每30分钟执行
@Scheduled(cron = "0 */30 * * * MON-FRI")
public void businessHoursTask() {
// 工作时间任务
}
}
十一、Swagger/OpenAPI 注解(API文档)
| 注解 | 作用 | 使用位置 |
|---|---|---|
@Tag |
API分组标签 | 类 |
@Operation |
接口描述 | 方法 |
@ApiResponse |
响应描述 | 方法 |
@ApiResponses |
多个响应描述 | 方法 |
@Parameter |
参数描述 | 参数 |
@Schema |
模型属性描述 | 类、字段 |
@Hidden |
隐藏接口或字段 | 类、方法、字段 |
示例:
@Tag(name = "用户管理", description = "用户相关操作接口")
@RestController
@RequestMapping("/api/users")
public class UserController {
@Operation(
summary = "创建用户",
description = "根据DTO创建新用户,返回创建后的用户信息",
responses = {
@ApiResponse(responseCode = "201", description = "创建成功"),
@ApiResponse(responseCode = "400", description = "参数校验失败"),
@ApiResponse(responseCode = "409", description = "用户名已存在")
}
)
@PostMapping
public ResponseEntity<User> createUser(
@Valid
@RequestBody
@Parameter(description = "用户信息", required = true)
UserDTO userDTO) {
// 实现
}
@Operation(summary = "根据ID查询用户")
@GetMapping("/{id}")
public User getUser(
@Parameter(description = "用户ID", example = "123")
@PathVariable Long id) {
return userService.findById(id);
}
}
@Schema(description = "用户数据传输对象")
public class UserDTO {
@Schema(description = "用户名", required = true, example = "zhangsan", minLength = 3, maxLength = 20)
@NotBlank
private String username;
@Schema(description = "邮箱", required = true, example = "zhangsan@example.com")
@Email
private String email;
@Schema(description = "年龄", minimum = "18", maximum = "120")
@Min(18)
private Integer age;
}
十二、Lombok 注解(代码生成)
| 注解 | 作用 | 使用位置 |
|---|---|---|
@Getter |
生成getter方法 | 类、字段 |
@Setter |
生成setter方法 | 类、字段 |
@ToString |
生成toString方法 | 类 |
@EqualsAndHashCode |
生成equals和hashCode方法 | 类 |
@NoArgsConstructor |
生成无参构造器 | 类 |
@AllArgsConstructor |
生成全参构造器 | 类 |
@RequiredArgsConstructor |
生成必需参数构造器(final字段) | 类 |
@Data |
组合注解(@Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor) | 类 |
@Builder |
生成建造者模式代码 | 类 |
@Slf4j |
生成SLF4J日志对象 | 类 |
@Log4j2 |
生成Log4j2日志对象 | 类 |
@Value |
生成不可变对象(final类 + 全final字段 + 全参数构造器 + getter) | 类 |
@SneakyThrows |
悄悄抛出受检异常 | 方法 |
示例:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String username;
@Column(nullable = false)
private String email;
@Builder.Default // 设置默认值
private LocalDateTime createdTime = LocalDateTime.now();
@ToString.Exclude // toString中排除
@EqualsAndHashCode.Exclude // equals和hashCode中排除
private String password;
}
// 使用Builder
User user = User.builder()
.username("zhangsan")
.email("zhangsan@example.com")
.build();
@Slf4j
@Service
public class OrderService {
public void processOrder(Order order) {
log.info("Processing order: {}", order.getId());
// 业务逻辑
log.debug("Order details: {}", order);
}
@SneakyThrows(InterruptedException.class) // 无需显式try-catch
public void asyncProcess() {
Thread.sleep(1000);
}
}
十三、Jackson JSON 处理注解
| 注解 | 作用 | 使用位置 |
|---|---|---|
@JsonProperty |
指定JSON属性名 | 字段、方法 |
@JsonIgnore |
忽略字段序列化 | 字段、方法 |
@JsonIgnoreProperties |
忽略多个属性 | 类 |
@JsonFormat |
指定日期/数字格式 | 字段 |
@JsonInclude |
指定包含策略(NON_NULL/NON_EMPTY等) | 类、字段 |
@JsonSerialize |
指定自定义序列化器 | 字段 |
@JsonDeserialize |
指定自定义反序列化器 | 字段 |
@JsonView |
指定视图序列化 | 类、字段、方法 |
示例:
@JsonInclude(JsonInclude.Include.NON_NULL) // 忽略null字段
public class UserDTO {
@JsonProperty("user_id") // JSON中显示为user_id
private Long id;
@JsonIgnore // 不序列化到JSON
private String password;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime createdTime;
@JsonSerialize(using = MoneySerializer.class)
@JsonDeserialize(using = MoneyDeserializer.class)
private BigDecimal balance;
@JsonView(Views.Public.class) // 只在Public视图显示
private String username;
@JsonView(Views.Internal.class) // 只在Internal视图显示
private String phone;
}
// 使用
public class Views {
public static class Public {}
public static class Internal extends Public {}
}
@JsonView(Views.Public.class)
@GetMapping("/users/{id}")
public User getUserPublic(@PathVariable Long id) { ... }
@JsonView(Views.Internal.class)
@GetMapping("/admin/users/{id}")
public User getUserInternal(@PathVariable Long id) { ... }更多推荐




所有评论(0)