Write a rpc frame from 0.5 to 1-4: request filter

Write a rpc frame from 0.5 to 1-4: request filter

For the convenience of subsequent expansion, to create a filter support, just copy a servlet filter.

Servlet filter analysis

When writing mvc projects, filters are often used, and a request can be pre- or post-processed. as follows:

@WebFilter(filterName = "requestFilter", urlPatterns = "/*")
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("filter init");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException {
        System.out.println("I came in");
        chain.doFilter(request, response);
        System.out.println("I'm leaving");
    }

    @Override
    public void destroy() {
        System.out.println("filter destroy");
    }
}

This is the realization of a responsibility chain model, debug look at the call stack to understand how the framework is implemented.

  • Generate a FilterChain object for each request, and make it hold the array of all filters, and initialize the member variable pos=0 (indicating which filter should be executed)
  • The entire chain is called from FilterChain.doFilter. Starting from the first filter, the chain itself is passed to the filter when calling, and pos is incremented.
  • If a filter does not intercept this request, it will call FilterChain.doFilter. Since pos has been incremented, the next filter will be called.
  • After all filters are called (pos=filters.length), the request is actually executed
  • After the request is returned, it will pass through all the filters (reverse order)

rpc filter implementation

Define the filter interface. If users want to add filter logic, they need to integrate this interface.

public interface RpcFilter {
    void doFilter(RpcRequest request, RpcResponse response, RpcFilterChain filterChain);
}

filter holder

public class RpcFilterChain implements RpcCode {
    private RpcFilter[] filters = new RpcFilter[0];
    private int pos;
    private RpcServiceInfo serviceInfo;
    private RpcServiceExecutor serviceExecutor;//The processor that will eventually execute the request

    public RpcFilterChain(List<RpcFilter> filterList, RpcServiceInfo serviceInfo, RpcServiceExecutor serviceExecutor) {
        if (filterList != null && !filterList.isEmpty()) {
            this.filters = new RpcFilter[filterList.size()];
            this.filters = filterList.toArray(this.filters);
        }
        this.serviceInfo = serviceInfo;
        this.serviceExecutor = serviceExecutor;
    }

    public void doFilter(RpcRequest request, RpcResponse response) {
        if (pos <filters.length) {
            RpcFilter filter = filters[pos++];
            filter.doFilter(request, response, this);
            return;
        }
        if (serviceExecutor == null) {
            response.error(SERVICE_NOT_FOUND, "service not exist: "+ serviceInfo);
            return;
        }
        serviceExecutor.execute(request, response);
    }

}

After receiving the request, the rpc server initializes a responsibility chain and then triggers it.

public RpcResponse execute(RpcRequest rpcRequest) {
        RpcServiceInfo rpcServiceInfo = new RpcServiceInfo(rpcRequest.getAppName(), rpcRequest.getServiceName());
        RpcFilterChain chain = new RpcFilterChain(filters, rpcServiceInfo, serviceExecutorMap.get(rpcServiceInfo));
        RpcResponse rpcResponse = new RpcResponse();
        try {
            chain.doFilter(rpcRequest, rpcResponse);
        } catch (Exception e) {
            rpcResponse.error(e);
        }
        return rpcResponse;
    }