1.注解的作用
-
编译检查:一些注解可以帮助编译器检测错误或者抑制警告。例如,
@Override
用于标明一个方法重写了父类中的方法,如果该方法签名不正确,编译器会报错;@SuppressWarnings
则用于告诉编译器忽略特定的警告信息。 -
生成文档:虽然不是直接通过注解实现,但是类似于Javadoc这样的工具可以通过自定义注解来增强API文档的生成能力。
-
代码生成:某些框架和工具可以根据注解来自动生成代码。例如,Lombok通过注解减少样板代码的编写,比如
@Data
注解可以自动生成getter、setter、toString等方法。 -
配置与依赖注入:Spring等框架广泛使用注解进行配置和依赖注入。例如,
@Autowired
用于自动装配依赖对象,而@Component
,@Service
,@Repository
等用于标识可被Spring容器管理的组件。 -
AOP(面向切面编程):注解可用于定义切点和通知,使得横切关注点(如日志记录、事务管理等)可以以声明式的方式应用到业务逻辑中。例如,在Spring AOP中,可以用
@Aspect
,@Before
,@After
等注解来定义切面。 -
运行时处理:有些注解在运行时也是有效的,并且可以通过反射机制来访问。例如,JPA(Java Persistence API)中的
@Entity
,@Table
,@Column
等注解用于映射Java对象到数据库表,ORM框架在运行时会读取这些注解来进行相应的持久化操作。 -
测试:JUnit等测试框架利用注解简化测试用例的编写和执行。例如,
@Test
用于标注测试方法,@BeforeEach
和@AfterEach
分别用于指定在每个测试方法之前和之后执行的操作。
2.如何自定义注解
2.1.为什么需要自定义注解?
在Java开发中,我们经常使用像 @Override
、@Deprecated
这样的系统自带注解。但有时候我们需要根据自己的业务需求来标记某些方法或类,这时就需要 自定义注解。
例如:
- 标记某个方法需要记录日志
- 表示某个方法需要权限验证
- 指定某个类是核心业务类
2.2.自定义注解的基本语法
import java.lang.annotation.*;
@Target(ElementType.METHOD) // 指定注解的作用目标
@Retention(RetentionPolicy.RUNTIME) // 指定注解保留到运行时
public @interface Log {
}
2.3.元注解说明(Meta Annotations)
创建注解时,用来修饰注解本身的注解叫做 元注解。Java 中常用的元注解有以下几个:
元注解 | 作用 |
---|---|
@Target | 指定该注解可以用于哪些地方(如方法、类、字段等) |
@Retention | 指定该注解的生命周期(源码期、编译期、运行时) |
@Documented | 表示该注解将被包含在生成的 Javadoc 文档中 |
@Inherited | 表示子类可以继承父类上的注解 |
@Repeatable | Java 8+ 支持,表示该注解可以在同一位置重复使用 |
示例:带属性的自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
String value() default "INFO"; // 可以设置默认值
int level() default 1;
}
使用方式:
@Log("DEBUG")
public void debugMethod() {
// ...
}
@Log(level = 3)
public void warnMethod() {
// ...
}
2.4.RetentionPolicy 生命周期详解
生命周期类型 | 含义 |
---|---|
SOURCE | 注解只保留在源码中,编译时丢弃(如 @Override ) |
CLASS | 注解在编译时保留,但运行时不可见(默认行为) |
RUNTIME | 注解在运行时依然存在,可以通过反射读取(最常用) |
✅ 推荐:如果你希望在运行时通过反射处理注解(比如做AOP日志记录),一定要使用
@Retention(RetentionPolicy.RUNTIME)
。
2.5.Target ElementType 类型一览
ElementType 类型 | 可用范围 |
---|---|
METHOD | 方法 |
TYPE | 类、接口、枚举 |
FIELD | 字段(成员变量) |
PARAMETER | 方法参数 |
CONSTRUCTOR | 构造函数 |
LOCAL_VARIABLE | 局部变量 |
ANNOTATION_TYPE | 注解类型 |
PACKAGE | 包 |
2.6.如何使用自定义注解?(结合反射)
要真正发挥自定义注解的作用,通常需要配合 反射机制 或 AOP(面向切面编程) 来实现。
示例:使用反射检查方法是否有 @Log 注解
public class AnnotationTest {
@Log
public void testMethod() {
System.out.println("执行了一个需要记录日志的方法");
}
public static void main(String[] args) throws Exception {
Method method = AnnotationTest.class.getMethod("testMethod");
if (method.isAnnotationPresent(Log.class)) {
System.out.println("该方法需要记录日志!");
}
}
}
2.7.、实际应用场景举例
应用场景 | 使用方式 |
---|---|
日志记录 | 使用 AOP 拦截带有 @Log 的方法并打印日志 |
权限控制 | 拦截带有 @Permission("admin") 的方法,判断用户权限 |
缓存管理 | 使用 @Cacheable 标记可缓存的方法 |
参数校验 | 使用 @Validate 实现自动参数校验逻辑 |
2.8.注意事项
- 注解不能直接执行代码,必须配合反射、AOP或其他框架才能发挥作用。
- 尽量保持注解简洁清晰,避免复杂逻辑放在注解中。
- 合理使用默认值,让注解更易用。
- 注意性能问题:频繁反射操作会影响性能,建议做好缓存处理。
- 版本兼容性:一旦发布为公共API,修改注解结构需谨慎。
总结
自定义注解是一种轻量级的元数据标记方式,通过
@Target
和@Retention
控制其作用范围和生命周期,再结合反射或AOP技术,可以实现日志、权限、缓存等通用功能的优雅封装。
3.常用的注解
-
@SpringBootApplication
- 用于启动SpringBoot应用程序的入口类。它不仅启动了应用程序,还自动配置spring应用所需的各种组件
-
@RestController
- 用于标记一个类,表明该类是一个控制器,且返回的数据会自动以JSON格式进行响应,适用于构建RESTful API
-
@RestController
- 用于标记一个方法或类,指定请求的URL映射,支持多种HTTP请求方式(GET、PSOST、PUT、DELETE等)
-
@GetMapping
- 用于标记一个方法,表示该方法处理HTTP GET请求的URL映射,用于查询资源
-
@PostMapping
- 用于标记一个方法,表示该方法处理HTTP POST请求的URL映射,用于创建或提交数据
-
@PutMapping
- 用于标记一个方法,表示该方法处理HTTP PUT请求的URL映射,用于更新资源
-
@DeleteMapping
- 用于标记一个方法,表示该方法处理HTTP DELETE请求的URL映射,用于删除资源
-
@RequestParam
- 用于从 HTTP 请求的查询参数中提取数据
- 适用于接收 URL 中的参数,例如:
/user?id=123
- 可通过
required
属性设置参数是否必须
-
@RequestBody
- 将 HTTP 请求体中的数据自动绑定并转换为 Java 对象
- 常用于接收 JSON 或 XML 格式的请求数据
- 通常与
@PostMapping
配合使用
-
@ResponseBody
- 标识方法的返回值直接写入 HTTP 响应体
- 常用于返回 JSON 或 XML 格式的数据
- 通常与
@RestController
或@Controller
配合使用
-
@PathVariable
- 从 URL 模板中提取路径变量的值
- 适用于 RESTful 风格的 URL,例如:
/user/{id}
- 可通过
name
或value
属性指定路径变量名
-
@Autowired
- 自动将 Spring 容器中的 Bean 注入到当前类
- 可标注在字段、构造方法或 setter 方法上
- 默认按类型匹配,若存在多个同类型 Bean 需配合
@Qualifier
-
@Value
- 将配置文件中的属性值注入到字段中
- 支持 SpEL 表达式,例如:
@Value("${app.name}")
- 适用于管理动态配置信息
-
@Bean
- 定义由 Spring 容器管理的 Bean
- 通常标注在配置类的方法上
- 方法返回值即为 Bean 实例
-
@Scope
- 指定 Bean 的作用域
- 常用作用域:
singleton
(默认,单例)prototype
(原型,每次注入新实例)request
(每次 HTTP 请求新实例)session
(每个用户会话新实例)
-
@Primary
- 标记优先注入的 Bean,当存在多个相同类型的 Bean 时,优先注入带有此注解的实例
- 常用于解决
@Autowired
注入时的歧义性问题 - 通常与
@Component
或@Bean
配合使用
- @Transactional
- 声明式事务管理注解,确保方法内的操作要么全部成功,要么全部回滚
- 支持配置:
propagation
(事务传播行为)isolation
(事务隔离级别)rollbackFor
(指定回滚的异常类型)
- 可标注在类或方法上
- @EnableAspectJAutoProxy
- 启用基于 AspectJ 的自动代理功能
- 核心 AOP 配置注解,需在配置类上使用
- 默认使用 JDK 动态代理,可设置
proxyTargetClass=true
强制使用 CGLIB
- @Aspect
- 定义切面类,包含切入点(Pointcut)和增强逻辑(Advice)
- 常用组合注解:
@Before
(方法执行前增强)@AfterReturning
(方法正常返回后增强)@Around
(环绕增强)
- 需配合
@Component
注册为 Spring Bean
- @Scheduled
- 声明定时任务,支持固定速率(fixedRate)、固定延迟(fixedDelay)和 Cron 表达式
- 示例:
@Scheduled(cron = "0 0/5 * * * ?") // 每5分钟执行
- 需在主类添加
@EnableScheduling
启用定时任务功能
- @EnableCaching
- 启用 Spring 缓存抽象功能
- 需配置缓存管理器(如 RedisCacheManager)
- 通常放在主配置类上
- @Cacheable
- 标记方法的返回值可被缓存
- 核心属性:
value/cacheNames
(指定缓存名称)key
(自定义缓存键生成规则)condition
(缓存条件表达式)
- 示例:
@Cacheable(value="users", key="#userId")
- @CacheEvict
- 用于清除缓存条目,支持按条件删除
- 常用属性:
value/cacheNames
(指定要清除的缓存名称)key
(指定删除的缓存键)allEntries=true
(清空整个缓存)
- 典型场景:数据修改后同步清理缓存
- @CachePut
- 强制更新缓存,始终执行方法并将结果写入缓存
- 与
@Cacheable
的区别:@Cacheable
:缓存命中时跳过方法执行@CachePut
:始终执行方法并更新缓存
- 适用场景:数据更新后需要立即刷新缓存
- @Controller
- 标记类为 Spring MVC 控制器
- 核心特性:
- 配合
@RequestMapping
处理 HTTP 请求 - 默认返回视图名称(需模板引擎支持)
- 与
@ResponseBody
组合可返回 JSON
- 配合
- @EnableWebSecurity
- 启用 Spring Security 安全框架
- 必须配合配置类使用:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter
- 提供认证(Authentication)和授权(Authorization)功能
- @Secured
- 基于角色的方法级权限控制
- 示例:
@Secured("ROLE_ADMIN") // 仅允许 ADMIN 角色访问
- 需在配置类启用:
@EnableGlobalMethodSecurity(securedEnabled=true)
- @PreAuthorize
- 支持 SpEL 表达式的细粒度权限控制
- 优势:
- 可组合复杂条件(如
@PreAuthorize("hasRole('ADMIN') or #userId == principal.id")
) - 支持方法参数引用(如
#userId
)
- 可组合复杂条件(如
- 启用要求:
@EnableGlobalMethodSecurity(prePostEnabled=true)
- @RestControllerAdvice
- 统一处理 RESTful API 异常
- 核心功能:
- 配合
@ExceptionHandler
捕获特定异常 - 可自定义错误响应体结构
- 配合
- 与
@ControllerAdvice
的区别:- 默认包含
@ResponseBody
语义
- 默认包含
- @Test
- 标记 JUnit 测试方法
- 关键特性:
- 支持断言(Assertions)验证结果
- 可与
@SpringBootTest
结合进行集成测试
- 生命周期注解:
@BeforeEach
/@AfterEach
- @MockBean
- 在 Spring 测试环境中模拟 Bean
- 典型用途:
- 替代数据库访问等复杂依赖
- 配合 Mockito 定义模拟行为
- 示例:
@MockBean private UserService userService;
- @SpringBootTest
- 启动完整的 Spring Boot 应用上下文进行集成测试
- 关键特性:
- 加载所有
@Component
Bean - 支持
@MockBean
模拟特定依赖 - 可配置
webEnvironment
模式(如MOCK
或RANDOM_PORT
)
- 加载所有
- 典型用法:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
- @DataJpaTest
- 专注测试 JPA 持久层,自动配置:
- 内存数据库(H2 默认)
EntityManager
- Spring Data JPA 仓库
- 优化:
- 仅扫描
@Entity
和@Repository
类 - 默认事务回滚(测试后不污染数据库)
- 仅扫描
- @WebMvcTest
- 切片测试 Web 层,特点:
- 只加载
@Controller
、@RestController
等 MVC 组件 - 自动配置
MockMvc
模拟 HTTP 请求 - 排除
@Service
、@Repository
等非 Web 组件
- 只加载
- 示例:
@WebMvcTest(UserController.class)
- @Entity
- 标记类为 JPA 实体,对应数据库表
- 规则:
- 默认表名 = 类名(可用
@Table(name="")
覆盖) - 必须有无参构造函数
- 字段默认自动映射(
@Column
可自定义)
- 默认表名 = 类名(可用
- @Id
- 标识实体类的主键字段
- 必须与
@Entity
配合使用 - 主键类型支持:
- 基本类型(
Long
,Integer
等) - 复合主键(需定义
@Embeddable
类)
- 基本类型(
- @GeneratedValue
- 指定主键生成策略,常用:
GenerationType.IDENTITY
(数据库自增)GenerationType.SEQUENCE
(序列)GenerationType.UUID
(通用唯一标识)
- 示例:
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column
- 自定义字段与列的映射,支持:
name
(列名)nullable
(是否允许为空)length
(字符串长度限制)unique
(唯一约束)
- 默认规则:
- 字段名 = 列名(驼峰转下划线)
- @JoinColumn
- 定义外键列,用于实体关联,属性:
name
(外键列名)referencedColumnName
(引用目标表的列名)
- 必须与关联注解(如
@ManyToOne
)配合使用
- @ManyToOne
- 定义多对一关联,典型场景:
- 多个订单属于一个用户 →
Order
实体中定义@ManyToOne User user
- 多个订单属于一个用户 →
- 级联操作:
cascade = CascadeType.PERSIST
(级联保存)fetch = FetchType.LAZY
(懒加载)
- @OneToMany
- 定义一对多关联关系(如:一个部门对应多个员工)
- 必须与
@ManyToOne
成对使用 - 常用属性:
mappedBy
(指定对方实体中的关联属性)cascade
(级联操作类型)fetch
(加载策略,默认LAZY
)
- @ManyToMany
- 建立多对多关系(如:学生与课程)
- 实现方式:
- 通过
@JoinTable
定义中间表 - 或使用
mappedBy
指定维护方
- 通过
- 注意:
- 避免循环引用
- 推荐设置中间实体替代
- @JoinTable
- 自定义多对多关联的中间表
- 核心属性:
name
(中间表名)joinColumns
(当前实体外键)inverseJoinColumns
(关联实体外键)
- 示例:
@JoinTable(name = "student_course", joinColumns = @JoinColumn(name = "student_id"), inverseJoinColumns = @JoinColumn(name = "course_id"))
- @MappedSuperclass
- 定义可继承的映射超类(不会生成单独的表)
- 典型用途:
- 公共字段(
id
,create_time
等) - 需配合
@EntityListeners
实现审计功能
- 公共字段(
- 与
@Entity
的区别:- 不能单独作为实体查询
- @Inheritance
- 指定实体继承策略,支持:
SINGLE_TABLE
(单表继承,默认)JOINED
(每个类独立表)TABLE_PER_CLASS
(每个具体类独立表)
- 必须与
@DiscriminatorColumn
配合使用
- @EnableTransactionManagement
- 启用声明式事务管理(默认已启用)
- 关键机制:
- 基于 AOP 代理实现
- 方法调用自动开启/提交事务
- 注意事项:
- 同类方法调用不会触发事务
- @EnableJpaAuditing
- 激活 JPA 审计功能
- 需配合注解使用:
@CreatedDate
@LastModifiedDate
@CreatedBy
- 配置要求:
- 主类添加
@EntityListeners(AuditingEntityListener.class)
- 主类添加
- @CreatedDate
- 自动填充实体创建时间
- 使用条件:
- 字段类型为
LocalDateTime
/Date
- 已启用
@EnableJpaAuditing
- 字段类型为
- 示例:
@CreatedDate private LocalDateTime createTime;
- @LastModifiedDate
- 自动记录实体最后修改时间
- 使用要求:
- 需配合
@EnableJpaAuditing
启用审计 - 字段类型为时间类型(如
LocalDateTime
)
- 需配合
- 典型场景:
@LastModifiedDate private LocalDateTime updateTime;
- @PrePersist
- 实体插入数据库前触发
- 常见用途:
- 初始化默认值
- 生成业务编码
- 示例:
@PrePersist public void prePersist() { this.createTime = LocalDateTime.now(); }
- @PreUpdate
- 实体更新数据库前触发
- 典型应用:
- 自动更新修改时间
- 数据版本校验
- 注意:
- 不适用于新增操作
- @PostPersist
- 实体插入数据库后触发
- 适用场景:
- 发送事件通知
- 更新关联数据
- 与
@PrePersist
的区别:- 已生成数据库主键
- @PostUpdate
- 实体更新数据库后触发
- 常用作:
- 记录操作日志
- 同步缓存数据
- 事务特性:
- 仍在同一事务中执行
- @PreRemove
- 实体删除前触发
- 核心用途:
- 验证删除条件
- 清理关联资源
- 危险操作:
- 避免在此方法中修改其他实体状态
- @PreFlush
- JPA 执行 flush 操作前触发
- 特殊场景:
- 批量操作前的最后校验
- 临时状态调整
- 触发时机:
entityManager.flush()
- 事务提交前自动触发
- @PostRemove
- 实体删除后触发
- 典型应用:
- 删除文件附件
- 更新统计信息
- 注意事项:
- 实体已从数据库移除
- @PostFlush
- JPA 执行 flush 操作后触发
- 高级用途:
- 跨系统数据同步
- 二级缓存维护
- 执行特点:
- 可能触发多次(每次 flush)
- @Before
- 定义AOP前置通知,在目标方法执行前触发
- 典型用途:
- 参数校验
- 权限检查
- 日志记录
- 示例:
@Before("execution(* com.example.service.*.*(..))") public void beforeAdvice(JoinPoint jp) { log.info("准备执行: " + jp.getSignature()); }
- @After
- 定义AOP后置通知,在目标方法执行后触发(无论是否抛出异常)
- 与
@AfterReturning
的区别:- 不关心方法返回值
- 总会执行(类似
finally
块)
- 适用场景:
- 资源清理
- 执行耗时统计
- @AfterReturning
- 定义AOP返回通知,仅在方法正常返回时触发
- 可获取返回值:
@AfterReturning(pointcut = "execution(* getUser(..))", returning = "result") public void logResult(Object result) { log.info("方法返回: " + result); }
- @AfterThrowing
- 定义AOP异常通知,方法抛出异常时触发
- 可捕获特定异常:
@AfterThrowing(pointcut = "serviceLayer()", throwing = "ex") public void handleException(DataAccessException ex) { alertService.sendErrorAlert(ex); }
- @EnableScheduling
- 启用Spring定时任务功能
- 必须添加到配置类:
@Configuration @EnableScheduling public class ScheduledConfig { ... }
- 配合
@Scheduled
使用:@Scheduled(fixedRate = 5000) // 每5秒执行 public void reportMetrics() { ... }
- @Async
- 标记方法为异步执行(默认使用SimpleAsyncTaskExecutor)
- 注意事项:
- 需在主类添加
@EnableAsync
- 调用方和被调方必须在不同类(自调用无效)
- 需在主类添加
- 示例:
@Async public void asyncProcess() { // 长时间任务... }
- @EnableAsync
- 开启Spring异步执行能力
- 可自定义线程池:
@Bean public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); return executor; }
- @EventListener
- 声明事件监听方法,支持:
- 应用自定义事件
- Spring内置事件(如
ContextRefreshedEvent
)
- 示例:
@EventListener public void handleOrderEvent(OrderCreatedEvent event) { notificationService.send(event.getOrder()); }
- @PostConstruct
- 在 Bean 初始化完成后立即执行(依赖注入之后)
- 典型用途:
- 加载缓存数据
- 初始化连接池
- 验证配置完整性
- 示例:
@PostConstruct public void init() { this.cache = loadCacheFromDB(); }
- @PreDestroy
- 在 Bean 销毁前执行(容器关闭时)
- 核心场景:
- 关闭文件句柄
- 释放网络连接
- 清理临时文件
- 注意事项:
- 不适用于原型(prototype)作用域的 Bean
- @RequestHeader
- 从 HTTP 请求头提取参数
- 常用属性:
name
/value
(指定头字段名)required
(是否必须,默认 true)defaultValue
(默认值)
- 示例:
public ResponseEntity<?> api( @RequestHeader("User-Agent") String userAgent, @RequestHeader(value = "X-Token", required = false) String token )
- @CookieValue
- 获取请求中的 Cookie 值
- 特殊配置:
- 支持 Spring EL 表达式(如
@CookieValue("${cookie.name}")
)
- 支持 Spring EL 表达式(如
- 典型应用:
- 会话跟踪
- 主题偏好读取
- @ModelAttribute
- 双重作用:
- 方法级:在控制器方法前执行,准备模型数据
@ModelAttribute public void addCommonModel(Model model) { model.addAttribute("serverTime", LocalDateTime.now()); }
- 参数级:绑定请求参数到对象
public String submit(@ModelAttribute User user)
- 方法级:在控制器方法前执行,准备模型数据
- @SessionAttributes
- 在 HTTP 会话 中保存模型数据
- 需配合
@Controller
使用:@Controller @SessionAttributes("cart") public class CartController { @ModelAttribute("cart") public ShoppingCart initCart() { return new ShoppingCart(); } }
- 生命周期:
- 直到调用
SessionStatus.setComplete()
- 直到调用
- @ExceptionHandler
- 捕获控制器内的异常并统一处理
- 特点:
- 支持多种异常类型(
@ExceptionHandler({AException.class, BException.class})
) - 可返回自定义错误响应体
- 支持多种异常类型(
- 示例:
@ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) { return ResponseEntity.status(404).body(new ErrorResponse(ex.getMessage())); }
- @ResponseStatus
- 自定义 HTTP 响应状态码
- 两种用法:
- 标记异常类:
@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "资源不存在") public class ResourceNotFoundException extends RuntimeException {}
- 标注控制器方法:
@ResponseStatus(HttpStatus.CREATED) @PostMapping public void create() { ... }
- 标记异常类:
- @Around
- 功能最强的 AOP 通知类型,可 完全控制 目标方法执行
- 核心能力:
- 修改参数
- 跳过原方法执行
- 捕获异常
- 修改返回值
- 示例(方法耗时统计):
@Around("execution(* com.example.service.*.*(..))") public Object logExecutionTime(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); Object result = pjp.proceed(); log.info("方法执行耗时: " + (System.currentTimeMillis() - start) + "ms"); return result; }
关键对比:
@PostConstruct
vs@Autowired
:@Autowired
完成依赖注入@PostConstruct
在注入后执行初始化逻辑
@ModelAttribute
方法级 vs 参数级:- 方法级:每次请求前执行
- 参数级:绑定请求数据到对象
@Around
与其他通知:- 唯一能完全控制方法执行的切面类型
- 必须调用
ProceedingJoinPoint.proceed()
继续执行原方法
- @ConditionalOnClass
- 用途:
- 条件化地配置Spring应用程序上下文中的Bean。仅当指定类存在于类路径上时,被注解的组件(如配置类或@Bean方法)才会生效。
- 核心特性:
- 确保特定功能仅在所需库存在时启用。
- 防止因缺少依赖导致的应用启动失败。
- 示例
- 当项目中引入 Jackson 依赖后,ObjectMapper 才会被自动注入到 Spring 容器
- 若项目未引入 Jackson 相关 JAR 包,则该配置类会被自动跳过
- 当且仅当类路径中存在 com.fasterxml.jackson.databind.ObjectMapper 类时,才会创建被该注解标注的 @Configuration 配置类或 @Bean 方法。
@Configuration
@ConditionalOnClass(ObjectMapper.class)
public class JsonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return jacksonObjectMapperBuilder -> {
// long -> string
jacksonObjectMapperBuilder.serializerByType(Long.class, ToStringSerializer.instance);
jacksonObjectMapperBuilder.serializerByType(BigInteger.class, ToStringSerializer.instance);
};
}
}