当前位置: 首页 > 知识库问答 >
问题:

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

鞠宏恺
2023-03-14

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

所以我有一个自定义注释@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的任何特定实现,那么我就能够获得注释值。请帮我理解我错过了什么?

共有1个答案

商绍元
2023-03-14

注释方法使事情变得复杂,我会尽量避免。一个没有注释的更简单的解决方案,假设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是否有可用的实现。

 类似资料:
  • 问题内容: 在阅读有关标记接口的信息时,我偶然发现了以下站点:项目37:使用标记接口定义类型 在这里,根据Joshua Bloch的说法,标记接口比标记注释有两个优点。 1. 标记接口定义了一种由标记的类的实例实现的类型。标记注释没有。这种类型的存在使您可以在编译时捕获错误,而如果使用标记注释,则这些错误在运行时才捕获。 2. 标记接口相对于标记注释的另一个优点是可以更精确地定位它们。如果使用ta

  • 在阅读有关标记接口的内容时,我偶然发现了以下网站:第37项:使用标记接口定义类型 根据Joshua Bloch的说法,标记接口比标记注释有两个优点。 > 标记接口定义由标记类的实例实现的类型;标记注释没有。这种类型的存在允许您在编译时捕获错误,如果您使用标记注释,则直到运行时才能捕获这些错误。 与标记注释相比,标记接口的另一个优点是可以更精确地定位它们。如果使用target,它可以应用于任何类或接

  • 我有一个简单的类叫BeaconDao 然而,当我用@service或@component标记beaconDao时,一切都运行得非常好。有人能看出问题所在吗?

  • 我正在尝试构建一个aar,以便在jcenter上发布。 assembleRelease任务工作正常,javadoc任务也工作正常,但javadocJar任务输出以下错误: /Users/martinmoreno/Projects/android-dev-utils/dev-utils/src/main/java/com/tinchoapps/devutils/BitmapUtils.java:11

  • 问题内容: 运行我的Android应用程序时出现此错误: 在类[[Lmodel.Vak;中,没有字段具有DatabaseField注释。 我的班级Vak有注解,所以我真的不明白为什么它仍然给我这个错误。 我有一个名为Databasehelper.java的文件,在其中扩展了OrmLiteSqLiteOpenHelper,该文件如下所示: 我还有一个扩展OrmLiteBaseActivity的文件控

  • 我从micronaut下载。lanch是一个简单的grpc项目,在添加Kotlin grpc插件之前,我可以构建它。 除了build.gradle.kts的变化,没有什么比原来的脚手架项目。 我在build.gradle.kts.编辑 首先,为了匹配IntelliJ Kotlin版本 其次,为kotlin grpc proto自动生成的文件添加了文件夹 而最后 从INtelliJ或straigh命