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

时间:2018-12-24 22:33:18

标签: java spring annotations annotation-processing

我有以下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();
}

我想要编写一个注释处理器,以有效地使我的Controller的行为类似于以下代码。

@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 个答案:

答案 0 :(得分:0)

您绝对可以制作自己的拦截器,也可以创建自己的PostProcessor。但是,Spring具有一个不错的内置功能(Application Events)(该功能实际上已在整个框架中使用)。这是一件很有趣的事情,它通过一个恰好适合您需求的漂亮抽象将DI和Spring用作总线。 (有关更多信息,另请参见this blog文章。)

filepath: {endswith}接受方面,您可以进行如下设置:

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而不是方法名,则可以类似地doing this提取注释。