jdk动态代理
Posted IT的鱼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk动态代理相关的知识,希望对你有一定的参考价值。
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
*/
package com.huawei.it.external.config;
import com.alibaba.fastjson.JSON;
import com.huawei.it.external.service.ITWoRemoteService;
import com.huawei.it.jalor5.core.exception.ApplicationException;
import com.huawei.it.jalor5.core.log.ILogger;
import com.huawei.it.jalor5.core.log.JalorLoggerFactory;
import com.huawei.it.jalor5.vegahsa.client.rpc.factory.RpcClientFactory;
import com.huawei.it.util.excetion.BizApplicationException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.util.StringUtils;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import javax.inject.Named;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 功能描述:封装ITWoRemoteService的代理对象,对远程调用的异常情况进行处理
* 起因:通过Jalor RPC调用,远程调用发生异常时,会将远程异常封装为非ApplicationException
* 具体封装的异常详见VegaRestTemplate.getErrorHandler().handleError()
* 而由于Jalor统一对异常进行了封装,详见WebServiceExceptionMapper,此种方式会导致
* 非ApplicationException异常,code统一为unknown,message统一为标准异常术语,最终
* 的结果是远程服务抛出的异常提示无法在客户端正常显示
* 这个类封装了什么:本类对异常各种异常进行了捕获,并对异常提示进行封装
* (1)对于4xx异常,抛出异常为”远程服务网络不通,或您无权限进行相关操作”
* (2)对于5xx异常,从code中解析异常信息
* (WO系统中直接使用throw new BizApplicationException("异常信息"),实际异常信息是封装在code中的)
* 如果异常信息不为null且不为"",则直接构建BizApplicationException抛出
* 如果异常信息为null或为"",抛出异常为“服务调用发生异常,请稍后重试”
* (3)对于其他异常,统一抛出“发生未知异常,请联系相关人员”
*
* @author YaoJiang-wx1047757
* @since 2021-05-08
*/
@Named("tWoRemoteService")
public class ITWoRemoteServiceFactoryBean implements FactoryBean<ITWoRemoteService> {
private static final ILogger LOGGER = JalorLoggerFactory.getLogger(ITWoRemoteService.class);
// unknown异常及正常5xx在返回体中的特征值
private static final String UNKNOWN = "code=unknown";
private static final String ERRCODE_PREFIX = "code=JALOR_EX$";
private static final Integer PREFIX_LENGTH = 14;
// 实际用于执行远程调用的类,是ITWoRemoteService的一个代理类
private static final ITWoRemoteService REMOTE_TARGET = RpcClientFactory.getSubAppRpcClinet(ITWoRemoteService.class);
/**
* 功能描述:重写FactoryBean的getObject()方法
* 内部对ITWoRemoteService接口创建了代理,代理内部实际上是使用Jalor生成的远程调用代理
* 执行远程调用,对调用过程中产生的异常进行捕获,将异常拆分为5xx/4xx/其他异常等三种类型
*
* @author YaoJiang-wx1047757
* @since 2021-05-08
* @return com.huawei.it.external.service.ITWoRemoteService ITWoRemoteService代理对象
* @throws ApplicationException 创建代理后,类型转换异常时抛出异常
*/
@Override
public ITWoRemoteService getObject() throws ApplicationException {
Object proxy = Proxy.newProxyInstance(ITWoRemoteService.class.getClassLoader(),
new Class[] {ITWoRemoteService.class}, new RemoteRequestInvocationHandler());
if (proxy instanceof ITWoRemoteService) {
return (ITWoRemoteService) proxy;
}
throw new BizApplicationException("======>>> ITWoRemoteServiceFactoryBean创建代理失败");
}
/**
* 功能描述:获取当前Bean的类型,当前Bean的类型为ITwoRemoteService.class
*
* @author YaoJiang-wx1047757
* @since 2021-05-08
* @return java.lang.Class Bean的类型
*/
@Override
public Class<?> getObjectType() {
return ITWoRemoteService.class;
}
/**
* 功能描述:具体代理执行类,包含了对异常捕捉的动作
*
* @author YaoJiang-wx1047757
* @since 2021-05-08
*/
static class RemoteRequestInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
LOGGER.info2("======>>> ITWoRemoteService准备发起远程调用,method:{},参数:{}",
method.getName(), JSON.toJSONString(args));
return method.invoke(REMOTE_TARGET, args);
} catch (InvocationTargetException e) {
LOGGER.error2("======>>> ITWoRemoteService调用发生异常,实际异常类型:{},异常堆栈信息:",
e.getTargetException().getClass().getName(), e.getTargetException());
// 获取具体异常信息
Throwable te = e.getTargetException();
// 5xx异常处理
if (te instanceof HttpServerErrorException) {
HttpServerErrorException he = (HttpServerErrorException) te;
String statusText = he.getStatusText();
// 异常信息截取 WO系统中直接使用throw new BizApplicationException("异常信息"),实际异常信息是封装在code中
// 异常信息格式为:{code=JALOR_EX$异常信息$(unknown), message=标准异常术语}
String errorMsg = null;
if (!StringUtils.isEmpty(statusText)) {
if (!statusText.contains(UNKNOWN) && statusText.contains(ERRCODE_PREFIX)) {
int errorCodeStart = statusText.indexOf(ERRCODE_PREFIX) + PREFIX_LENGTH;
int errorCodeEnd = statusText.indexOf("$", errorCodeStart);
errorMsg = statusText.substring(errorCodeStart, errorCodeEnd);
}
}
if (StringUtils.isEmpty(errorMsg)) {
errorMsg = "服务调用发生异常,请稍后重试";
}
throw new BizApplicationException(errorMsg);
}
// 4xx异常处理
if (te instanceof HttpClientErrorException) {
throw new BizApplicationException("远程服务网络不通,或您无权限进行相关操作");
}
// 其他异常处理
throw new BizApplicationException("发生未知异常,请联系相关人员");
}
}
}
}
以上是关于jdk动态代理的主要内容,如果未能解决你的问题,请参考以下文章