“This is the fifth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

The assembly class will scan all the annotated classes given the package path for configuration.

If you want to see the implementation directly, you can jump to Google save me in the directory

The cause of

I am currently working on Netty, using Netty to implement a simple IM Demo, which uses a custom protocol, the format is as follows:

The instruction type specifies the parse type of the content.

For example,

 public final class Command {
     // Login request instruction
     public static final byte LOGIN_REQUEST = 1;
     
     / /... The rest of the instructions
 }
Copy the code

You then need to create the corresponding protocol content object for parsing

 @Data   //lombok
 public class LoginRequestPacket extends Packet {
 ​
     private String userId;
 ​
     private String username;
 ​
     private String password;
 ​
     @Override
     public Byte getCommand(a) {
         returnLOGIN_REQUEST; }}Copy the code

Finally, you need to associate the instruction with the corresponding Pakcet in the decoder

 public PacketCodec(a) {
     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);
     // This is a bunch of stuff, I go to the guy, that is really trouble, front make forget to match, test also will have a problem cause the communication has not responded
 }
Copy the code

Train of thought

In order to save myself from having to go to the decoder to add commands every time, I wonder if it can directly add the corresponding Packet to the parser when it is created. It is easy to associate with the function of @mappersCAN in Mybatis to automatically scan Mapper. When using Mybatis to create an interface, add @mapper to the interface as follows:

 @Mapper
 public interface TableMapper{
     / / interface
 }
Copy the code

As a result, in accordance with this idea. The key points are:

  1. @MapperScanThe package path to scan is configured in its annotationsbasePackageThe element
  2. Need to pass through@MapperMark the classes that need to be assembled

Since the main part of my IM is PacketCodec scanning assembly, I just add the logic of scanning configuration to its constructor

All that remains is to create a labeled class and pass in the Command value to bind the Packet

Early death in

In accordance with the idea, in fact, the simplest is to see Mybatis package scan source. Look at @mapperscan. The line of code is as follows. MapperScannerRegistrar will load it ahead of time.

 // @import is a Spring framework annotation that indicates that classes in the annotation element attribute need to be loaded with the annotated class in advance
 @Import({MapperScannerRegistrar.class})
Copy the code

Look at MapperScannerRegistrar, can I go? ! Methods of operation are related to the Spring, involves BeanDefinition, BeanDefinitionRegistry…

My little Netty Demo didn’t know how to use these things in the first place, let alone BeanDefinition. It didn’t even have a container… Where to register at…. Is it possible to change the blood type of the little Demo?

Let me see if I have any other ideas… In fact, there is another idea, which is to use ClassLoader and then pass in the path of Packet for parsing assembly one by one. However, considering the troublesome path operation and the subsequent maintenance difficulty, I still don’t want to make a pile of crap.

Google to save me

And when I was looking for other ways, I found a nice thing called Reflections. Wuhu, take off directly ~ simple and convenient, easy to use

Reflections is a reflection framework that scans the CLASspath for metadata information

Reference links:

www.jianshu.com/p/49199793a…

Blog.csdn.net/java_faep/a…

To modify the

Create Packet annotations

 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.TYPE})
 public @interface Packet {
 ​
     byte value(a) default- 1; // Accepts the value of the Command passed to bind to the annotated class
 }
Copy the code

Tag class

 @Data
 @codec.Packet(LOGIN_REQUEST)    // custom annotation, LOGIN_REQUEST is its instruction value
 public class LoginRequestPacket extends Packet {
 ​
     / /...
 }
Copy the code

Modify the PacketCodec constructor, the class that needs to be scanned for assembly

 public PacketCodec(a) {
     packetMap = new HashMap<>();
     // Configure the packet path to scan. Mine is under the protocol package of the PacketCodec class
     Reflections reflections = new Reflections(this.getClass().getPackage().getName() + ".protocol");
     // getTypesAnnotatedWith(annotation class) to get the class marked by the corresponding annotation classSet<Class<? >> packets = reflections.getTypesAnnotatedWith(codec.Packet.class);// Processing of the annotated class
     for(Class<? > pClazz : packets) {Packetmap. put(Command.LOGIN_REQUEST, loginRequestpacket.class);packetMap.put(pClazz.getAnnotation(codec.Packet.class).value(), (Class<? extends Packet>) pClazz); }}Copy the code

After modification, the program can run normally, and the scanning mark class is configured. Although you still need to annotate on Packet, it’s much easier not to go back to the decoder for configuration.