java - 在编译时使用注释处理器扩展类功能
问题描述
我有以下 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();
}
}
我已经能够在运行时通过反射来做到这一点,但这大大延长了启动时间。有没有办法只用注释和自定义注释处理器来完成上述工作?换句话说,我想创建一个注解,将一个带注解的方法添加到一个类中,并将一个任意方法调用添加到一个已经存在的方法中。
我知道注释处理并不真正支持修改源。我有兴趣知道任何其他方法来执行上述操作,而无需将注册表及其相关代码直接放在我的源代码中。
解决方案
您绝对可以制作自己的拦截器或创建自己的PostProcessor
. 然而,Spring 有一个很好的内置特性(它实际上在整个框架中都使用过),称为Application Events。这是一个很好的小东西,它通过一个很好的小抽象来利用 DI 和 Spring 作为总线,完全可以满足您的需求。(另请参阅此博客文章了解更多信息)。
从ApplicationEvent
接受方面来说,您可以进行简单的设置:
// 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));
}
}
恕我直言,对于拥有这样一个功能的极大便利来说,代码并不多。
此外,如果您更愿意使用value
from@Counted
而不是方法名称,则可以类似地执行 this来取消注释。
推荐阅读
- javascript - 添加身份验证后在其他选项卡屏幕上显示主页标题。(遵循反应导航文档)
- python - 如何通过 sqlalchemy 在多个(生成的)python 进程中使用 sqlite
- python - 如何在 Django 管理视图中显示链接对象?
- swift - 如何验证 Firestore 中的文档路径?
- python-3.x - 如何从python中的excel电子表格中将数据提取到字典列表中?
- php - 如何防止 cURL 在 WP 函数中被触发两次?
- solidity - 使用 truffle 在构造函数中使用参数测试智能合约
- java - 从文件到数组的直方图
- matplotlib - matplotlib 添加艺术家未在图例上显示标签
- c# - 使用 foreach 将多个元素添加到列表中