Implementation of Lightweight Process Control Component Based on netty http protocol stack, netty protocol stack

Source: Internet
Author: User
Tags switch case

Implementation of Lightweight Process Control Component Based on netty http protocol stack, netty protocol stack

Today is the winter solstice, the so-called "Winter New Year", the company should also let everyone go home at five o'clock to eat dumplings and drink mutton soup, I still insist on staying in the company because of my high professional qualities (in fact, I can only stay in the company to eat the canteen because I don't have dumplings to eat or have mutton broth to drink ......). Over the past hour, I would like to introduce nettice, a Lightweight Process Control Component Based on the netty http protocol stack ), at present, some functions have been implemented and will be continuously improved, hoping to solve some development problems for everyone (or at least provide some ideas ).

What is a process control component?

In simple terms, the service process is in an interaction process. For the client side, it is from the request assembly and sending, A Sequential stream of response receiving, parsing, and business processing. For the server side, it is from the request receiving, parsing, and business processing, A Sequential stream of response assembly and sending. The process control component mentioned in this Article refers to the process of developing an http server using the netty http protocol stack to ensure that the process is executed in this order, at the same time, the general non-business logic is abstracted and transparent to the upper layer, so that developers only need to pay attention to the underlying Implementation of the business logic.

Why is such a component required?

An http server usually needs to process multiple business logic. Each business logic corresponds to one request message and one response message, the server needs to automatically distribute these different messages to the corresponding business logic for processing.

However, we should be familiar with all the children's shoes that have developed http servers using the netty http protocol stack. netty does not provide message distribution components.

In this case, you can only differentiate services by a special identifier (such as a field value) in the request message, and use switch case for processing. But in this way, as the business logic increases, the switch case code block will become longer and longer, which greatly affects code readability. In addition, each time you add or delete a business logic, you must modify the logic code, later maintenance is becoming more and more troublesome.

In addition, when netty http protocol stack is used, direct parsing and ing of client parameter to service method input parameters on the server is not provided.

What does this sentence mean? For example, if you use httpclient on the client to send a message to the netty http server, the transfer parameter is "project = nettice & author = cyfonly ", the server has a business method public void bizHandle (String project, String author). Before you call the bizHandle method, you must first manually write the code to parse the Request Parameters of the client to parse the values corresponding to the two keys of the project and author.

The problem is that when the business logic is increasing, you have to write a piece of Parameter Parsing Code for each request. What a pain point is this, and there are a lot of business logic code to write in the future!

Is there a way to avoid distributing requests by writing switch case code segments and parse all request parameters in a unified way?

Of course, nettice was born to solve this problem ~~

What can nettice do?Features

  • Receive Assembly request data, process control, and rendering data
  • URI-to-method direct ing and namespace
Function
  • Process Control for HttpRequest
  • Process http requests like normal methods
  • Automatically assemble the requested data and support basic types, List, Array, and Map
  • Provides Render rendering and write-back responses, and supports multiple Content-types.
  • Supports configurable namespaces
How is nettice designed and implemented?

The overall design of message distribution is as follows (a picture is better than a thousand words ):

How to Use nettice?Nettice import Project

Nettice is easy to use as a component. Here we use specific chestnuts for Instructions (Please click here for the demo code ).

The first is to introduce the nettice-core.jar, or directly use the nettice-core source code as the module of the maven project (which is not uploaded to the maven repository currently and cannot be introduced through the pom dependency ). Then define the necessary configurations of the nettice component nettice. xml:

<? Xml version = "1.0" encoding = "UTF-8"?> <Router> <action-package> <package> com. server. action </package> </action-package> <namespaces> <! -- Assign a namespace by package. When multiple matching items exist, use the directory-level highest --> <namespace name = "/nettp/" packages = "com. server. action. * "> </namespace> <namespace name ="/nettp/sub/"packages =" com. server. action. sub "> </namespace> </namespaces> </router>

Finally, add the message distribution handler to the server:

.addLast("dispatcher",new ActionDispatcher())

Now you can use the nettice function!

Note that the business processing class must inherit BaseAction to be recognized by the nettice component!

URI ing and namespace

Use the method name as the URI ing keyword. If a method with the same name exists in the project, the developer can use the @ Namespaces annotation or in nettice. add namespaces in xml configuration to modify URI ing to avoid this problem.

For example, com. server. action. DemoAction provides the returnTextUseNamespace () method and com. server. action. sub. SubDemoAction also provides the returnTextUseNamespace () method, but the two methods implement different functions. By default, the nettice component uses the method name for URI ing. The preceding two returnTextUseNamespace () Methods conflict, and developers can use the @ Namespace annotation to modify the URI ing:

package com.server.action;public class DemoAction extends BaseAction{      @Namespace("/nettp/demo/")      public Render returnTextUseNamespace(@Read(key="id") Integer id, @Read(key="project") String project){              //do something              return new Render(RenderType.TEXT, "returnTextUseNamespace in [DemoAction]");      }}
package com.server.action.sub;public class SubDemoAction extends BaseAction{      @Namespace("/nettp/subdemo/")      public Render returnTextUseNamespace(@Read(key="ids") Integer[] ids, @Read(key="names") List<String> names){            //do something            return new Render(RenderType.TEXT, "returnTextUseNamespace in [SubDemoAction]");      }}

You can also set it in nettice. xml:

<namespaces>    <namespace name="/nettp/demo/" packages="com.server.action.*"></namespace>    <namespace name="/nettp/subdemo/" packages="com.server.action.sub"></namespace></namespaces>
Receive Assembly request data

The @ Read annotation can be used to automatically assemble request arrays. Different types (basic type, List, Array, and Map) are supported, and default values can be set. Currently, only defavalue value can be set for basic types ).

Basic Data Type Parsing

This example demonstrates how to obtain the basic type from HttpRequest. If there is no value, the default value is automatically set.

Client request:

private static void sendGetPriType() throws Exception{    String path = "http://127.0.0.1:8080/nettp/primTypeTest.action?";    String getUrl = path + "id=10001&project=nettice&author=cyfonly";    java.net.URL url = new java.net.URL(getUrl);    java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();    conn.setRequestMethod("GET");    conn.setDoOutput(true);    conn.connect();    if(conn.getResponseCode() == 200){        BufferedReader in = new BufferedReader(new InputStreamReader((InputStream) conn.getInputStream(), "UTF-8"));        String msg = in.readLine();        System.out.println("msg: " + msg);        in.close();    }    conn.disconnect();}

Server method:

public Render primTypeTest(@Read(key="id", defaultValue="1" ) Integer id, @Read(key="project") String project, @Read(key="author") String author){    System.out.println("Receive parameters: id=" + id + ",project=" + project + ",author=" + author);    return new Render(RenderType.TEXT, "Received your primTypeTest request.[from primTypeTest]");}

Output result:

Receive parameters: id=10001,project=nettice,author=cyfonly
List/Array type Parsing

This example demonstrates how to obtain the List/Array type from HttpRequest.

Client request:

private static void sendPostJsonArrayAndList() throws Exception{    String path = "http://127.0.0.1:8080/nettp/sub/arrayListTypeTest.action";    JSONObject obj = new JSONObject();    int[] ids = {1,2,3};    List<String> names = new ArrayList<String>();    names.add("aaaa");    names.add("bbbb");    obj.put("ids", ids);    obj.put("names", names);    String jsonStr = obj.toJSONString();    byte[] data = jsonStr.getBytes();    java.net.URL url = new java.net.URL(path);    java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();    conn.setRequestMethod("POST");    conn.setDoOutput(true);    conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");    conn.setRequestProperty("Content-Length", String.valueOf(data.length));    OutputStream outStream = conn.getOutputStream();    outStream.write(data);    outStream.flush();    outStream.close();    if(conn.getResponseCode() == 200){        BufferedReader in = new BufferedReader(new InputStreamReader((InputStream) conn.getInputStream(), "UTF-8"));        String msg = in.readLine();        System.out.println("msg: " + msg);        in.close();    }    conn.disconnect();}

Server method:

public Render arrayListTypeTest(@Read(key="ids") Integer[] ids, @Read(key="names") List<String> names){    System.out.println("server output ids:");    for(int i=0; i<ids.length; i++){        System.out.println(ids[i]);    }    System.out.println("server output names:");    for(String item : names){        System.out.println(item);    }    JSONObject obj = new JSONObject();    obj.put("code", 0);    obj.put("msg", "Received your Array/List request.[from arrayListTypeTest()]");
    return new Render(RenderType.JSON, obj.toJSONString());}

Output result:

server output ids:123server output names:aaaabbbb

 Map type Parsing

This example demonstrates how to obtain the Map type from HttpRequest.

Client code:

private static void sendPostJsonMap() throws Exception{    String path = "http://127.0.0.1:8080/nettp/sub/mapTypeTest.action";    JSONObject obj = new JSONObject();    Map<String, String> srcmap = new HashMap<String, String>();    srcmap.put("project", "nettice");    srcmap.put("author", "cyfonly");    obj.put("srcmap", srcmap);    String jsonStr = obj.toJSONString();    byte[] data = jsonStr.getBytes();    java.net.URL url = new java.net.URL(path);    java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();    conn.setRequestMethod("POST");    conn.setDoOutput(true);    conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");    conn.setRequestProperty("Content-Length", String.valueOf(data.length));    OutputStream outStream = conn.getOutputStream();    outStream.write(data);    outStream.flush();    outStream.close();    if(conn.getResponseCode() == 200){        BufferedReader in = new BufferedReader(new InputStreamReader((InputStream) conn.getInputStream(), "UTF-8"));        String msg = in.readLine();        System.out.println("msg: " + msg);        in.close();    }    conn.disconnect();}

Server method:

public Render mapTypeTest(@Read(key="srcmap") Map<String,String> srcmap){    System.out.println("server output srcmap:");    for(String key : srcmap.keySet()){        System.out.println(key + "=" + srcmap.get(key));    }    JSONObject obj = new JSONObject();    obj.put("code", 0);    obj.put("msg", "Received your Map request.[from mapTypeTest]");    return new Render(RenderType.JSON, obj.toJSONString());}

Output result:

server output srcmap:author=cyfonlyproject=nettice

Note that only one Map parameter can exist when Map is used.

Rendering data

The processing method is to return the data in a specific format to the client by returning the Render object. A Render object consists of the enumerated type RenderType and data. The nettice component uses RenderType to set the appropriate Content-Type for Response. developers can also extend Render and related classes to support more types.

For example, this is an example of returning a JSON object. The client will receive a Json object:

public Render postPriMap(){    JSONObject obj = new JSONObject();    obj.put("code", 0);    obj.put("msg", "had received your request.");    return new Render(RenderType.JSON, obj.toJSONString());}
What else will be improved?

As mentioned at the beginning, nettice has implemented some functions and does not have much time to optimize its performance. Therefore, it will be improved in the future. Currently, we plan to do the following:

  • Java bean support
  • Parameter Parsing Process Optimization
  • Performance Optimization

However, for the moment, nettice does solve some pain points of using netty http protocol stack to develop http server.

Okay, it's time for dinner. So much will be introduced for now. This article will be improved if it is not introduced or not detailed enough. continue to pay attention to it ~~

If you want to learn more about the code, you are welcome to comment on it, add QQ (869827095), or code it with yourself.

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.