
Observes是 Java EE现 Jakarta EE中 CDI (Contexts and Dependency Injection) 规范的核心注解之一用于实现事件驱动架构。它允许 Bean 以松耦合的方式监听和处理其他 Bean 触发的事件。1. 核心概念与作用解耦通信Observes使得事件的发布者Producer和订阅者Observer/Consumer完全解耦。发布者无需知道谁在监听事件只需通过Event.fire()发送消息订阅者只需声明对某种类型事件的兴趣。观察者模式实现它是 CDI 对经典观察者设计模式的标准化实现。类型安全基于 Java 泛型和限定符Qualifiers编译器可以在编译期检查事件类型匹配避免运行时错误。2.基本用法一个观察者方法必须满足以下条件是一个非静态方法。至少有一个参数。 the first parameter must be annotated withObserves.该参数的类型决定了它监听的事件类型。代码示例步骤 1定义事件类事件可以是任何普通的 Java 对象POJO。publicclassUserRegisteredEvent{privateStringusername;privateDateregistrationTime;publicUserRegisteredEvent(Stringusername){this.usernameusername;this.registrationTimenewDate();}publicStringgetUsername(){returnusername;}publicDategetRegistrationTime(){returnregistrationTime;}}步骤 2发布事件在任意 CDI Bean 中注入Event对象并触发。importjavax.enterprise.event.Event;importjavax.inject.Inject;publicclassUserService{InjectprivateEventUserRegisteredEventuserRegisteredEvent;publicvoidregisterUser(Stringusername){// ... 业务逻辑 ...// 触发事件userRegisteredEvent.fire(newUserRegisteredEvent(username));}}步骤 3监听事件使用 Observesimportjavax.enterprise.event.Observes;importjavax.ejb.Stateless;StatelesspublicclassNotificationService{// 当 UserRegisteredEvent 被触发时此方法自动执行publicvoidsendWelcomeEmail(ObservesUserRegisteredEventevent){System.out.println(Sending welcome email to: event.getUsername());// 发送邮件逻辑...}}3. 高级特性A. 使用限定符Qualifiers进行精确匹配如果多个观察者监听同一类型的事件可以使用自定义注解作为限定符来区分。// 定义限定符QualifierRetention(RUNTIME)Target({FIELD,PARAMETER})publicinterfaceUrgent{}// 发布带限定符的事件InjectUrgentEventOrderEventorderEvent;orderEvent.fire(newOrderEvent(...));// 只监听带有 Urgent 限定符的 OrderEventpublicvoidhandleUrgentOrder(ObservesUrgentOrderEventevent){// 处理紧急订单}B. 同步与异步观察同步观察默认Observes默认是同步的。触发事件的线程会阻塞直到所有观察者方法执行完毕。这保证了事务的一致性但可能影响性能。异步观察在 CDI 2.0 (Java EE 8) 中可以使用ObservesAsync注解实现异步监听。观察者将在不同的线程中执行不会阻塞发布者。// 异步监听不阻塞主线程publicvoidlogActivity(ObservesAsyncActivityEventevent){// 记录日志耗时操作不影响主业务流程}C. 事务性观察器Transactional Observer可以指定观察者方法仅在事务的特定阶段执行。这对于确保数据一致性非常有用例如只有在数据库提交成功后才发送通知。importjavax.enterprise.event.TransactionPhase;// 仅在事务成功提交后执行publicvoidsendConfirmation(Observes(duringTransactionPhase.AFTER_SUCCESS)OrderConfirmedEventevent){// 发送确认邮件}可选的事务阶段包括IN_PROGRESS事务进行中默认行为。BEFORE_COMPLETION事务提交前。AFTER_COMPLETION事务完成后无论成功或失败。AFTER_SUCCESS事务成功提交后。AFTER_FAILURE事务回滚后。D. 条件观察器Conditional Observer默认情况下如果观察者 Bean 不存在CDI 容器会先创建它然后调用观察方法。如果你希望只有当 Bean 已经存在时才接收事件可以设置during TransactionPhase.IN_PROGRESS并结合notifyObserver Reception.IF_EXISTSCDI 1.1。importjavax.enterprise.event.Reception;// 只有当 NotificationService 实例已存在时才通知否则忽略事件publicvoidoptionalNotify(Observes(notifyObserverReception.IF_EXISTS)UserEventevent){// ...}4. 执行顺序如果一个事件有多个观察者CDI 规范不保证它们的执行顺序。如果需要控制顺序使用Priority注解CDI 1.1。或者在一个观察者中触发另一个事件形成链式调用。Priority(100)publicvoidfirstHandler(ObservesMyEventevent){...}Priority(200)publicvoidsecondHandler(ObservesMyEventevent){...}注意优先级数值越小越先执行。常见应用场景日志记录将日志逻辑从业务代码中分离通过事件异步记录。缓存更新数据修改后触发事件清除或更新相关缓存。通知系统用户注册、订单状态变更时发送邮件、短信或推送通知。审计追踪记录关键操作的历史。模块间通信在大型应用中不同模块如用户模块、订单模块通过事件交互避免直接依赖。注意事项异常处理如果同步观察者抛出异常该异常会传播回事件发布者可能导致整个事务回滚。异步观察者的异常通常需要通过CompletionStage或全局异常处理器捕获。性能考量同步观察者会增加请求响应时间。对于耗时操作务必使用异步观察 (ObservesAsync) 或将其提交到线程池。循环依赖避免事件触发链形成闭环A 触发 BB 触发 A这会导致无限递归或栈溢出。Bean 生命周期观察者方法所在的 Bean 必须符合其作用域Scope的生命周期规则。例如RequestScoped的 Bean 只能在请求期间观察事件。5.总结Observes是构建松散耦合、可维护且可扩展的企业级 Java 应用的强大工具。它通过标准化的事件机制替代了传统的回调接口或硬编码的服务调用特别适用于处理横切关注点如日志、通知、审计和模块间通信。在使用时应根据业务需求合理选择同步/异步、事务阶段和执行优先级。