Remote-talk calling code package

Online a week treatment problem, after investigation found RPC call to the distal end of the timeout, frame timeout exception is not thrown captured, resulting in data into the intermediate state, the subsequent processing can not be advanced. Fortunately little effect, promptly repair out.
About this part of the code specifications, before also been thinking, just to have this opportunity to do some finishing.

Discussion of the background and scope

When do apply a layered architecture, there is a practical way to class on behalf of external services such as UserService, packed into a UserServiceClient class, upper-layer service call unified use UserServiceClient, it is a simple proxy mode.
Examples of the discussion herein, i.e. UserService, UserServiceClient and its implementation UserServiceClientImpl, formally defined as follows:

// 远程RPC接口
public interface UserService {
    /**
     * 用户查询
     */
    ResultDTO<UserInfo> query(QueryReequest param);
    
    /**
     * 用户创建
     */
    ResultDTO<String> create(CreateRequest param);
}
// 本地接口
public interface UserServiceClient {
    /**
     * 用户查询
     */
    Result<UserInfo> query(QueryReequest param);
    
    /**
     * 用户创建
     */
    Result<String> create(CreateRequest param);
}
// 本地接口实现
public classe UserServiceClientImpl implement  UserServiceClient {

    @Autorwire
    private UserService userSerivce;
    /**
     * 用户查询
     */
    @override
    Result<UserInfo> query(QueryReequest param) {
        // 包装调用代码片段
    }

    /**
     * 用户创建
     */
    @override
    Result<String> create(CreateRequest param) {
        // 包装调用代码片段
    }
}

First, no treatment / no encapsulation

Client class without any treatment, just kind of call is Servie and as they return.

// 本地接口实现
public classe UserServiceClientImpl implement  UserServiceClient {

    @Autorwire
    private UserService userSerivce;
    /**
     * 用户查询
     */
    @override
    Result<UserInfo> query(QueryReequest param) {
        return userSerivce.query(param);
    }

    /**
     * 用户创建
     */
    @override
    Result<String> create(CreateRequest request) {
        return userSerivce.create(param);
    }
}

Very not recommended, because you can look at and subsequent comparison of several forms.

The wording in fact @Delegate notes with lombok offer is the same, this is not recommended as annotations.

@Component
public class UserServiceClient {
    @Autowired
    @Delegate
    private UserService userService;
}

Second, the results unified repackaging

RPC calls may target different systems, packaging result of the call is also different. To facilitate handling the upper layer service, reducing the perception of external, you can define a generic class Result packaging.

// 本地接口实现
public classe UserServiceClientImpl implement  UserServiceClient {

    @Autorwire
    private UserService userSerivce;
    /**
     * 用户查询
     */
    @override
    Result<UserInfo> query(QueryReequest param) {
        ResultDTO<UserInfo> rpcResult = userSerivce.query(param);
        Result<UserInfo> result = new Result<>(); 
        // 封装调用结果
        result.setSuccess(result.isSuccess());
        result.setData(result.getData());
        // 错误码、错误堆栈等填充,略
        return result;
    }

    /**
     * 用户创建
     */
    @override
    Result<String> create(CreateRequest request) {
        // 略
    }
}

Third, the result is not only take the package

When the upper layer processor, the results of determination of the package would be more redundancy. If the Client can distinguish the intended use, unintended results may be encapsulated into business exception, the expected results returned directly.
Particular scene can return results abnormal distinguished by different services.

// 本地接口实现
public classe UserServiceClientImpl implement  UserServiceClient {

    @Autorwire
    private UserService userSerivce;
    /**
     * 用户查询
     */
    @override
    UserInfo query(QueryReequest param) {
        ResultDTO<UserInfo> rpcResult = userSerivce.query(param);
        if(rpcResult == null) {
            throw new BizException("调用结果为空!");
        }
        if(rpcResult != null && rpcResult.isSuccess()) {
            return rpcResult.getData();
        }
        if("XXX".equals(rpcResult.getErrorCode())) {
            throw new XXXBizException("调用结果失败,异常码XXX");
        } else {
            throw new BizException("调用结果失败");
        }
    }

    /**
     * 用户创建
     */
    @override
    String create(CreateRequest request) {
        // 略
    }
}

Fourth, increased exception handling calls at

RPC call to inter-system interaction takes place, there will inevitably be times out, a lot of the framework of direct throw timeout exception. In addition, the business system call interfaces may be due to historical reasons or coding problems that may directly own exception thrown to the caller. In order to ensure the stability of their own system, the need for an exception to capture.
How to catch exceptions? Not simply catch(Exception e)be able to get. In Ali Baba produced "Java Development Manual" mentioned, the use Throwable to capture because:

[Force] When the RPC call, two square package, related methods or dynamically generated class Throwable must catch an exception
class to intercept.
Description: to call the method through reflection, if you can not find the method, throws NoSuchMethodException. What would be thrown
NoSuchMethodError it? When the second party package type of conflict, the arbitration mechanism may result in the introduction of unintended class version of a method signature does not match
with, or bytecode modification framework: dynamically create or modify classes (such as the ASM), a corresponding method is modified signature. These cases, which
make the code compile time is right, but when code is run, throws NoSuchMethodError.

In this way, a perfect Client is complete:

// 本地接口实现
public classe UserServiceClientImpl implement  UserServiceClient {

    @Autorwire
    private UserService userSerivce;
    /**
     * 用户查询
     */
    @override
    UserInfo query(QueryReequest param) {
        try {
            ResultDTO<UserInfo> rpcResult = userSerivce.query(param);
        } catch (Throwable t) {
            if(t instanceof XXXTimeoutException) {
                // 已知的特殊调用异常处理,如超时异常需要做自动重试,特殊处理
                throw new BizException("超时异常")
            }
            throw new BizException("调用异常", t)
        }
        if(rpcResult == null) {
            throw new BizException("调用结果为空!");
        }
        if(rpcResult != null && rpcResult.isSuccess()) {
            return rpcResult.getData();
        }
        if("XXX".equals(rpcResult.getErrorCode())) {
            throw new XXXBizException("调用结果失败,异常码XXX");
        } else {
            throw new BizException("调用结果失败");
        }
    }

    /**
     * 用户创建
     */
    @override
    String create(CreateRequest request) {
        // 略
    }
}

Packaging abnormality interceptors

For external calls, and internal calls can be made uniform treatment with interceptor. For exception handling and print logs captured in the interceptor to do, make coding more concise.
Examples are as follows:

import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class RpcInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        String invocationSignature = method.getDeclaringClass().getSimpleName() + "." + method.getName();

        // 排除掉java原生方法
        for(Method m : methods) {
            if(invocation.getMethod().equals(m)) {
                return invocation.proceed();
            }
        }

        Object result = null;
        Objectp[] params = invocation.getArguments();

        try {

            result = invocation.proceed();
        } catch( Throwable e) {
            // 接各种异常,区分异常类型

            // 处理异常、打印日志

        } finally {
            // 打印结果日志, 打印时也要处理异常
        }
        return result;
}

Proxy settings

import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConitionalOnBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.Bean;
import org.springframework.context.ComponentScan;
import org.springframework.context.Configuration;



@Configuration
public class Interceptor {
    
    @Bean
    public RpcInterceptor rpcSerivceInterceptor() {
        RpcInterceptor rpcSerivceInterceptor = new RpcInterceptor();
        // 可以注入一些logger什么的
        return rpcSerivceInterceptor;
    }

    @Bean
    public BeanNameAutoProxyCreator rpcServiceBeanAutoProxyCreator() {
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        // 设置代理类的名称
        beanNameAutoProxyCreator.setBeanNames("*RpcServiceImpl");

        // 设置拦截链名字
        beanNameAutoProxyCreator.setInterceptorName("rpcSerivceInterceptor");
        return beanNameAutoProxyCreator;
    }


}

If you need to return the results to the upper unified package, you can do inside the interceptor.

Guess you like

Origin www.cnblogs.com/wuyuegb2312/p/11263014.html