「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」
这篇文章具体实现功能是:自定义一个注解,装配类会扫描所给包路径所有被注解类进行配置。
想直接看实现方式可以跳到目录里的 Google救我
起因
最近在捣鼓 Netty,通过 Netty 实现一个简单的 IM Demo,其中使用到了自定义的协议,格式如下:
其中指令类型指明了内容的解析类型。
例如
1 | Java复制代码 public final class Command { |
然后需要创建对应的协议内容对象以便进行解析
1 | Java复制代码 @Data //lombok |
最后需要在解码器中将指令和对应 Pakcet 关联起来
1 | Java复制代码 public PacketCodec() { |
思路
为了能让自己不用每次添加命令都跑到解码器进行添加,我想能不能直接在创建对应 Packet 的时候他能自己添加到解析器呢?很容易就联想到 Mybatis 中的 @MapperScan
自动扫描 Mapper 的功能,使用 Mybatis 创建接口时,需要在接口处添加@Mapper
如下:
1 | Java复制代码 @Mapper |
于是乎,就按照这个思路来了。其中关键点在于:
@MapperScan
配置了需要扫描的包路径,即其注解中的basePackage
元素- 需要通过
@Mapper
标记需要装配的类
因为自己的 IM 中主要是PacketCodec
需要进行扫描装配,那么我就在其构造方法中加入扫描配置的逻辑就好
剩下的就是创建一个被标记类,并且传入 Command 的值与该 Packet 进行绑定即可
初遇难处
按照思路,其实最简单的是先去看 Mybatis 中包扫描的源码。先查看@MapperScan
,其中有一行代码如下,MapperScannerRegistrar
会提前加载。
1 | Java复制代码 // @Import 是 Spring 框架中的注解,用于说明注解元素属性中的类需要提前与被注解类加载 |
顺着看 MapperScannerRegistrar
,我去?!都是些操作与 Spring 相关的方法,涉及到 BeanDefinition 、BeanDefinitionRegistry…
卧槽,完了,我这 Netty 小 Demo 一开始哪想得到会用这些东西,别说 BeanDefinition 了,连个容器都没…到哪注册去….难不成给这个小 Demo 换个血型?
我再想想有没有其他思路好了…其实还有一个思路,便是用ClassLoader
然后传入 Packet 所在的路径一个一个进行解析装配,不过想到麻烦的路径操作,以及后面的维护难度,还是不要堆屎山了。
Google救我
在寻找其他方式的时候,我发现了个好东西 —— Reflections。芜湖,直接起飞~简单方便,一用就会
Reflections 是一个反射框架,能够扫描 classpath,获取元数据信息
参考链接:
着手修改
创建 Packet 注解
1 | Java复制代码 @Retention(RetentionPolicy.RUNTIME) |
标记类
1 | Java复制代码 @Data |
修改 PacketCodec 构造方法,也就是需要进行扫描装配的类
1 | Java复制代码 public PacketCodec() { |
修改后程序能够正常运行,扫描标记类进行配置大功告成。虽然还是需要在 Packet 上进行注解,但是不用回到解码器当中进行配置,也算是轻松了不少。
本文转载自: 掘金