1.hello word 一个Motan扩展
大概需要下面的三点:
-
实现SPI扩展点接口
package com.weibo.api.motan.filter; @Spi public interface Filter {Response filter(Caller<?> caller, Request request); }
业务代码实现Filter
public class PlsProviderExceptionFilter implements Filter {@Overridepublic Response filter(Caller<?> caller, Request request) {//实现具体的业务逻辑}
}
-
实现类增加注解
@Spi(scope = Scope.SINGLETON) //扩展加载形式,单例或多例 @SpiMeta(name = "motan") //name表示扩展点的名称,根据name加载对应扩展 @Activation(sequence = 100) //同类型扩展生效顺序,部分扩展点支持。非必填
@SpiMeta(name = "pls-exception-filter") //sequence默认20,越大越先执行完 @Activation(sequence = 100, key = {MotanConstants.NODE_TYPE_SERVICE}) public class PlsProviderExceptionFilter implements Filter {//... }
-
增加SPI实现声明 c l a s s p a t h / M E T A − I N F / s e r v i c e s / {classpath}/META-INF/services/ classpath/META−INF/services/{SPI interface fullname}文件中添加对应SPI接口实现类全名。 可参照motan-core模块/META-INF/services/下的配置
#扩展接口 com.sxl.motan.PlsProviderExceptionFilter
官方对moten扩展机制介绍
filter机制是在client端与server端请求处理是都会经过的过滤机制,使用者可以通过filter来实现对请求的request和response进行定制化处理。 filter扩展的实现方式是通过上述的SPI扩展,使用中有如下问题需要注意。
1、如何使扩展的filter生效。
SPI扩展必须对应一个唯一的name,实际使用中通过name来加载扩展。一般扩展需要在配置中设置对应的name,然后自动加载。
filter扩展默认是不生效的,加载filter的方式分为强制加载和指定加载。如果需要强制生效,可以通过配置@Activation来实现,MotanConstants.NODE_TYPE_SERVICE表示在server端强制生效,MotanConstants.NODE_TYPE_REFERER表示在client端强制生效。 强制生效情况下,不管任何service都会进行filter过滤。 配置样例如下:
@Activation(key = { MotanConstants.NODE_TYPE_SERVICE, MotanConstants.NODE_TYPE_REFERER })
如果只需要在某些service中生效,则可以直接通过在basicService或者service中配置 filter="filter_name"即可,其中的filter_name就是扩展filter中声明的@SpiMeta(name = “***”)中name的值
推荐通过配置方式使用filter,减少不必要的filter装载
2.实现motan异常统一处理核心逻辑
2.1自定义异常类定义
异常枚举
用于规范异常,各个模块维护自己的异常编码。对应的异常编码可以同步 [帮助系统并给出解决方案。方便***用户查找解决***
package com.sxl.exception.errorCode;/*** 系统各平台业务异常枚举* @ClassName: com.sxl.exception.PlsBizErrorCode.java* @author: songxulin* @date : 2021-01-04 15:37* @version V1.0*/
public enum PlsBizErrorCode {/************************** 公共异常 *****************************/E_000000("000000","fail","失败"),E_000001("000001","success","成功"),E_000002("000002","parameterError","请求参数为空"),E_000003("000003","parameterInvalid","请求参数非法"),E_000004("000004","jsonError","JSON转换失败"),E_000005("000005","dbError","数据库异常"),E_000006("000006","networkError","网络异常"),E_000007("000007","unkownError","未知异常"),E_000008("000008","handleDataException","数据处理异常"),E_000009("000009","existed","数据已存在"), E_000010("000010","numberFormatException","数值转换异常"),E_000011("000011","NullPointerException","数据空指针异常"),/************************** 通用模块异常 ******************************/P_C00001("P_C00001","skuParseError","sku解析异常"),;private String code;private String name;private String desc;PlsBizErrorCode(String code, String name, String desc) {this.code = code;this.name = name;this.desc = desc;}@Overridepublic String getCode() {return code;}@Overridepublic String getName() {return name;}@Overridepublic String getDesc() {return desc;}
}
异常抽象类
异常统一继承此类
package com.sxl.exception;import com.sxl.exception.errorCode.ErrorCode;/*** 刊登系统异常抽象类* @ClassName: com.sxl.exception.AbstractException.java* @author: songxulin* @date : 2021-01-04 17:27* @version V1.0*/
public abstract class AbstractPLSException extends RuntimeException{private static final long serialVersionUID = -4470524790791804455L;private String state;private String name;private void init(String code, String name){this.state = code;this.name = name;}private void init(ErrorCode errorCode){init(errorCode.getCode(), errorCode.getName());}private AbstractPLSException(String message) {super(message);}private AbstractPLSException(String message, Throwable cause){super(message,cause);}public AbstractPLSException(String code, String name, String desc){this(desc);init(code, name);}public AbstractPLSException(String code, String name, String desc, Throwable cause{this(desc, cause);init(code, name);}public AbstractPLSException(ErrorCode errorCode){this(errorCode.getDesc());init(errorCode);}public AbstractPLSException(ErrorCode errorCode, String desc){this(desc);init(errorCode);}public AbstractPLSException(ErrorCode errorCode, Throwable cause){this(errorCode.getDesc(), cause);init(errorCode);}public String getState() {return state;}public String getName() {return name;}public String getStateMsg(){return state+":"+getMessage();}
}
自定义异常
package com.sxl.exception;import com.sxl.exception.errorCode.ErrorCode;/*** 刊登系统业务异常* @ClassName: com.sxl.exception.PlsBizException.java* @author: songxulin* @date : 2021-01-04 15:36* @version V1.0*/
public class PlsBizException extends AbstractPLSException {private static final long serialVersionUID = 5600133107550376666L;public PlsBizException(String code, String name, String desc) {super(code, name, desc);}public PlsBizException(ErrorCode errorCode, String desc) {super(errorCode,desc);}public PlsBizException(ErrorCode errorCode) {super(errorCode);}public PlsBizException(ErrorCode errorCode, Throwable cause) {super(errorCode, cause);}
}
异常枚举
package com.sxl.exception;import com.alibaba.fastjson.JSONException;
import com.sxl.exception.errorCode.ErrorCode;
import com.sxl.exception.errorCode.PlsBizErrorCode;
import java.util.HashMap;
import java.util.Map;
/*** 异常枚举* @ClassName: com.sxl.exception.ExceptionEnum.java* @author: songxulin* @date : 2021-01-04 19:38* @version V1.0*/
public enum ExceptionEnum {JSONException("JSONException", JSONException.class, PlsBizErrorCode.E_000004),NumberFormatException("NumberFormatException",NumberFormatException.class, PlsBizErrorCode.E_000010),NullPointerException("NullPointerException",NullPointerException.class, PlsBizErrorCode.E_000010),IllegalArgumentException("IllegalArgumentException",IllegalArgumentException.class,PlsBizErrorCode.E_000008),;private String name;private Class clazz;private ErrorCode errorCode;private static Map<Class,ExceptionEnum> enumMap =new HashMap<>(16);static {for (ExceptionEnum value : ExceptionEnum.values()) {enumMap.put(value.clazz,value);}}ExceptionEnum(String name, Class clazz, ErrorCode errorCode) {this.name = name;this.clazz = clazz;this.errorCode = errorCode;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Class getClazz() {return clazz;}public void setClazz(Class clazz) {this.clazz = clazz;}public ErrorCode getErrorCode() {return errorCode;}public void setErrorCode(ErrorCode errorCode) {this.errorCode = errorCode;}/*** 根据异常类获取对应异常* @param e Class 异常class* @return ExceptionEnum*/public static ExceptionEnum getByClazz(Class e){return enumMap.get(e);}
}
2.2 filter编写
package com.sxl.motan;import com.alibaba.fastjson.JSON;
import com.weibo.api.motan.common.MotanConstants;
import com.weibo.api.motan.core.extension.Activation;
import com.weibo.api.motan.core.extension.SpiMeta;
import com.weibo.api.motan.exception.MotanAbstractException;
import com.weibo.api.motan.filter.Filter;
import com.weibo.api.motan.rpc.Caller;
import com.weibo.api.motan.rpc.DefaultResponse;
import com.weibo.api.motan.rpc.Request;
import com.weibo.api.motan.rpc.Response;
import com.sxl.exception.AbstractPLSException;
import com.sxl.exception.ExceptionEnum;
import com.sxl.exception.PLSServiceException;
import com.sxl.vo.ResultVO;
import com.sxl.vo.VoHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** * @ClassName: com.sxl.motan.PlsProviderExceptionFilter.java* @author: songxulin* @date : 2021-01-04 20:09* @version V1.0*/
@SpiMeta(name = "pls-exception-filter")
//sequence默认20,越大越先执行完
@Activation(sequence = 100, key = {MotanConstants.NODE_TYPE_SERVICE})
public class PlsProviderExceptionFilter implements Filter {private final static Logger log = LoggerFactory.getLogger(PlsProviderExceptionFilter.class);@Overridepublic Response filter(Caller<?> caller, Request request) {Response response;try {response = caller.call(request);} catch (Exception e) {log.error(e.getMessage(), e);return buildExceptionResponse(e);}if (response.getException() != null) {log.error(String.format("%s,%s 调用异常",request.getAttachments().get("host"),request.getMethodName()),response.getException().getCause());return buildExceptionResponse(response);}return response;}/*** 构建异常Response* @param e 异常* @return Response*/private Response buildExceptionResponse(Exception e) {DefaultResponse response = new DefaultResponse();AbstractPLSException ex;//自定义异常if (e instanceof MotanAbstractException) {ex = getException((MotanAbstractException) e);} else {//系统未知异常ex = new PLSServiceException("", "", "系统未知异常");}response.setValue(JSON.toJSONString(formatError(ex)));return response;}/*** 获取异常类型* @param e 异常* @return AbstractPLSException*/private AbstractPLSException getException(MotanAbstractException e) {Throwable cause = e.getCause();if (cause instanceof AbstractPLSException) {return (AbstractPLSException) cause;} else {ExceptionEnum exceptionEnum = ExceptionEnum.getByClazz(cause.getClass());if(exceptionEnum!=null){return new PLSServiceException(exceptionEnum.getErrorCode());}return new PLSServiceException("", "", "系统未知异常");}}/*** 格式化异常* @param e AbstractPLSException* @return ResultVO 自定义返回体*/private ResultVO formatError(AbstractPLSException e) {return VoHelper.getErrorResult(e.getStateMsg());}private Response buildExceptionResponse(Response response) {return buildExceptionResponse(response.getException());}
}
完成上面的代码后,motan接口统一处理就完成了。
3.使用
1. 抛出异常
throw new PlsBizException(PlsBizErrorCode.P_YA0001);
2. motan门面类
异常不进行抓取 ,需要处理异常的地方进行抛出 throws Exception
没有统一处理前
@Override
public String addListing(String jsonParam) {LOGGER.info("新增listing接口被请求,请求参数jsonParam:{}", jsonParam);ResultVO resultVO = new ResultVO();try {//...resultVO = iPlsAliexpressListingService.addListing(data, operator);} catch (ValidatorParameterException vpe) {resultVO.setMsg(vpe.getMessage());resultVO.setState(ResponseCode.FAIL.getCode());} catch (WarningException e) {resultVO.setMsg(e.getMessage());resultVO.setState(ResponseCode.WARNING.getCode());LOGGER.error("AliExpress addListing 新增Listing 侵权检测警告,{} ", e.getMessage(), e);} catch (Exception e) {resultVO.setMsg(e.getMessage());resultVO.setState(ResponseCode.FAIL.getCode());LOGGER.error("新增listing接口异常", e);}return JSONUtils.toJSON(resultVO);
}
统一处理后
@Overridepublic String addListing(String jsonParam) throws Exception{LOGGER.info("新增listing接口被请求,请求参数jsonParam:{}", jsonParam);//..ResultVO resultVO = iPlsAliexpressListingService.addListing(data, operator);}
可以看到代码变得简洁了很多,而且异常的格式也得到规范。
} catch (Exception e) {resultVO.setMsg(e.getMessage());resultVO.setState(ResponseCode.FAIL.getCode());LOGGER.error("新增listing接口异常", e);
}
return JSONUtils.toJSON(resultVO);
}
统一处理后```java@Overridepublic String addListing(String jsonParam) throws Exception{LOGGER.info("新增listing接口被请求,请求参数jsonParam:{}", jsonParam);//..ResultVO resultVO = iPlsAliexpressListingService.addListing(data, operator);}
可以看到代码变得简洁了很多,而且异常的格式也得到规范。