本文继续上一篇使用Metrics方法级远程监控Java程序来讲。在上文中,我们其实只是实现了功能,但是如果做成库,给多个工程使用,那就还差一些。于是我对这个库又做了一些优化。
1 不足点
- 写死了切点@RestController,@Controller,和@Service,不灵活。然而我们项目中部分服务还使用了自己自定义的注解,如@XXController和@XXService等(这里就不写具体名字了)。在我们的业务逻辑中同属于Controller层和Service层。如果是之前的编码方式,这些类中的方法就监控不到了。于是我希望监控的切面是可以配置的。
- 写死了包名,如果我换一个业务,起不同的包名,就监控不到了。所以我希望包名也是可以配置的。
2 实现可配置的切面
2.1 希望的使用姿势
我希望使用这个库的工程,可以通过以下方式决定自己要监控的类。
|
|
我希望可以在Application上使用一个注解(如:MonitorEnable),然后在其中指定切点(甚至自定义的注解)。这样我们便可以任意选择自己想要监控的业务层代码。那么接下来看看如何实现。
2.2 从自定义注解中获取配置的切点
2.2.1 自定义配置使用的注解
首先自定义注解MonitorEnable
,并定义value
为Annotation的Class数组。这里我们为了简单,限制一下切点的类型。之后如果需要扩展功能再放开。
|
|
这样其他工程就可以在类上使用这个注解了。接下来我们获取注解中的Value值。
2.2.2 从注解中获取配置的切点
MonitorEnable
作用是提供配置数据的。那么我们想要获取它里面信息的话,需要为MonitorEnable
加上@Import
注解,并为其指定一个配置类,这里我们指定MonitorConfig
为配置类。
更改后的MonitorEnable
注解文件:
|
|
要想在MonitorConfig
配置类中获取MonitorEnable
中的配置信息,需要实现ImportAware
接口,这样Spring在加载完MetaData
的时候会回调setImportMetadata
方法。我们可以在这里获取注解中的内容。
|
|
MonitorProperty类:
|
|
这样我们在程序启动中就可以获取MonitorEnable
使用者配置的值,并且存储在了MonitorProperty
中。
2.3 根据切点为监控方法准备Timer
现在切点已经是配置进来的了,那么为监控方法准备Timer
这一步也要做相应更改。这一步比较简单。MethodMonitorCenter
类增加代码如下,从MonitorProperty
中获取切点,替换之前写死的逻辑:
|
|
2.4 根据切点创建切面
对Spring AOP还不熟悉的读者可以上网上搜索一下。有很多的文章介绍。我就不再赘述了。
我们常见的Spring AOP的使用姿势都是硬编码方式。所谓硬编码的方式就是指,Java注解(我上一篇文章中所使用的方法),和XML配置的方式。现在我们的切点是配置进来的。那么就不能通过硬编码来实现了。然而Java动态代理和AspectJ都需要知道代理目标类。显然也不适合我们这种场景。但是我相信硬编码能够做到的,软编码肯定可以做到,只不过可能会比较麻烦。于是翻了翻Spring源码。找到了方法。本篇文章不想涉及源码和原理,只讲实现。
前提,删除上一篇文章中的MetricsMonitorAOP
类,因为我们已经不能用硬编码的方式了。
2.4.1 准备创建切面处理类
自定义类MonitorAdvice
实现MethodInterceptor
接口,其中的invoke
方法相当于环绕切面的方法。
|
|
2.4.2 用软代码根据切点创建切面
MonitorConfig
类中增加代码,讲解请看注释:
|
|
这样,就可以通过软代码的方式实现之前硬编码实现的切面功能。
3 可配置的包名
这个相对于上一个优化简单很多。
3.1 希望的使用姿势
我希望用户可以通过以下两种方式任意一种,达到配置包名的需求:
通过application.properties
文件配置,如,在application.properties
文件中增加如下代码:
|
|
或者通过MonitorEnable
注解进行如下配置:
|
|
来实现监控制定的包名。
3.2 实现包名可配置
这里只讲通过application.properties
文件配置的方式实现方案。通过注解的配置的实现只是获取方式不同,有兴趣的可以直接去看源码。
3.2.1 MonitorProperty增加包名属性
我们可以注意到,3.1中都是可以配置多个包名的,那么在MonitorProperty
中增加属性basePackages
:
|
|
3.2.2 为MonitorProperty赋值
这一步方法有很多种,我们使用ConfigurationProperties
注解为其赋值:
|
|
3.2.3 更改筛选逻辑
已经获取了用户配置的包名,那么我们用用户配置的包名重写原来根据包名筛选的逻辑:
|
|
这样使用者就可以配置自己的包名了。
4 优化效果
使用者通过在自己的Application类上增加MonitorEnable
注解,然后可以自定义配置切点:
|
|
然后通过在application.properties
文件中配置monitor.property.basePackages
属性,配置自己想监控的包名:
|
|
然后通过/monitor/metrics
这个Restful接口获取监控方法的数据。
5 总结
本次优化的两点中,使用软代码方式创建切面是比较困难的,相关的文献比较少。如果有时间,我会单独写一篇文章讲解一下源码和原理。
最后欢迎关注我的个人公众号。提问,唠嗑,都可以。