闽公网安备 35020302035485号
// 堆代码 duidaima.com
// 贫血模型的典型实现
public class Order {
@Autowired
private PaymentService paymentService; // 违反单一职责原则
public void pay() {
paymentService.process(this);
}
}
@Primary
publicclass SpringContext implements ApplicationContextAware, PriorityOrdered, ApplicationRunner {
privatestatic ApplicationContext applicationContext;
// 初始化完成的信号
privatestaticfinal CountDownLatch INITIALIZATION_LATCH = new CountDownLatch(1);
@Override
public void run(ApplicationArguments args) throws Exception {
// 通知等待的线程初始化已完成
INITIALIZATION_LATCH.countDown();
}
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContext.applicationContext = applicationContext;
}
publicstatic <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
// 获取Bean,需等待应用完全启动
publicstatic <T> T getBeanSync(Class<T> clazz) {
try {
// 阻塞等待初始化完成,最多等待 1 分钟
if (!INITIALIZATION_LATCH.await(1, TimeUnit.MINUTES)) {
thrownew IllegalStateException("应用初始化超时");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
thrownew RuntimeException("获取Bean时线程被中断", e);
}
return applicationContext.getBean(clazz);
}
@Override
public int getOrder() {
return PriorityOrdered.HIGHEST_PRECEDENCE;
}
}
在订单领域模型中,我们通过显式获取的方式维护领域模型的纯粹性:public class Order {
private Long orderId;
private BigDecimal amount;
private OrderStatus status;
// 保持领域模型的纯洁性
public void pay() {
PaymentService paymentService = SpringContext.getBean(PaymentService.class);
PaymentResult result = paymentService.execute(this);
if (result.isSuccess()) {
this.status = OrderStatus.PAID;
DomainEventPublisher.publish(new OrderPaidEvent(this));
}
}
}
优势对比表:
| 维度 | 自动注入方案 | 显式获取方案 |
|---|---|---|
| 领域模型纯净度 | 依赖容器 | 完全POJO |
| 可测试性 | 需要Spring环境 | 普通Mock即可 |
| 依赖可见性 | 隐式 | 显式 |
| 循环依赖风险 | 高 | 无 |
| 代码可读性 | 需要IDE辅助 | 一目了然 |
public class AsyncBeanAccessor {
public static <T> Mono<T> getBeanReactive(Class<T> beanClass) {
return Mono.fromCallable(() -> SpringContext.getBean(beanClass)).subscribeOn(Schedulers.boundedElastic());
}
}
测试支持方案通过自定义Mock策略实现依赖隔离:@Test
public void testOrderPayment() {
// 配置Mock环境
SpringContextMock.registerMock(PaymentService.class, mockService);
Order order = new Order(/*...*/);
order.completePayment();
assertThat(order.getStatus()).isEqualTo(PAID);
}
0x4演进式设计:保持领域模型的技术中立性,为未来可能的框架迁移预留可能性