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

在编译时使用注释处理器扩展类功能

淳于烈
2023-03-14

我有以下Spring Boot类,用自定义注释Counted注释:

@RestController
@RequestMapping("/identity")
public class IdentityController {

    @Autowired
    private IdentityService identityService;

    @PostMapping
    @Counted(value = "post_requests_identity")
    public Integer createIdentity() {
        return identityService.createIdentity();
    }
}

Counted注释定义如下:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Counted {
    String value();
}

我想要的是编写一个注释处理器,有效地使我的控制器像下面的代码一样工作。

@RestController
@RequestMapping("/identity")
public class IdentityController {

    @Autowired
    private IdentityService identityService;

    @Autowired
    private PrometheusMeterRegistry registry;

    @PostConstruct
    public void init() {
        registry.counter("post_requests_identity");
    }

    @PostMapping
    public Integer createIdentity() {
        registry.counter("post_requests_identity").increment();
        return identityService.createIdentity();
    }
}

我已经能够在运行时通过反射实现这一点,但这大大延长了启动时间。有没有办法只使用注释和自定义注释处理器来实现上述功能?换句话说,我想创建一个注释,将带注释的方法添加到类中,并将任意方法调用添加到现有方法中。

我知道注释处理并不真正支持修改源代码。我有兴趣知道任何其他方法来执行上述操作,而不会将注册表及其相关代码直接放入源代码中。

共有1个答案

公良征
2023-03-14

您完全可以制作自己的拦截器或创建自己的PostProcencer。然而,Spring有一个很好的内置功能(另外,它实际上在框架周围都使用),称为Application Events。这是一个很好的小东西,通过一个很好的小抽象来利用DI和Spring作为总线,完全满足您的需求。(更多信息请参见这篇博客文章)。

Application ation事件接受端,您可以有一个简单的设置:

// Create an ApplicationEvent type for your "count" event like so...
public class CountEvent extends ApplicationEvent {

    private String counterName;

    ...

}

// Create a class that accepts the count events and meters them...
@Component
public class MeterEventService {

    @Autowired
    private PrometheusMeterRegistry registry;

    @EventListener
    public void createIdentity(CountEvent countEvent) {
        String countedMethod = countEvent.getCounterName();
        registry.counter(countedMethod).increment();
    }
}

从发送端,您可以使用自定义注释轻松地从问题的结束处继续:

@Component
@Aspect
public class Mail {

    // Autowire in ApplicationContext
    private ApplicationContext applicationContext;

    @After("execution (@<package to annotation>.Counted * *(..))")
    public void countMetric(JoinPoint jp){
        MethodSignature signature = (MethodSignature) jp.getSignature();
        String method = signature.getMethod().getName();
        applicationContext.publishEvent(new CountEvent(method));
    }
}

我想这不是太多的代码,因为这样的功能非常方便。

此外,如果您更愿意使用@Counted中的值,而不是方法名称,则可以通过类似的方式提取注释。

 类似资料:
  • 那么,这是一种好的做法吗?有什么缺点吗?如果它像我现在看起来的那么好,为什么没有很多库以一种简单的方式来做到这一点(我找到的唯一一个是类索引)?相反,对于运行时处理,有这么多?

  • null 代码(步骤1和2): 实际上,第一个任务执行良好,并为注释处理器实现编译.class文件。它在第二个任务停止。 Ant说: Java 1.6 Ant 1.8.2

  • 我正在编写一个注释处理器来在编译时执行以下检查: 有一个接口 有一个注释<code>Apply<code>用于注释方法 用注释的方法应被称为,并且只取实现 到目前为止,我已经识别了所有名为< code>apply的带注释的方法,并提取了它们作为参数的类名。所以我只剩下: 问题是:如果有的话,我如何才能从中获得参数的类层次结构表示,以便检查它是否实现了。无法使用<code>类加载器。loadClas

  • 我正在尝试创建一个自定义注释,例如,确保字段或方法既是又是,如果字段或方法既不是又不是,则会生成编译时错误,如以下示例所示: 到目前为止,我已经完成了两个自定义注释接口: 和: 正如所暗示的,我不知道如何生成编译时错误。Processor的文档清楚地表明我不应该抛出异常, 如果处理器抛出未捕获的异常,该工具可能会停止其他活动注释处理器。 它接着描述了当提出错误条件时会发生什么,现在是如何提出错误条

  • 问题内容: 我正在尝试创建一个自定义批注,例如,以确保字段或方法为and ,并且如果该字段或​​方法不为and ,则将生成编译时错误,如以下示例所示: 到目前为止,我已经完成了两个自定义注释接口: 和: 如所示,我不知道如何生成编译时错误。Processor 的文档清楚地表明,我不应该抛出异常, 如果处理器抛出未捕获的异常,则该工具可能会停止其他活动的注释处理器。 它继续描述了引发错误条件时会发生

  • 但当我尝试构建以下类时,它表示找不到AbstractProcessor类: 如何让它识别这个类? 下面是确切的错误: 我的导入内容如下所示: 这是我的java版本: