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 {
@Override
public 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;
}
@Override
public String getCode() {
return code;
}
@Override
public String getName() {
return name;
}
@Override
public 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);
@Override
public 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);
}
统一处理后
@Override
public 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
@Override
public String addListing(String jsonParam) throws Exception{
LOGGER.info("新增listing接口被请求,请求参数jsonParam:{}", jsonParam);
//..
ResultVO resultVO = iPlsAliexpressListingService.addListing(data, operator);
}
可以看到代码变得简洁了很多,而且异常的格式也得到规范。