zfoo Documentation

Extremely fast enterprise server framework, can be used in RPC, game server, web server.

RAW Doc

Technical Documentation: zfoo-project/zfoo

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

English | 简体中文

Ⅰ. Introduction of zfoo🚩

  • Extremely fast, asynchronous, actor design, lock free, universal RPC framework, native GraalVM support
  • High scalability, Single server deployment, microservice deployment, cluster deployment, gateway deployment
  • Can be used as a game server framework or website server framework
  • zfoo protocol supports C++ Rust Java/Kotlin/Scala JavaScript/TypeScript/ES C# Go Php Ruby Lua GDScript Python Dart Swift

Perfect work development process, complete online solution

  • Spring projects, distributed projects, container projects, hot update code without
    downtime
    hotswap
  • Excel json csv configuration is automatically mapped and parsed, Online hotswap
    configuration
    storage
  • Automapping framework for MongoDB orm
  • Event bus event
  • Time task scheduling scheduler
  • Cpu, memory, hard disk, network monitoring built into the program no code and extra tools
    required monitor

Ⅱ. Who uses this project

  • Projects with extremely high-performance requirements, such as website and game server frameworks, single server, global server, live chat, IM system, real-time push
  • Projects such as saving, development, deployment, operation and maintenance costs
  • As a backend infrastructure for Godot, Unity, Cocos,Webgl, H5, Network protocol supports tcp udp websocket http
  • Keep it Simple and Stupid, simple configuration, lightweight code

Ⅲ. Maven dependency✨

  • Environment requirement JDK 17+, support OpenJDK, Oracle JDK and native GraalVM
text
<dependency>
    <groupId>com.zfoo</groupId>
    <artifactId>boot</artifactId>
    <version>4.1.4</version>
</dependency>
  • If you don't want to depend on all zfoo modules, you only need to choose to depend on one of them
text
<dependency>
    <groupId>com.zfoo</groupId>
    <artifactId>protocol</artifactId>
    <version>4.1.4</version>
</dependency>

Ⅳ. Tutorials

Ⅴ. Usage⭐

1. [protocol](protocol/README.md) ultimate performance serialization and deserialization

text
// protocol registration
ProtocolManager.initProtocol(Set.of(ComplexObject.class, ObjectA.class, ObjectB.class));

// serialization
ProtocolManager.write(byteBuf, complexObject);

// deserialization
var packet = ProtocolManager.read(byteBuf);

2. [net](net/README.md) ultimate performance RPC framework, supports tcp udp websocket http

text
// Service provider, only need to add an annotation to the method, the interface will be automatically registered
@PacketReceiver
public void atUserInfoAsk(Session session, UserInfoAsk ask) {
}

// Consumers, synchronously requesting remote service, will block the current thread
var ask = UserInfoAsk.valueOf(userId);
var answer = NetContext.getCosumer().syncAsk(ask, UserInfoAnswer.class, userId).packet();

// Consumers, asynchronously requesting remote service, and will still execute logic in the current thread after the asynchronous
NetContext.getCosumer().asyncAsk(ask, UserInfoAnswer.class, userId)
          .whenComplete(answer -> {
              // do something
          );

3. [hotswap](hotswap/src/test/java/com/zfoo/hotswap/ApplicationTest.java) hot update code, no need to stop the server, no additional configuration, just one line of code to start hot update

text
// Pass in the class file that needs to be updated
HotSwapUtils.hotswapClass(bytes);

4. [orm](orm/README.md) automatic mapping framework based on mongodb

text
// You don't need to write sql and any configuration yourself, define a table in the database directly through annotation definitions
@EntityCache
public class UserEntity implements IEntity<Long> {
    @Id
    private long id;
    private String name;
}

// update database data
entityCaches.update(userEntity);

5. [event](event/src/test/java/com/zfoo/event/ApplicationTest.java) use the observer design pattern, decouples different modules and improves the quality of the code

text
// To receive an event, you only need to add an annotation to the method and the method will be automatically listen for the event
@EventReceiver
public void onMyNoticeEvent(MyNoticeEvent event) {
    // do something
}

// fire an event
EventBus.post(MyNoticeEvent.valueOf("My event"));

6. [scheduler](scheduler/README.md) scheduling Framework Based on Cron Expression

text
@Scheduler(cron = "0/1 * * * * ?")
public void cronSchedulerPerSecond() {
    // do something
}

7. [storage](storage/src/test/java/com/zfoo/storage/ApplicationTest.java) Excel to class automatic mapping framework, you only need to define a class corresponding to Excel, and directly parse Excel

text
@Storage
public class StudentResource {
    @Id
    private int id;
    @Index
    private String name;
    private int age;
}

Ⅵ. Commit specification👏

  • People who like this project are welcome to maintain this project together, and pay attention to the following
    specifications when submitting code
  • The code formats use the default formatting of IntelliJ Idea
  • conventional-changelog-metahub

Ⅶ. License

zfoo use Apache License Version 2.0


Overview (`boot/README.md`)

zfoo spring boot support

  • zfoo boot makes it easy to create Spring Boot application using zfoo by using auto-configure

Overview (`event/README.md`)

English | 简体中文

Ⅰ. Introduction

  • event The event bus is used to decouple different
    modules and improve the quality of the code. The core idea is the observer design pattern

Ⅱ. Event bus at the hardware level

1. Between devices communication

2. Reduced complexity with the bus

3. Multiple Architectures of Hardware Buses

The core of the design idea of the bus is to reduce the complexity and coupling degree of interaction between multiple
modules.

At the actual hardware level, a bus is actually a set of wires connecting circuits.
Because of the differences in speed between different devices, there are often multiple buses in a computer.

In fact, the design idea of the bus is often used in our software development process.
The event bus is a common design pattern. Usually, the event bus will also be combined with the subscriber-publisher
mode to
become a main mode of interaction between loosely coupled modules of a large-scale system.

Ⅲ. Event bus at software level

  • The event bus is called the observer mode from the design mode
  • There is no fixed way to write the design pattern, zfoo event implements the event bus with the simplest annotation
  • zfoo event uses Javassist bytecode enhancement technology to dynamically proxy event receivers, avoiding reflection
    and no performance loss

Overview (`hotswap/README.md`)

English | 简体中文

Ⅰ. Introduction

  • hotswap Hot update code, no need to stop the
    server, no additional configuration, one line of code to enable hot update

Ⅱ. Stand-alone hot update

  • directly pass in the class file that needs hot update
    text
    // pass in the class file that needs to be updated
    HotSwapUtils.hotswapClass(bytes);

Ⅲ. Distributed Hot Update

  • upload the class files that need to be updated to the zookeeper registration center, and other servers monitor the
    class files that need to be updated, and update the code when they are monitored

  • tank
    Distributed hot update code implementation


Overview (`monitor/README.md`)

English | 简体中文

Ⅰ. Introduction

  • monitor Lightweight cpu, memory, hard disk,
    network monitoring

Ⅱ. Use

  • uptime, imitating the uptime command of Linux, can be used to monitor the load of cpu

    text
    UptimeVO uptime = OSUtils.uptime();
  • df, imitating the Linux df command, can be used to monitor the hard disk capacity

    text
    List<DiskFileSystemVO> df = OSUtils.df();
  • free, imitating Linux's free command, can be used to monitor memory usage

    text
    MemoryVO free = OSUtils.free();
  • sar, the sar command imitating Linux, can be used to monitor network IO

    text
    List<SarVO> sar = OSUtils.sar();

Ⅲ. Traditional Server Monitoring

  • Traditional stand-alone server monitoring mainly depends on cpu, memory, hard disk, network

  • Distributed server monitoring is mainly to monitor multiple servers, which is not much different from stand-alone
    monitoring.

    text
    It is very simple to write a distributed server monitoring by yourself. 
    You only need to collect the main data of the current server every second or minute, and upload it to the database or other servers.
    Use these collected data to analyze performance, make monitoring alarms, make line charts or other visual charts.
    Monitor can be easily collected through static class encapsulation, and then realize its own distributed monitoring program, 
    and can be completely embedded in Java programs without additional deployment

Ⅲ. Modern Server Monitoring

  • Now that the server is the era of containers, server monitoring has also changed from server monitoring to container
    monitoring
  • Container monitoring is almost an integrated function of the container itself, and even cloud vendors will provide
    monitoring programs and monitoring services for free

Ⅳ. Server Monitoring We Can Do

  • Self-customized monitoring is the monitoring that fits your own project, such as implementing a monitoring that
    monitors the number of times the rpc interface is called by yourself

Overview (`net/README.md`)

English | 简体中文

Ⅰ. Introduction

  • net Asynchronous, actor design,
    lock-free, universal RPC framework based on Spring's MVC-style usage
  1. Elegant synchronous and asynchronous requests, faster, supports tcp udp websocket
  2. Service registration and discovery, the configuration center uses zookeeper, which can be extended to other
    registration centers
  3. Built-in high-performance gateway, custom forwarding strategy
  4. Scalable services, load balancing, cluster monitoring, everything you expect
  • net provides two layers of api interface
    • IRouter(low level api) The underlying network interface, which sends messages directly through the Session
      connection
    • IConsumer(high level api) The high-level network interface is the encapsulation of I Router, and the consumer sends
      RPC messages to the service provider
text
Extreme high performance, high availability, high scalability (generally refers to adding machines), 
high scalability (generally refers to the principle of opening and closing at the code level)

config,local configuration, zookeeper registration discovery, and request load balancing are all placed under this package
core,unified package of core package, server and client
router,message routing
handler,netty's handler defines some common handlers for clients and servers
protocol,registration of message classes, encoding and decoding of messages, bytecode enhancement, etc.
schema,analysis of spring's custom tags
session,encapsulation of netty's channel
task,task thread pool, task distribution
  • Network communication specification
    • The client's request to the server ends with Request, and the return ends with Response
    • The call between the servers ends with Ask, and the return ends with Answer.

Background

text
When using Java to make online games involves more complex interactive scenarios, there are a lot of remote requests.
At this time, a high-performance rpc framework is needed.

There are many rpc frameworks in the Java ecosystem, but few rpc frameworks can fit into the rpc framework of game projects. 
Some of them are listed below:
    dubbo,The code is heavyweight, asynchronous calls are cumbersome, there is no gateway, and it is impossible to directly interact with the client;
    grpc,The code is heavyweight, complex to use, complex to deploy, no gateway, difficult to customize;
    akka,Using Scala language, the learning cost is extremely high, just give up;
    
So I wrote a universal rpc framework, the code is lightweight, can be easily customized, with its own gateway, inherently asynchronous, and the tool chain is complete.
After subsequent continuous optimization, a serialization framework with the very fast speed in Java was also made, and then the speed took off directly.
Later, I found out that it can be used not only for games, but also for rpc scenes with extreme performance requirements.

Ⅱ. Server Architecture Diagram

Ⅲ. Why fast


  • Use current best performin zfoo protocol as serialization and deserialization protocol for
    gateway and RPC messages
  • Lock-free design and elegant thread pool design, the user's request can always be guaranteed to be executed in the
    same thread of the same server through the gateway, so there is no need to use locks to ensure concurrency
  • The rpc call is naturally asynchronous, and it is guaranteed to be executed in the same thread after the rpc
    asynchronous call ends, similar to the design idea of actor, especially suitable for scenarios with extremely high
    performance requirements
  • Use the MVC design pattern to standardize development, ensure code quality, and execute efficiently

Ⅳ. Server Architecture Evolution


  • Add a reverse proxy, similar to a gateway
text
The first step in preparing for a larger scale architecture is to add a "reverse proxy"
Routing forwards the request to the correct endpoint
health examination
Authentication ensures that the user is actually allowed to access the server
Firewalls ensure users can only access the parts of the network we allow them to use

text
The load balancer distributes the requests to the two servers. User 1 goes left, User 2 goes right, User 3 goes left again.

  • extended database
text
The integrated orm is based on mongodb, which can support distributed deployment
mongodb,Replica set deployment (master-slave mode), data synchronization, read-write separation,
mongodb,Fragmentation deployment, failover (disaster recovery)

text
As the development team grows with the application, more and more developers are working on the same server, and the potential for conflicts is high.
At this time, it is a better choice to split the business through microservices.

Microservices can be scaled individually to better adapt to demand. Development teams are independent from each other, each responsible for their own microservice lifecycle
Each microservice has its own resources, such as a database

  • Caching and Content Delivery Network (CDN)
text
A large part of web applications consists of static resources, such as images, CSS style files, Java scripts, and some pre-rendered pages for specific products, etc.
Game applications also contain a large number of image resources, 3D modeling resources
An enhanced version of the cache is called the Content Delivery Network (Content Delivery Network), a large number of caches all over the world.
This allows users to fetch web content from places that are physically close to them, rather than moving data from the source to the user each time.

  • message queue
text
When the traffic peaks, sometimes it is necessary to process a large number of flash sales such as Double 11, so that a large number of sudden requests can be queued up to process tasks
application decoupling
message distribution

  • Fragmentation, partitioning, such as assigning users to the closest server to provide services

Ⅴ. Dependent middleware zookeeper tutorial

Ⅵ. Reference article


Overview (`orm/README.md`)

English | 简体中文

Ⅰ. Introduction

  • orm Based on MongoDB's orm framework, it provides a
    mapping between POJO objects and Mongo DB databases
  • MongoDB is a distributed database that can be used on a single machine or distributed in a single machine
  • Orm can directly use the MongoDB official driver to operate the database

Ⅱ. Use

1. Direct use (low level api) to directly operate the database through the api provided by the official MongoDB driver

  • Start by getting the Collection through Orm Manager
text
var collection = OrmContext.getOrmManager().getCollection(UserEntity.class)
  • Manipulate collections through collections
    • insert,collection.insertOne(obj)
    • delete,collection.deleteOne(obj)
    • update,collection.updateOne(obj)
    • query,collection.find(Filters.eq("_id", userId))

2. Indirect use (middle level API) to access data through the collection's simple wrapper IAccessor and IQuery interfaces

  • IAccessor is a data access interface

    • Inserting data into the database uses the field value of the object's field which marked @Id as the primary key
    text
    OrmContext.getAccessor().insert(obj)
    • To delete data in the database, the return value of the id() method of the object will be used as the search
      keyword, and the data with this id() as the main key will be deleted
    text
    OrmContext.getAccessor().delete(obj);
    • Modify the data in the database
    text
    OrmContext.getAccessor().update(obj);
    • Load data from the database
    text
    OrmContext.getAccessor().load(id, class);
  • IQuery is data complex query interface

    • The methods currently offered are: queryFieldLike,queryAll,queryFieldEqual,queryFieldIn,pageQuery

3. Cache usage (high level API), cache entity regular refresh cache to the database

  • Specify a list of policies for the database and cache through the following configuration
text
<orm:config id="config" entity-package="com.zfoo.orm.**.entity">

    <orm:host database="${mongodb.database}" user="${mongodb.user}" password="${mongodb.password}">
        <orm:address name="${mongodb.address.name}" url="${mongodb.address.url}"/>
    </orm:host>

    
    <orm:caches>
        <orm:cache strategy="default" size="6000" expire-millisecond="600000"/>
        <orm:cache strategy="thousand" size="1000" expire-millisecond="600000"/>
        <orm:cache strategy="threeThousand" size="3000" expire-millisecond="600000"/>
    </orm:caches>

    
    <orm:persisters>
        <orm:persister strategy="default" type="time" config="600000"/>
        <orm:persister strategy="cron30s" type="cron" config="0/30 * * * * ?"/>
        <orm:persister strategy="time30s" type="time" config="30000"/>
    </orm:persisters>
</orm:config>

database indicates which database to operate
address indicates the address of the database and supports sharding configuration
  • mappings through annotations
text
@EntityCaches(cacheStrategy = @Cache("tenThousand"), persister = @Persister("time30s"))
public class UserEntity implements IEntity<Long> {
}

cache strategy represents a caching strategy, the data in the database is first read into the Entity Caches cache in Orm, 
such as thousand, which means that 1000 pieces of data in the cache database expire in 10 minutes

persisters represents a persistence strategy, such as time 30 s, which means that the cached data in the Entity Caches is 
written to the database every 30 seconds, and even if it goes down midway, only 30 s seconds of data is lost
  • How to use the cache

    1. By annotation
    text
    @Component
    public class UserManager {
    
        @EntityCachesInjection
        public IEntityCaches<Long, UserEntity> userEntityCaches;
    
    }
    1. Dynamically obtained through classes
    text
    IEntityCaches<Long, UserEntity> userEntityCaches = OrmContext.getOrmManager().getEntityCaches(UserEntity.class);
  • Update the object

text
userEntityCaches.update(entity);

Ⅲ. Notes

  • If you don't want to map an attribute, just add the transient keyword
  • Supports basic data properties (byte, short, int, long, float, double, boolean), string String, custom objects, does
    not support generics
  • Arrays support one-dimensional arrays, and collections support List, Set
  • Database primary keys can use integers as much as possible, because Mongo DB's default primary key is a string, which
    takes up space
  • The database uses a self-developed ORM framework, such as an entity class User Entity, which maps to the collection in
    the database as user, with the first letter lowercase, and the Entity removed
  • Intelligent parsing, does not support generic and circular referenced objects, and the wrong entity object definition
    will fail to start the program with an error warning

Ⅳ. Tutorial

  • test contains all tutorials for
    adding, deleting, and modifying, please install Mongo DB before running

Overview (`protocol/README.md`)

English | 简体中文

Ⅰ. Introduction

  • A decentralized serialization library, secure, private, reliable, and compatible, allowing everyone to have a unique
    set of protocols
  • The protocol can customize the private protocol format to make your protocol more secure, and supports adding fields
    and being compatible with previous and subsequent protocols
  • Support to generate ProtoBuf's Proto file to Pojo protocol file, and the generated protocol can be converted to other
    protocols and used by Java
  • The protocol is currently natively supported C++ Rust Java/Kotlin/Scala JavaScript/TypeScript/ES C# Go Php Ruby Lua
    GDScript Python Dart Swift

Ⅱ. Quick use

  • Environment requirement JDK 17+, support OpenJDK, Oracle JDK and native GraalVM
text
// The zfoo protocol is registered and can only be initialized once
ProtocolManager.initProtocol(Set.of(ComplexObject.class, ObjectA.class, ObjectB.class));

// serialization
ProtocolManager.write(byteBuf, complexObject);

// deserialization
var packet = ProtocolManager.read(buffer);

Ⅲ. Performance testing

text
system:win10
cpu: i9900k
memory:64g
  • Single-threaded test with abscissa as the number of objects serialized and deserialized and time spent in milliseconds
    on the ordinate

Ⅳ. Why fast

  • Use Javassist bytecode to enhance the dynamic generation of serialization and deserialization functions for sequential
    execution, and sequential functions can be easily JIT compiled to achieve extreme performance
  • Natively integrated with netty's high-performance ByteBuf, support Zero Copy
  • With primitive type collection, there is no boxing and unboxing, invalid GCs are avoided, and the performance is fast
    enough
  • thread-safe and lock-free, without any performance loss in multi-threaded environment
  • No reflection, no unsafe operations, support GraalVM
  • Flattening the call depth of the method stack, and there is no performance penalty for nesting data structures, such
    as List<Set<Map<>>>; Comparing kryo and protobuf data structure nesting results in a performance penalty
  • There is no risk of vulnerability injection, only bytecode enhancement will be performed during initialization, and no
    bytecode operations will be performed in the later stage
  • Taking advantage of the principle of program locality, the serializer is placed in the short[] array, and the object
    serialization and deserialization will only look for the serializer once
text
The data compression volume is small, and the compression volume is smaller than that of Kryo and Protobuf; Smaller than kryo because kryo needs to write the registration number of each object
Intelligent syntax, incorrect protocol definitions will fail to start the program and give an error warning
Improve development efficiency, fully support POJO development, very easy to use

Ⅴ. Why small

  • Lightweight implementation, core serialization and deserialization code of about a thousand lines
  • Optimized the zigzag and varint encoding algorithms for int and long, avoiding some redundant method calls and bit
    operations
  • The data compression volume is small, and the compression volume is smaller than that of Kryo and Protobuf; Smaller
    than kryo because kryo needs to write the registration number of each object
  • Intelligent syntax, incorrect protocol definitions will fail to start the program and give an error warning
  • Improve development efficiency, fully support POJO development, very easy to use
text
The current size of the serialized object is as follows:
Simple objects, zfoo package size 8, kryo package size 5, protobuf package size 8
Regular objects, ZFOO package size 430, KRYO package size 483, Protobuf package size 793
For complex objects, ZFOO package size 2216, KRYO package size 2528, and Protobuf package size 5091

Ⅵ. Data type

  • Default data format support eliminates the need for users to register
    manually.Reference class definition

    • boolean,byte,short,int,long,float,double,String
    • Boolean,Byte,Short,Integer,Long,Float,Double,String,If it is null during serialization, a default value will be
      given
    • int[],Integer[],If it is null, it is parsed as an array of length 0
      • Native generic List, Set, Map, deserialization return type Hash Set, Array List, Hash Map, and null pointer
        safe (returns a collection of size 0)
      • List,You must specify a generic class if [1,1,null,1] is sent and [1,1,0,1] is received
      • List,If [obj,obj,null,obj] is sent, [obj,obj,null,obj] is received, that is, the reference type is
        null before serialization, and it is also null after serialization
  • Unsupported data formats, because ZFOO automatically recognizes unsupported types and gives error warnings, so users
    don't have to care too much

    • int[][],Arrays above two dimensions, considering that not all languages support multidimensional arrays
    • List[],Map[],The Java language itself does not support generic class arrays
    • List,Map,Generics are set in arrays, which looks strange and has few actual uses
    • char or Character, many other languages do not support char and can be replaced with string
    • Enumerated classes, many other languages do not support enumerated classes and can be replaced with int or string
    • Custom generic class XXX Class, generic classes are prone to performance and parsing problems in many
      frameworks, and are not supported in all languages
    • Circular references, although the underlying support circular references, but considering that circular references
      bring semantically difficult to understand and prone to errors, so they are blocked

Ⅶ. Protocol specifications

  • The protocol class must be a simple javabean, not inheriting from any other class, but can inherit an interface

  • The protocol number is defined as a short type to reduce the packet size and memory size, a packet can be reduced by 2
    bytes, and the application memory of each protocol can also be reduced by 6 byte(protocols + IProtocolRegistration +
    protocolIdMap)

text
It is difficult for a project's protocol body class to exceed 3 w, and there will be tools that automatically package 
your protocol number a little more compactly, so that your protocol number will not exceed 3 w
  • There are four ways to indicate that the protocol class

    • The first uses annotations: @Protocol(id = protocolId)

      text
      @Protocol(id = 104)
      public class SimpleObject {
      
          public int c;
          public boolean g;
      
      }
    • The second use: Register the agreement through Protocol Manager.initProtocolAuto() without writing the protocol
      number

      text
      public class SimpleObject {
      
          public int c;
      
          public boolean g;
      
      }
    • The third use: Register the protocol through ProtocolManager.initProtocol(xmlProtocols) in the protocol.xml file

      text
      <protocols>
          
          <module id="1" name="common">
              <protocol id="100" location="com.zfoo.protocol.packet.ComplexObject"/>
              <protocol id="101" location="com.zfoo.protocol.packet.NormalObject"/>
              <protocol id="102" location="com.zfoo.protocol.packet.ObjectA"/>
              <protocol id="103" location="com.zfoo.protocol.packet.ObjectB"/>
              <protocol id="104" location="com.zfoo.protocol.packet.SimpleObject"/>
              <protocol id="105" location="com.zfoo.protocol.packet.VeryBigObject"/>
              <protocol id="106" location="com.zfoo.protocol.packet.EmptyObject"/>
          </module>
          
          <module id="2" name="native">
              <protocol location="com.zfoo.net.packet.common"/>
              <protocol location="com.zfoo.tank.common.protocol.common"/>
          </module>
      </protocols>
    • The fourth use: generate a protocol with a protocol number by defining a proto file, so that the protocol can be
      easily registered

      text
      syntax = "proto3";
      package test.message;
      
      message SimpleObject {
          int64 aa = 1;
      }
      
      // If the tag of a field exceeds 1000, the field is considered to be a compatible protocol field
      message OneMessage {
          // This is a comment on the field
          int64 id = 1;
          // This is equivalent to adding a @Compatible annotation to this field
          string name = 1001;
      }
  • If you add a field for version compatibility, you need to add a Compatible annotation, and the order needs to be
    naturally increased, so as to ensure that the old and new protocols can be compatible with each other, Protocol
    nesting is also still compatible

  • In order to be compatible with versions and avoid modifying field names, default uses field names to read and write
    in the natural order of strings (can also be customized), so it will cause exceptions in serialization

  • The official environment does not necessarily have to delete an unwanted field in order to be version compatible and
    avoid reducing fields

  • Among the six principles of design patterns, the principle of opening and closing is open to expansion and closed to
    modification. The design of the protocol should also adhere to this principle when it comes to functionality,
    prioritizing the addition of new protocols over modifying existing ones

Ⅷ. The difference between zfoo and Protobuf

  • Protobuf can delete fields, but ZFOO does not support deleting fields, which improves performance by 1x and reduces
    the size by 1x at the expense
text
In fact, the officially launched project almost did not encounter anyone who would delete the field, 
and if this field was deleted, the server had to change the code not to reference the deleted field, 
and the client had to change the code not to reference the deleted field, which doubled the workload. 
If either of them forgets to modify the code, it will directly report an error, 
so adding a discarded field @Deprecated comment to this field in the actual project can avoid a lot of unnecessary trouble.
  • zfoo takes the intersection of type declarations in all languages, instead of protobuf taking the union, simplifying
    the type implementation of protobuf

    • protobuf
      text
      double
      float
      int32
      int64
      uint32
      uint64
      sint32
      sint64
      fixed32
      fixed64
      sfixed32
      sfixed64
      bool
      string
      bytes
      bytes
    • zfoo
      text
      float
      double
      byte
      int16
      int32
      int64
      bool
      string
  • zfoo takes the intersection of the grammars of all languages, instead of the union of protobuf, and adds the grammar
    implementation of protobuf

    • protobuf
      text
      Collection nesting syntax is not supported
    • zfoo
      text
      Supports nested collection syntax
  • Simplified protobuf syntax, no enumeration, no oneof, no optional


Overview (`scheduler/README.md`)

English | 简体中文

Ⅰ. Introduction

  • scheduler The time task scheduling bus, cron
    expression parsing uses Spring's own interpreter pattern

Ⅱ. Time task scheduling

  • Adjusting the local machine time before and after triggers task scheduling, and local development is very useful
  • ScheduledExecutorService.triggerPerSecond() executed every second,loop through the executable scheduler
  • zfoo believes that a program does not have much time to schedule, so the Scheduled Executor Service has only one
    thread, so users should avoid doing time-consuming and blocking operations
  • zfoo scheduler uses Javassist bytecode enhancement technology to dynamically proxy time scheduling tasks, avoiding
    reflections and no performance loss

Ⅲ. Cron Expression Example

text
/* Detailed source-code truncated for AI context efficiency. */

Overview (`storage/README.md`)

English | 简体中文

Ⅰ. Introduction

  • storage
    Java pojo and excel/csv/json automatic mapping framework, only need to define a class corresponding to Excel, directly parse
    Excel, json, csv

  • Take advantage of the reflection nature of the Java dynamic language to parse Excel without any code

  • Arrays or collections support null safe, and empty arrays or collections resolve to arrays or collections of length 0

  • Empty strings are parsed to string of length 0, and empty object are parsed to null

  • Support Excel to export json, csv files

Ⅱ. Automatic mapping

  • The first line of Excel corresponds to the Java class attribute, and the second and third lines do not serve as
    comments, where the first column must be the Id attribute

  • The Java class for Excel

  • In addition, you can also use the record class provided by Java's new features

  • After parsing, there are two ways to use it

    1. By annotation
    text
    @Component
     public class StudentManager {
    
      @ResInjection
      private IStorage<Integer, StudentResource> studentResources;
    
      }
    1. Dynamically obtained through classes
    text
    IStorage<Integer, StudentResource> studentResources = StorageContext.getStorageManager().getStorage(StudentResource.class);
  • Find the corresponding row by id

text
var studentResource = studentResources.get(1000);

Alternatively, it can be obtained through the following methods

text
var resource = StorageContext.get(StudentResource.class, 1001);
  • Find the corresponding row by index, default to a repeatable index, and return a list
text
var students = studentResources.getIndex(StudentResource::getName, "james0");

If you are a record class, the usage is as follows

text
var students = studentStorage.getIndexes(StudentResource::name, "james0");
  • The unique index is obtained through Storage.getUniqueIndex(), and the index annotation needs to be marked as @Index(
    unique = true)
text
StudentResource student = storage.getUniqueIndex(StudentResource::idCard, "110101200007281903");

Ⅲ. Hot update Excel Json

  • tank
    Distributed hot update Excel Json csv configuration file implementation

Ⅳ. Use

  • Financial analysis, data analysis statistics
  • Numerical configuration in the game

--- METRICS ---