自定义 Filter

SOFARPC 提供了一套良好的可扩展性机制,为各个模块提供 SPI(Service Provider Interface) 的能力。

SOFARPC 对请求与响应的过滤链(FilterChain)处理方式为:

  • 通过多个过滤器 Filter 来进行具体的拦截处理。

  • 允许用户自定义 Filter 扩展,且自定义 Filter 的执行顺序在内置 Filter 之后。

下文将就自定义 Filter 类及其生效进行说明:

自定义 Filter 类

自定义 Filter 类需继承 com.alipay.sofa.rpc.filter.Filter 类。示例如下:

package com.alipay.sofa.rpc.customfilter;

import com.alipay.sofa.rpc.core.exception.SofaRpcException;
import com.alipay.sofa.rpc.core.request.SofaRequest;
import com.alipay.sofa.rpc.core.response.SofaResponse;
import com.alipay.sofa.rpc.filter.Filter;
import com.alipay.sofa.rpc.filter.FilterInvoker;
import com.alipay.sofa.rpc.log.Logger;
import com.alipay.sofa.rpc.log.LoggerFactory;

public class CustomEchoFilter extends Filter{

/**
     * Logger for CustomEchoFilter
     **/
private static final Logger LOGGER =LoggerFactory.getLogger(CustomEchoFilter.class);

@Override
public boolean needToLoad(FilterInvoker invoker){
  // 判断一些条件,自己决定是否加载这个 Filter。
  return true;
}

@Override
public SofaResponse invoke(FilterInvoker invoker,SofaRequest request) throws SofaRpcException{
        // 调用前打印请求。
        LOGGER.info("echo request : {}, {}", request.getInterfaceName()+"."+ request.getMethod(),
        request.getMethodArgs());

        // 继续调用。
       SofaResponse response = invoker.invoke(request);

       // 调用后打印返回值。
       if(response ==null){
            return response;
       }else if(response.isError()){
            LOGGER.info("server rpc error: {}", response.getErrorMsg());
       }else{
            Object ret = response.getAppResponse();
            if(ret instanceof Throwable){
                LOGGER.error("server biz error: {}",(Throwable) ret);
            }else{
                LOGGER.info("echo response : {}", response.getAppResponse());
            }
       }
       return response;
    }
}

自定义 Filter 类生效方式

自定义 Filter 类支持如下生效方式:

  • API 方式

    该方式可以指定生效的 provider 或 consumer。示例如下:

    // 服务提供者
    providerConfig.setFilterRef(Arrays.asList(new CustomFilter()));
    // 服务调用者
    consumerConfig.setFilterRef(Arrays.asList(new CustomFilter()));
  • @Extension 注解 + 扩展文件 + 编码注入

    处理步骤如下:

    1. 处理自定义 Filter 类。

      @Extension("customer")
      public class CustomFilter extends Filter{
           @Override
           public boolean needToLoad(FilterInvoker invoker){
                return true;
           }
          @Override
          public SofaResponse invoke(FilterInvoker invoker,SofaRequest request) throws SofaRpcException{
               SofaResponse response = invoker.invoke(request);
               return response;
          }
      }
    2. 创建扩展文件。

      • 文件名:以 Filter 为后缀。例如:com.alipay.sofa.rpc.filter.Filter

      • 文件路径:为固定路径。位于 META-INF/services/sofa-rpc/ 下。

      完整示例:META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter。扩展文件内容如下:

      customer=com.alipay.sofa.rpc.custom.CustomFilter
    3. 注入编码。

      // 服务提供者
      providerConfig.setFilter(Arrays.asList(“customer”));
      // 服务调用者
      consumerConfig.setFilter(Arrays.asList(“customer”));
  • @Extension 注解 + 扩展文件 + @AutoActive 注解

    处理步骤如下:

    1. 处理自定义 Filter 类。

      @Extension(“customer”)
      @AutoActive(providerSide =true, consumerSide =true)
      public class customerFilter extends Filter{
           @Override
           public boolean needToLoad(FilterInvoker invoker){
              return true;
           }
           @Override
           public SofaResponse invoke(FilterInvoker invoker,SofaRequest request) throws SofaRpcException{
               SofaResponse response = invoker.invoke(request);
               return response;
           }
      }
      说明

      使用 2 个注解 @Extension@AutoActive 处理 Filter 类可以免去编码注入。作用域为所有 provider 或 consumer。其中,参数 providerSide 表示是否生效于服务端;参数 consumerSide 表示是否生效于客户端。

    2. 创建扩展文件。

      • 文件名:以 Filter 为后缀。例如 com.alipay.sofa.rpc.filter.Filter

      • 文件路径:固定路径,位于 META-INF/services/sofa-rpc/ 下。

      完整示例:META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter。扩展文件内容如下:

      customer=com.alipay.sofa.rpc.custom.CustomFilter