@Service 标记的类不存在注释数据

发布于 2025-01-12 17:18:28 字数 2735 浏览 5 评论 0原文

我正在尝试实现解析器模式(策略模式)。

所以我有一个自定义注释 @PaymentTypeValue

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface PaymentTypeValue {
    PaymentType[] value();
}

PaymentType 作为枚举类

public enum PaymentType{
CASH, CARD, NET_BANKING, UPI, WALLET;
}

,现在我有接口 PaymentService

public interface PaymentService {
   void process();
}

并有它的 5 个实现,其中一个就像

@Service
@PaymentTypeValue({PaymentTypeValue.CASH})
public class CashPaymentService implements PaymentService {
  @Override
  void process(){
    //some logic
  }
}

我 现在问题出

@Component
public class PaymentServiceResolver {

    private static final Logger log = getLogger(PaymentServiceResolver.class);

    @Autowired
    private List<PaymentService> paymentServices;

    private final Map<PaymentType, PaymentService> paymentServiceMap = new EnumMap<>(PaymentType.class);

    @PostConstruct
    public void init() {
        paymentServices.forEach(paymentService -> {
                    PaymentTypeValue annotation = paymentService.getClass().getAnnotation(PaymentTypeValue.class);
                    if (annotation != null && annotation.value() != null) {
                        PaymentType[] paymentTypes = annotation.value();
                        Arrays.stream(paymentTypes).forEach(paymentType -> {
                            paymentServiceMap.put(paymentType, paymentService);
                        });
                    } else {
                        log.error("paymentService {} is missing a necessary annotation",
                                paymentService.getClass().getName());
                        log.error("This paymentService cannot be initialized");
//                        throw new IllegalStateException("paymentService is missing a necessary annotation for " + paymentService.getClass().getName());
                    }
                }
        );
    }

    public PaymentService resolvePaymentService(PaymentType paymentType) {
        PaymentService paymentService = paymentServiceMap.get(paymentType);
        if (paymentService != null) {
            return paymentService;
        } else {
            String message = "Could not find paymentService for " + paymentType;
            log.error(message);
            throw new RuntimeException(message);
        }
    }
}

在 init() 方法中,PaymentService 的所有服务实现都出现在列表中,但是当我尝试查找注释时,它给出了 null。 我检查了 paymentService.getClass() 方法的值,其中annotationData 有 0 个注释。如果我自动装配 PaymentService 的任何特定实现,那么我就能够获取注释值。请帮助我理解我在这里缺少什么?

I'm trying to implement resolver pattern ( strategy pattern ).

So I have one custom annotation @PaymentTypeValue

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface PaymentTypeValue {
    PaymentType[] value();
}

and PaymentType as enum class

public enum PaymentType{
CASH, CARD, NET_BANKING, UPI, WALLET;
}

now I have interface PaymentService

public interface PaymentService {
   void process();
}

and have its 5 implementations, one is like

@Service
@PaymentTypeValue({PaymentTypeValue.CASH})
public class CashPaymentService implements PaymentService {
  @Override
  void process(){
    //some logic
  }
}

And I have resolver which is like this

@Component
public class PaymentServiceResolver {

    private static final Logger log = getLogger(PaymentServiceResolver.class);

    @Autowired
    private List<PaymentService> paymentServices;

    private final Map<PaymentType, PaymentService> paymentServiceMap = new EnumMap<>(PaymentType.class);

    @PostConstruct
    public void init() {
        paymentServices.forEach(paymentService -> {
                    PaymentTypeValue annotation = paymentService.getClass().getAnnotation(PaymentTypeValue.class);
                    if (annotation != null && annotation.value() != null) {
                        PaymentType[] paymentTypes = annotation.value();
                        Arrays.stream(paymentTypes).forEach(paymentType -> {
                            paymentServiceMap.put(paymentType, paymentService);
                        });
                    } else {
                        log.error("paymentService {} is missing a necessary annotation",
                                paymentService.getClass().getName());
                        log.error("This paymentService cannot be initialized");
//                        throw new IllegalStateException("paymentService is missing a necessary annotation for " + paymentService.getClass().getName());
                    }
                }
        );
    }

    public PaymentService resolvePaymentService(PaymentType paymentType) {
        PaymentService paymentService = paymentServiceMap.get(paymentType);
        if (paymentService != null) {
            return paymentService;
        } else {
            String message = "Could not find paymentService for " + paymentType;
            log.error(message);
            throw new RuntimeException(message);
        }
    }
}

Now the problem is in init() method, all the service implementations of PaymentService are present in list but when i'm trying to find annotations its giving null.
I checked the value of paymentService.getClass() method and in that annotationData had 0 annotations. If I autowire any specific implementation of PaymentService then I'm able to get the annotation value. Please help me understand what I'm missing here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

自此以后,行同陌路 2025-01-19 17:18:28

注释方法使事情变得复杂,我会尽力避免这种情况。没有注释的更简单的解决方案,假设 PaymentType 和服务实现之间存在 1:1 映射:

  1. 向服务接口添加函数 boolean canHandle(PaymentType) 。
  2. 解析器使用该信息来定位匹配的服务。

接口:

public interface PaymentService {

    boolean canHandle(PaymentType paymentType);

    void process();
}

服务实现:

@Service
public class CashPaymentService implements PaymentService {

    @Override
    public boolean canHandle(PaymentType paymentType) {
        return PaymentType.CASH.equals(paymentType);
    }

    @Override
    public void process() {
        // processing...
    }
}

服务定位器:

@Component
public class PaymentServiceResolver {

    private final List<PaymentService> paymentServices;
    private final Map<PaymentType,PaymentService> serviceMapping = new ConcurrentHashMap<>(5);

    @Autowired
    public PaymentServiceResolver(List<PaymentService> paymentServices) {
        this.paymentServices = paymentServices;
    }

    public PaymentService resolve(PaymentType paymentType) {
        return serviceMapping.computeIfAbsent(paymentType, resolveInternal());
    }

    private Function<PaymentType, PaymentService> resolveInternal() {
        return paymentType ->
                paymentServices.stream()
                        .filter(service -> service.canHandle(paymentType))
                        .findFirst()
                        .orElseThrow(() -> new IllegalStateException("Unsupported payment type: " + paymentType));
    }
}

您可以向解析器添加更多验证逻辑,以在 Spring 初始化阶段检查每个 PaymentType 是否有可用的实现。

The annotation approach makes things complex, I would try to avoid that. A simpler solution without annotations, assuming that there is a 1:1 mapping between PaymentType and service implementation:

  1. Add a function boolean canHandle(PaymentType) to the service interface.
  2. A resolver uses that information to locate a matching service.

Interface:

public interface PaymentService {

    boolean canHandle(PaymentType paymentType);

    void process();
}

Service implementation:

@Service
public class CashPaymentService implements PaymentService {

    @Override
    public boolean canHandle(PaymentType paymentType) {
        return PaymentType.CASH.equals(paymentType);
    }

    @Override
    public void process() {
        // processing...
    }
}

Service locator:

@Component
public class PaymentServiceResolver {

    private final List<PaymentService> paymentServices;
    private final Map<PaymentType,PaymentService> serviceMapping = new ConcurrentHashMap<>(5);

    @Autowired
    public PaymentServiceResolver(List<PaymentService> paymentServices) {
        this.paymentServices = paymentServices;
    }

    public PaymentService resolve(PaymentType paymentType) {
        return serviceMapping.computeIfAbsent(paymentType, resolveInternal());
    }

    private Function<PaymentType, PaymentService> resolveInternal() {
        return paymentType ->
                paymentServices.stream()
                        .filter(service -> service.canHandle(paymentType))
                        .findFirst()
                        .orElseThrow(() -> new IllegalStateException("Unsupported payment type: " + paymentType));
    }
}

You may add more validation logic to your resolver to check during the Spring's initialization phase whether an implementation is available for each PaymentType.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文