Soul Gateway learns Admin source code analysis

Author: Zeng Linhui

Source code analysis

1. Page operation source code analysis

Before analyzing the source code, take a look at the following figure. The page shows that the list of plug-ins loaded will correspond to the request of the back end. According to the request of the back end, find the corresponding Controller classThen find the corresponding method. As you can see in the figure above, this is to access the mapping in plugin, which is empty by default, pass in the page-related parameters, and query the corresponding plug-in record in the databaseThe corresponding tables in the database are shown below, and Divide is in the enabled state, which was used to test the gateway in the previous articleThe selector is also requested, and the requested controller is shown below. In the previous demo, we added the conditional CRUD in the selector directly to the gateway in real time without restarting the gateway, so there is a publishEvent method except for query, add, delete, and modify methods after saving to the database. It is this event method that allows users to configure rules directly in the Soul background to take effect all the time

public int createOrUpdate(final SelectorDTO selectorDTO) {
        int selectorCount;
        SelectorDO selectorDO = SelectorDO.buildSelectorDO(selectorDTO);
        List<SelectorConditionDTO> selectorConditionDTOs = selectorDTO.getSelectorConditions();
        if (StringUtils.isEmpty(selectorDTO.getId())) {
            selectorCount = selectorMapper.insertSelective(selectorDO);
            selectorConditionDTOs.forEach(selectorConditionDTO -> {
                selectorConditionDTO.setSelectorId(selectorDO.getId());
                selectorConditionMapper.insertSelective(SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO));
            });
        } else {
            selectorCount = selectorMapper.updateSelective(selectorDO);
            //delete rule condition then add
            selectorConditionMapper.deleteByQuery(new SelectorConditionQuery(selectorDO.getId()));
            selectorConditionDTOs.forEach(selectorConditionDTO -> {
                selectorConditionDTO.setSelectorId(selectorDO.getId());
                SelectorConditionDO selectorConditionDO = SelectorConditionDO.buildSelectorConditionDO(selectorConditionDTO);
                selectorConditionMapper.insertSelective(selectorConditionDO);
            });
        }
        publishEvent(selectorDO, selectorConditionDTOs);
        return selectorCount;
    }
Copy the code

2. Source code analysis with soul-Bootstrap Data synchronization (Websocket)

The data was saved to the database after the admin page operation, and then the spring responsive programming was used to synchronize the data to the Bootstrap project, so as to dynamically refresh the gateway rules and plug-ins without restarting the gateway after adding configurations. When soul-Bootstrap starts, the log will type a paragraph like this

The 00:33:39 2021-01-21. 14276-620 the INFO [0.0-9095 - exec - 5] O.D.S.A.L.W ebsocket. WebsocketCollector: websocket on open successful....Copy the code

So the question is, who does it connect to with webSocket, and how? Now let’s debug by finding the code to log, and then by breaking the point, here is where the log comes outLet’s examine this code first:

  • Get the requested address for the configuration from the websocketConfig configuration, which of course is configured in the following image
  • Once you have this configuration address, you create a timed thread pool with the size of urls.length and the thread name prefix “websocket-connect” daemon thread. The reason for creating daemons is that it is only necessary to ensure that the websocket connection between bootstrap and admin is continuously connected, which is similar to the heartbeat function, so it is best to use daemons
  • According to the client created, request the address of the configuration file one by one, and then print the previously found log
  • The thread is then started to determine if the client is closed and reconnects if it is closed (initial interval is 10 seconds, then check every 30 seconds, so if you see that the console sometimes prints multiple successful connection logs, it is reconnected)

  • After saving or updating data in the background, the publishEvent method is called. This method is a spring reactive programming method. Since it is reactive, it is event-based. You have to have a listener

If you still don’t understand the connection between the listener and the previous publishEvent, break the code in the listener and debug it. I’m just going to click on this for convenience to synchronize all the dataHere into the DataChangedEventDispatcher this class, call the event related methods, in the lower left corner of this place, is to see the familiar methods, yes is publishEvent stated above

  • Then jump to WebsocketDataChangedListener this class, highlighted here have a look at the send method in the debug method

  • Admin sends the updated data to bootstrap by sending it to bootstrap

3. Source code analysis with soul-Bootstrap data synchronization (ZooKeeper

If you want to enable the local or remote ZooKeeper service, then start soul-adminFirst entered the ZookeeperDataInit run method of a class, this method performs, the strange thing is jumped WebsocketDataChangedListener classThat do not understand, such as the class onPluginChanged method after the execution, returned to ZookeeperDataChangedListener to classIf not deleted, the zkNode node data is updatedMethod to update the ZK nodeAnd after onSelectorChanged, onMetaDataChanged, onRuleChanged methods will go first WebsocketDataChangedListener class corresponds to approach, Before it into a ZookeeperDataChangedListener class. If the plug-in data changes, repeat the steps above. The poM file has a dependency on websockets. Since the websocket configuration is commented out in the application.yml file (not enable=false), comment out the dependency and see if the code does not compile properly. Another option is to disable webSocket, and then restart to find that it will no longer jump to webSocket-related classes

4. Source code analysis with soul-Bootstrap data synchronization (HTTP)

If you are using HTTP, websocket-related classes will still be accessed. If you are using HTTP, websocket-related classes will still be accessed

Here’s a constructor that instantiates a clients array blocking queue of size 1024. A timed task thread pool with 1 thread and a name prefix of “long-polling” background daemon thread. A related attribute configuration is that the timed thread is started in the method before initialization, and after a 5 minute interval, refreshLocalCache is executed every 5 minutes to refresh the local cache

    private void refreshLocalCache() {
        this.updateAppAuthCache();
        this.updatePluginCache();
        this.updateRuleCache();
        this.updateSelectorCache();
        this.updateMetaDataCache();
    }
Copy the code

When synchronizing data manually, the following related methods are executed, again from a timed thread pool, but immediatelyAfter five minutes, perform the relevant refresh method to print the log

The 2021-01-22 01:00:19. 20800-007 the INFO [- long - polling - 2] A.L.H.H ttpLongPollingDataChangedListener: HTTP sync Strategy refresh config start. 2021-01-22 01:00:19.010 INFO 20800 -- [-long-polling-2] o.d.s.a.l.AbstractDataChangedListener : update config cache[APP_AUTH], old: {group='APP_AUTH', md5='d751713988987e9331980363e24189ce', lastModifyTime=1611248118794}, updated: {group='APP_AUTH', md5='d751713988987e9331980363e24189ce', LastModifyTime =1611248419010} 2021-01-22 01:00:19.012 INFO 20800 -- [-long-polling-2] o.d.s.a.l.AbstractDataChangedListener : update config cache[PLUGIN], old: {group='PLUGIN', md5='70b269257d47f0f6404ae7b7e976d8f1', lastModifyTime=1611248295740}, updated: {group='PLUGIN', md5='70b269257d47f0f6404ae7b7e976d8f1', LastModifyTime =1611248419012} 2021-01-22 01:00:19.069 INFO 20800 -- [-long-polling-2] o.d.s.a.l.AbstractDataChangedListener : update config cache[RULE], old: {group='RULE', md5='5811b56257e31109621976d39fc226aa', lastModifyTime=1611248301607}, updated: {group='RULE', md5='5811b56257e31109621976d39fc226aa', LastModifyTime =1611248419069} 2021-01-22 01:00:19.075 INFO 20800 -- [-long-polling-2] o.d.s.a.l.AbstractDataChangedListener : update config cache[SELECTOR], old: {group='SELECTOR', md5='70bad5ebb1cf6e3fc55278eef2df42f3', lastModifyTime=1611248299419}, updated: {group='SELECTOR', md5='70bad5ebb1cf6e3fc55278eef2df42f3', LastModifyTime =1611248419075} 2021-01-22 01:00:19.077 INFO 20800 -- [-long-polling-2] o.d.s.a.l.AbstractDataChangedListener : update config cache[META_DATA], old: {group='META_DATA', md5='5f79d821e3b601330631a2d53294fb34', lastModifyTime=1611248302571}, updated: {group='META_DATA', md5='5f79d821e3b601330631a2d53294fb34', LastModifyTime =1611248419077} 2021-01-22 01:00:19.077 INFO 20800 -- [-long-polling-2] a.l.h.HttpLongPollingDataChangedListener : http sync strategy refresh config success.Copy the code

5. Soul has other ways to synchronize data

The soul-admin source code has been analyzed for a long time. The soul-admin source code has been analyzed for a long time. The soul-admin source code has been analyzed for a long time

conclusion

Soul-admin has some functionality that is not yet available, and a lot of fun stuff. This post will continue to be updated, and we will analyze the source code in detail when it is used.

  1. 2021-01-20 Analyzed soul-admin using websocket to synchronize data to soul-bootstrap
  2. 2021-01-21 Analysis of soul-admin using ZooKeeper to synchronize data to soul-bootstrap
  3. 2021-01-21 analyses soul-admin using HTTP to synchronize data to soul-bootstrap