Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand reflection in serialization

2025-01-30 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article focuses on "how to understand reflection in serialization". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to understand reflection in serialization.

Preface

Serialization is not unfamiliar to everyone, to put it bluntly, is to save the state of the current class object as binary, and then be used for persistence or network transmission; commonly used RPC framework serialization operation before data transmission, mainstream RPC framework contains a variety of serialization methods such as protobuf,fastjson,kryo,hessian,java built-in serialization, etc., can be roughly divided into binary and string (json string).

Reflection

Because the current class object state needs to be saved as binary, it is often necessary to obtain all class attributes. At this time, reflection is used in most serialization methods, all class attribute acquisition methods are obtained through reflection, and then the property values are obtained, as follows:

/ / 1. Method Method [] methods = obj.getClass (). GetDeclaredMethods (); for (Method method: methods) {method.invoke (obj);} / / 2. Field Field fields [] = obj.getClass () .getDeclaredFields (); for (Field field: fields) {field.get (obj);}

However, reflection is often suspected in terms of performance, so there is a similar way that protobuf automatically generates serialization code, and fastjson uses ASM instead of reflection. Let's first compare the performance of various methods with a simple test to see if reflection is really slow.

Performance testing

Under the windows10+jdk8 environment, stress tests are performed on direct, reflective, and ASM calling methods respectively. It seems that the time elapsed can be performed multiple times in the test with a stable value. The following tests obtain attribute values from the Person object through methods, as follows:

Public class Person {private String id;private String name; public String getId () {return id;} public String getName () {return name;}} is called directly

Direct call is the most commonly used way for us to obtain the attribute value directly through the object call method name. We will poll the two methods during the stress test:

Public static void test () {Person person = new Person ("10001", "zhaohui"); long startTime = System.currentTimeMillis (); for (int I = 0; I < 100000000000000; iTunes +) {if (I% 2 = = 0) {person.getId ();} else {person.getName ();}} long endTime = System.currentTimeMillis () System.out.println ("Manual time:" + (endTime-startTime) + "ms");}

The result of multiple tests is about 90ms, and the speed of direct call is the fastest, but we need to write the serialization code of each bean manually, or use the tool like protobuf to generate all the serialization code for us, such as generating Person serialization code:

Public void writeTo (com.google.protobuf.CodedOutputStream output) throws java.io.IOException {getSerializedSize (); if (bitField0_ & 0x00000001) = = 0x00000001)) {output.writeInt32 (1, id_);} if (bitField0_ & 0x00000002) = = 0x00000002)) {output.writeBytes (2, getNameBytes ());} getUnknownFields (). WriteTo (output);}

You can see that each generated bean automatically generates serialization code, and all bean inherits from a unified abstract class, which provides a complete set of specifications; one drawback is that each modification requires manual modification of the proto file, and then regenerate the code

Reflection call

Using the reflection mechanism provided by jdk, get the Methods and then the attribute value, as shown below:

Public static void test () throws Exception {long startTime = System.currentTimeMillis (); Person person = new Person ("10001", "zhaohui"); Method [] ms = Person.class.getDeclaredMethods (); for (int I = 0; I < 10.00000000000; iSum +) {ms [I & ms.length-1] .invoke (person);} long endTime = System.currentTimeMillis () System.out.println ("Reflex time:" + (endTime-startTime) + "ms");}

After testing, the test time is about 205ms, and there is still a certain gap with direct calls. However, each round of jdk upgrades improves performance, such as MethodHandle introduced in jdk7, which simulates bytecode level calls.

ASM call

Reflection reads the class information stored on the persistent heap, while ASM handles .class bytecode directly. There is no need to load the class. We use ReflectASM to test here.

ReflectASM is a very small Java class library that provides high-performance reflection processing through code generation, automatically provides access classes for get/set fields, and access classes use bytecode manipulation instead of Java's reflection technology, so it is very fast. Public static void test () {Person person = new Person ("10001", "zhaohui"); long startTime = System.currentTimeMillis (); MethodAccess methodAccess = MethodAccess.get (Person.class); String [] mns = methodAccess.getMethodNames (); int len = mns.length;int indexs [] = new int [len]; for (int I = 0; I < len; ionization +) {indexs [I] = methodAccess.getIndex (MNS [I]) } for (int I = 0; I < 1: 00000000000; iTunes +) {methodAccess.invoke (person, indexs [I & len-1]);} long endTime = System.currentTimeMillis (); System.out.println ("ASM time:" + (endTime-startTime) + "ms");}

After testing, the time is maintained around 110ms, and the speed is fast enough to catch up with the direct call; for maximum performance, you should use a method or field index instead of a name

Summary

We can see that although the reflection performance has been improving, there is still a little gap between direct call and ASM; but in fact, if this time is spent on RPC, it can be said to be very small in the whole network transmission; if you are extremely interested in performance, you can consider using direct call or ASM.

Thinking

With regard to the direct call to protobuf mentioned above, serialization code is generated through the tool, but every change in this way has to generate the code manually, which is a bit troublesome. Can we directly use the framework of lombok to do an extension to generate serialization code automatically? in fact, ASM is also used at the bottom of lombok to generate byte code directly and provide serialization comments.

@ Target (ElementType.TYPE) @ Retention (RetentionPolicy.SOURCE) public @ interface Serialize {}

The annotations can then be directly applied to bean to help us generate serialization code, just like @ Getter/@Setter, which is equivalent to an integration of direct calls and ASM; similar to the following code:

@ Serializepublic class Person {private String id;private String name; / / automatically generate public byte [] serialize () {ByteBuffer bb = ByteBuffer.allocate (100); bb.put (id.getBytes ()); bb.put (name.getBytes ()); return bb.array ();} so far, I believe you have a better understanding of "how to understand reflection in serialization". You might as well do it in practice! Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report