如何使用抽象 spring 服务的多态性?

How to use polymorphism with abstract spring service?

我有一个多态服务,像这样:

public abstract class PaymentService {
    abstract boolean processPayment(Payment payment);
}
@Service
public class CreditPaymentService extends PaymentService {
    @Override
    public boolean processPayment(Payment payment) {
        // method implementation
    }
}
@Service
public class CashPaymentService extends PaymentService {
    @Override
    public boolean processPayment(Payment payment) {
        // method implementation
    }
}

在我的 PaymentController 中,我收到一笔付款,我必须将它发送到正确的服务来处理它,具体取决于付款的类型。

@Controller
public class PaymentController {

    @Autowired
    private PaymentService service;

    @Override
    @PostMapping
    public ResponseEntity<Payment> processPayment(@RequestBody Payment payment) {
        service.processPayment(payment);
        return noContent().build();
    }
}

spring如何知道要实例化哪个服务?

不会。您必须使用 @Qualifier 并自动连接它们,然后确定将付款发送到哪个,大概是通过查看请求正文。

有一个解决方法,即为您的付款服务使用工厂。

首先创建一个工厂,它将根据 paymentType 为您提供正确的服务(您也可以为此使用枚举)。

然后每当你想获得一个paymentService,你就通过factory获得它。

    @Component
    public class PaymentServiceFactory {

        @Autowired
        ApplicationContext context;

        public PaymentService getPaymentService(String paymentType) {

            // paymentType: Could be cash or credit
            return (PaymentService) context.getBean(paymentType + "PaymentService");
        }
    }

    @Controller
    public class PaymentController {
        @Autowired
        PaymentServiceFactory paymentServiceFactory;

        @PostMapping
        private ResponseEntity<Payment> processPayment(@RequestBody Payment payment) {

            PaymentService service = paymentServiceFactory.getPaymentService(payment.type);
            service.processPayment(payment);
            return noContent().build();
        }
    }

希望对您有所帮助。

另一种方法是使用 bean 名称,如下所示。这需要请求中指定的付款方式。

示例:Payment

public class Payment {
    private String mode;

    public String getMode() {
        return this.mode;
    }

    //.. rest of the class
}

现在定义一个常量classPaymentModes

public final class PaymentModes {
    private PaymentModes() {
    }

    public static final String CASH = "cash";
    public static final String CREDIT = "credit";
}

并为服务提供 bean 名称

@Service(value = PaymentModes.CASH)
public class CashPaymentService extends PaymentService {

    @Override
    public boolean processPayment(Payment payment) {
        //Implementation
    }
}

@Service(value = PaymentModes.CREDIT)
public class CreditPaymentService extends PaymentService {
    @Override
    public boolean processPayment(Payment payment) {
        // Implementation
    }
}

这将使用在组件扫描期间指定的 bean 名称将这两个 bean 注册到应用程序上下文。

来自documentation

An autowired Map instance’s values consist of all bean instances that match the expected type, and the Map instance’s keys contain the corresponding bean names.

因此,如果您按如下方式自动装配

@Autowired
Map<String,PaymentService> serviceMap;

地图如下所示:

{cash=rg.so.q61741320.CashPaymentService@1e74829, credit=rg.so.q61741320.CreditPaymentService@16f416f}

其中 key 是配置的 bean 名称,value 是 bean 实例。

并且可以使用以下逻辑从映射中查找所需的服务实例。

@Override
@PostMapping
private ResponseEntity<Payment> processPayment(@RequestBody Payment payment) {
    String paymentMode = payment.getMode();// get payment mode;
    if(serviceMap.containsKey(paymentMode)) {
        serviceMap.get(paymentMode).processPayment(payment);
    }
    return noContent().build();
}

注意:覆盖的方法应该是 public 以允许从其他 classes 调用它,但在带有问题的代码中作为 private 给出。似乎是打字错误。

希望对您有所帮助