稀土掘金 稀土掘金

使用 Reflections 扫描被注解标记的类

「这是我参与11月更文挑战的第5天,活动详情查看: 2021最后一次更文挑战」

这篇文章具体实现功能是:自定义一个注解,装配类会扫描所给包路径所有被注解类进行配置。

想直接看实现方式可以跳到目录里的 Google救我

起因

最近在捣鼓 Netty,通过 Netty 实现一个简单的 IM Demo,其中使用到了自定义的协议,格式如下:

其中指令类型指明了内容的解析类型。

例如

 public final class Command {
     //登录请求指令
     public static final byte LOGIN_REQUEST = 1;
     
     //...其余指令
 }

然后需要创建对应的协议内容对象以便进行解析

 @Data   //lombok
 public class LoginRequestPacket extends Packet {
 ​
     private String userId;
 ​
     private String username;
 ​
     private String password;
 ​
     @Override
     public Byte getCommand() {
         return LOGIN_REQUEST;
     }
 }

最后需要在解码器中将指令和对应 Pakcet 关联起来

 public PacketCodec() {
     packetMap = new HashMap<>();
     packetMap.put(Command.LOGIN_REQUEST, LoginRequestPacket.class);
     packetMap.put(Command.LOGIN_RESPONSE, LoginResponsePacket.class);
     packetMap.put(Command.MESSAGE_REQUEST, MessageRequestPacket.class);
     packetMap.put(Command.ENTER_GROUP, EnterGroupRequestPacket.class);
     packetMap.put(Command.RESPONSE, ResponsePacket.class);
     packetMap.put(Command.GROUP_MESSAGE, GroupMessageRequestPacket.class);
     packetMap.put(Command.LOGOUT_REQUEST, LogoutRequestPacket.class);
     packetMap.put(Command.LOGOUT_RESPONSE, LogoutResponsePacket.class);
     packetMap.put(Command.EXIT_GROUP, ExitGroupRequestPacket.class);
     // 就这一堆,我去好家伙,那是真的麻烦,前面弄着忘记配了,测试还会出问题导致通信一直没反应
 }

思路

为了能让自己不用每次添加命令都跑到解码器进行添加,我想能不能直接在创建对应 Packet 的时候他能自己添加到解析器呢?很容易就联想到 Mybatis 中的 @MapperScan自动扫描 Mapper 的功能,使用 Mybatis 创建接口时,需要在接口处添加@Mapper如下:

 @Mapper
 public interface TableMapper{
     //接口
 }

于是乎,就按照这个思路来了。其中关键点在于:

  1. @MapperScan配置了需要扫描的包路径,即其注解中的basePackage元素
  2. 需要通过@Mapper标记需要装配的类

因为自己的 IM 中主要是PacketCodec需要进行扫描装配,那么我就在其构造方法中加入扫描配置的逻辑就好

剩下的就是创建一个被标记类,并且传入 Command 的值与该 Packet 进行绑定即可

初遇难处

按照思路,其实最简单的是先去看 Mybatis 中包扫描的源码。先查看@MapperScan,其中有一行代码如下,MapperScannerRegistrar会提前加载。

 // @Import 是 Spring 框架中的注解,用于说明注解元素属性中的类需要提前与被注解类加载
 @Import({MapperScannerRegistrar.class})

顺着看 MapperScannerRegistrar,我去?!都是些操作与 Spring 相关的方法,涉及到 BeanDefinition 、BeanDefinitionRegistry...

卧槽,完了,我这 Netty 小 Demo 一开始哪想得到会用这些东西,别说 BeanDefinition 了,连个容器都没...到哪注册去....难不成给这个小 Demo 换个血型?

我再想想有没有其他思路好了...其实还有一个思路,便是用ClassLoader然后传入 Packet 所在的路径一个一个进行解析装配,不过想到麻烦的路径操作,以及后面的维护难度,还是不要堆屎山了。

Google救我

在寻找其他方式的时候,我发现了个好东西 —— Reflections。芜湖,直接起飞~简单方便,一用就会

Reflections 是一个反射框架,能够扫描 classpath,获取元数据信息

参考链接:

www.jianshu.com/p/49199793a…

blog.csdn.net/java_faep/a…

着手修改

创建 Packet 注解

 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.TYPE})
 public @interface Packet {
 ​
     byte value() default -1; // 接受传入的 Command 指令值,用于与被注解类绑定
 }

标记类

 @Data
 @codec.Packet(LOGIN_REQUEST)    //自定义的注解,LOGIN_REQUEST 是其指令值
 public class LoginRequestPacket extends Packet {
 ​
     //...
 }

修改 PacketCodec 构造方法,也就是需要进行扫描装配的类

 public PacketCodec() {
     packetMap = new HashMap<>();
     // 配置需要扫描的包路径,我的是 PacketCodec 类所在包的 protocol 包下
     Reflections reflections = new Reflections(this.getClass().getPackage().getName() + ".protocol");
     // getTypesAnnotatedWith(注解类),即可获得被对应注解类标记的类
     Set<Class<?>> packets = reflections.getTypesAnnotatedWith(codec.Packet.class);
     // 对被注解类的处理
     for (Class<?> pClazz : packets) {
         // 绑定指令值和被注解类,取代了之前的 packetMap.put(Command.LOGIN_REQUEST, LoginRequestPacket.class);
         packetMap.put(pClazz.getAnnotation(codec.Packet.class).value(), (Class<? extends Packet>) pClazz);
     }
 }

修改后程序能够正常运行,扫描标记类进行配置大功告成。虽然还是需要在 Packet 上进行注解,但是不用回到解码器当中进行配置,也算是轻松了不少。

玻璃钢生产厂家浙江中庭商场美陈批发通州商场美陈灯饰画加工厂西安园林玻璃钢雕塑制作玻璃钢仿铜抽象人物雕塑端州玻璃钢人物雕塑批发封开玻璃钢卡通雕塑北京节庆商场美陈销售厂家台州玻璃钢雕塑价格玻璃钢葫芦福禄雕塑修文玻璃钢雕塑制作厂家北京节庆商场美陈费用玻璃钢雕塑需要注意哪些山西玻璃钢浮雕室外镂空雕塑厂家安阳玻璃钢浮雕镂空不锈钢雕塑池州创意玻璃钢雕塑宁波学校玻璃钢雕塑哪家便宜常州玻璃钢海洋雕塑湖南玻璃钢动物雕塑厂商特供玻璃钢白虎雕塑玻璃钢镂空雕塑厂玻璃钢瓜果雕塑价格广东做玻璃钢雕塑厂家四会玻璃钢卡通雕塑批发贵州玻璃钢动物雕塑定制云南专业校园玻璃钢景观雕塑厂家苏州玻璃钢花盆批发价格玻璃钢雕塑造型贴金惠安玻璃钢花盆厂家玻璃钢仿铜雕塑生产厂家郑州玻璃钢雕塑小品市场香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化