@Service
public class SpringContextHolder implements ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
private static ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.ctx = applicationContext;
ctx.publishEvent(new BeanLoadedEvent(loadAllBeanClassInfo()));
}
private Class[] baseClassArr = new Class[]{
Date.class, String.class, Integer.class, int.class, Long.class, long.class,
Double.class, double.class, Float.class, float.class, Enum.class,
Boolean.class, boolean.class, Character.class, char.class, Object.class, Byte.class, byte.class
};
private List<Class> baseClsList = Arrays.asList(baseClassArr);
public static ApplicationContext getCtx(){
return SpringContextHolder.ctx;
}
public static Object getBean(String beanName) {
return ctx.getBean(beanName);
}
public static <T> T getBean(String beanName , Class<T>clazz) {
return ctx.getBean(beanName , clazz);
}
private Map<String, List<MeapClassInfo>> loadAllBeanClassInfo(){
Map<String, List<MeapClassInfo>> mapClassInfo = new HashMap<>();
try {
Field f = ClassLoader.class.getDeclaredField("classes");
f.setAccessible(true);
Vector classVector = (Vector) f.get(ClassLoader.getSystemClassLoader());
Vector vector = (Vector) classVector.clone();
logger.info("class num: {}", vector.size());
for (Object cv : vector) {
String classInfo = cv.toString();
if (classInfo.startsWith("class com.xxx.xxx") &&
!classInfo.contains("domain") && !classInfo.contains("model") &&
!classInfo.contains("domain") && !classInfo.contains("SpringContextHolder")) {
String className = classInfo.substring(classInfo.indexOf("com"));
logger.info("******load class name: " + className);
Class cls = Class.forName(className);
Method[] methods = cls.getDeclaredMethods();
List<MeapClassInfo> mList = new ArrayList<>();
for (Method m : methods) {
logger.info("\t******load method name: " + m.getName());
MeapClassInfo mInfo = new MeapClassInfo();
try {
// 获取入参
Parameter[] params = m.getParameters();
Map<String, Object> mapParams = new HashMap<>();
for (Parameter p : params) {
mapParams.putAll(getObjectFieldInfoMap(p.getName(), p.getType()));
}
// 获取返回内容
Map<String, Object> mapReturns = new HashMap<>();
Class retType = m.getReturnType();
Type retGerericType = m.getGenericReturnType();
mapReturns.putAll(getObjectFieldInfoMap("ret",
retGerericType.getClass() == ParameterizedTypeImpl.class ? retGerericType : retType));
// 构造切面对象
mInfo.setCls(className);
mInfo.setMethod(m.getName());
mInfo.setParams(mapParams);
mInfo.setReturns(mapReturns);
mList.add(mInfo);
} catch (Exception ex) {
logger.error("类【{}】的方法【{}】解析出现异常:{}", className, m.getName(), ex);
}
}
mapClassInfo.put(className, mList);
}
}
}catch (Throwable ex){
logger.error("反射获取类和方法信息时出现异常:{}", ex);
}
return mapClassInfo;
}
private Map<String, Object> getObjectFieldInfoMap(String fieldName, Type type) throws ClassNotFoundException {
Map<String, Object> retMap = new HashMap<>();
// 一些特殊的类型不做处理
if(!checkCanReflect(type)){
return retMap;
}
// 基础类型直接返回type即可
if(baseClsList.contains(type)) {
Map<String, Object> map = new HashMap<>();
map.put("tp", ((Class)type).getSimpleName());
retMap.put(fieldName, map);
}else if(type instanceof ParameterizedTypeImpl){
Map<String, Object> map = new HashMap<>();
// 我们自定义的泛型(如:Response)在服务返回给客户端时,是Response的Map结构
// 需要特殊处理:先获取Response的结构,在将参数结构塞到Response的result属性中去
Type rawType = ((ParameterizedTypeImpl)type).getRawType();
if(rawType.getTypeName().equals(Response.class.getTypeName())){
map = getObjectFieldInfoMap("", rawType);
((Map<String, Object>)map.get("fd")).put("result",
getObjectFieldInfoMap("", ((ParameterizedType) type).getActualTypeArguments()[0]));
} else {
// 如果是普通的list、map等参数化结构,直接获取类型表达式
// map.put("tp", type.getTypeName());
map.put("fd", buildParameterizedTypeImpleMap(type));
map.put("tp", ParameterizedTypeImpl.class.getSimpleName());
}
//参数化属性在循环递归处理时都属于fieldName的子内容
//所以当fieldName为空时,表示不需要再分层次了,直接putAll
if(StringUtils.isBlank(fieldName)){
retMap.putAll(map);
}else {
retMap.put(fieldName, map);
}
}else if(type.getClass() == Class.class){
// Field[] fields = ((Class)type).getDeclaredFields();
Field[] fields = getObjFields((Class)type).toArray(new Field[]{});
if(fields != null && fields.length > 0) {
Map<String, Object> map = new HashMap<>();
for (Field f : fields) {
try {
Type tf = f.getGenericType();
if(checkCanReflect(tf)) {
if (tf instanceof ParameterizedTypeImpl) {
Map<String, Object> m = new HashMap<>();
// m.put("tp", tf.getTypeName()); // 屏蔽的原因是:在解析时无需关注具体是什么参数化的类型
m.put("tp", ParameterizedTypeImpl.class.getSimpleName());
m.put("fd", buildParameterizedTypeImpleMap(tf));
map.put(f.getName(), m);
} else if (baseClsList.contains(f.getType())) {
Map<String, Object> m = new HashMap<>();
m.put("tp", ((Class) tf).getSimpleName());
map.put(f.getName(), m);
} else if (tf.getTypeName().startsWith("com.xxx.xxx")) {
Map<String, Object> m = new HashMap<>();
m.put("tp", tf.getTypeName());
m.put("fd", getObjectFieldInfoMap(f.getName(), tf));
map.put(f.getName(), m);
}else{
logger.info("暂不处理的类型: {}", tf.getTypeName());
}
}else {
logger.info("无法获取属性信息: {}", tf.getTypeName());
}
}catch (Exception ex){
logger.info("获取GenericType失败:{}", ex);
}
}
Map<String, Object> mAll = new HashMap<>();
mAll.put("tp", type.getTypeName());
mAll.put("fd", map);
if(StringUtils.isBlank(fieldName)){
retMap.putAll(mAll);
}else {
retMap.put(fieldName, mAll);
}
}else{
Map<String, Object> m = new HashMap<>();
m.put("tp", type.getTypeName());
m.put("fd", new HashMap<>());
retMap.put(fieldName, m);
}
}
return retMap;
}
private List<Map<String, Object>> buildParameterizedTypeImpleMap(Type type) throws ClassNotFoundException {
Type[] typeArr = ((ParameterizedType)type).getActualTypeArguments();
List<Map<String, Object>> mList = new ArrayList<>();
for(Type t : typeArr) {
mList.add(getObjectFieldInfoMap("", t));
}
return mList;
}
/**
* 获取一个对象类型的所有属性
* @param cls
* @return
*/
private List<Field> getObjFields(Class cls){
List<Field> list = new ArrayList<>();
if(cls != Object.class) {
Field[] fields = cls.getDeclaredFields();
for(Field f : fields){
list.add(f);
}
if (cls.getSuperclass() != null && cls.getSuperclass() != Object.class){
list.addAll(getObjFields(cls.getSuperclass()));
}
}
return list;
}
private boolean checkCanReflect(Type type) {
if (type instanceof WildcardTypeImpl) {
return false;
} else if (type instanceof TypeVariableImpl) {
return false;
} else if (type.getClass() == Class.class) {
Class cls = (Class) type;
if (Throwable.class.isAssignableFrom(cls)) {
return false;
}
}
return true;
}
}
类信息: 类名(含包名)
方法信息:
1)方法名
2)入参信息(基本类型参数、参数化参数、普通对象参数(含基类),以及类型的嵌套)
3)返回对象信息(结构同入参信息)
4)一般泛型的原型(rawType)是我们不太关注的,但是我们自定义的一些泛型类(如:Response类),原型属性也是需要的,针对这种情况,需要把 泛型类作为一个属性塞到原型类的某个属性中(Response中,是将泛型塞到 result字段中去的)
5)类型嵌套需要递归处理
方法参数和返回信息的构造规则:
1)采用 json,结构大致为: {"arg0": {"tp": "", "fd": {}}}
如果是基本格式,那么解析为: {"arg0": {"tp": "Long"}}
如果是普通对象,那么解析为: {"arg0": {"tp": "", "fd": {“xxx": {"tp": "Long"}}}},无限嵌套
如果是参数化结构,那么解析为:
{"arg0": {"tp": "", "fd": [{"tp": "Long"}, {"tp": "String"}]}}
{"arg0": {"tp": "", "fd": [{"tp": "com.xxx.xxx.....", "fd": {"xxx": {}, "xxx": {}}}]}}
2)反射获取方法的几个参数时,无法得到参数名,只有 arg0 arg1 这样的
3)反射获取方法的返回时,没有变量名,手动赋值:ret
4)方法入参示例:
{
"arg0": {
"tp": "xxx.proxy.service.entity.req.TemplateDeletingReq",
"fd": {
"channelNo": {
"tp": "String"
},
"templateId": {
"tp": "String"
},
"productNo": {
"tp": "String"
}
}
}
}
5)方法返回示例:
{
"ret": {
"tp": "xxx.proxy.service.entity.resp.BaseResp",
"fd": {
"retCode": {
"tp": "String"
},
"retMsg": {
"tp": "String"
}
}
}
}
6)一个比较复杂的示例:
{
"ret": {
"tp": "xxx.service.domain.resp.Response",
"fd": {
"retDesc": {
"tp": "String"
},
"result": {
"tp": "xxx.service.domain.model.mesp.EmployeeBusiness",
"fd": {
"groupBusinessId": {
"tp": "Long"
},
"groupId": {
"tp": "Long"
},
"orderList": {
"tp": "ParameterizedTypeImpl",
"fd": [
{
"tp": "xxx.service.domain.model.mesp.EmployeeBusinessOrder",
"fd": {
"businessRetDesc": {
"tp": "String"
},
"businessContentType": {
"tp": "Long"
},
"phoneNo": {
"tp": "String"
},
"setStatus": {
"tp": "Long"
},
"setContentId": {
"tp": "Long"
},
"operatorUserId": {
"tp": "Long"
}
}
}
]
},
"confirmTime": {
"tp": "Date"
}
}
},
"retCode": {
"tp": "String"
}
}
}
}
前面说过方法的入参和出参的结构都是以层次化的json数据进行描述的,
为了方便的获取需要友好展示的数据,那么语法糖中也是层次化的,如下所示:
{
"arg0": {
"tp": "xxx.proxy.service.entity.req.TemplateDeletingReq",
"fd": {
"channelNo": {
"tp": "String"
},
"templateId": {
"tp": "String"
},
"productNo": {
"tp": "String"
}
}
}
}
我要记录channelNo的话,那么语法糖中的属性名格式为: arg0.chennelNo
而且不考虑channelNo是在arg0的普通字段里面,还是在参数化的字段里面
转换规则为 {"ka": "渠道编号", "va": ""}
完整的配置为: {"arg0.channleNo": {"ka": "渠道编号", "va": ""}}
其中:
ka 是 keyAlias
va 是 valueAlias
根据 方法的请求内容和入参格式化信息,以及需要友好展示的属性,按照下面的逻辑完成数据定位和值的转换:
如下是解析的代码:
/**
* 根据数据格式描述符等获取友好展示的信息
* @param mapDataInfo 原始数据
* @param descInfo 数据的格式描述信息
* @param sugarInfo 需要友好展示的属性格式信息
* @param keyName 关键字名称(用于快速查询)
* @param sb 友好展示的信息
* @param sb_key 关键字结果
*/
private void getMethodLogSugarInfo(Map<String, Object> mapDataInfo, String descInfo, String sugarInfo, String keyName,
StringBuilder sb, StringBuilder sb_key){
Map<String, Object> mapDescInfo = new HashMap<>(); //数据格式
if(StringUtils.isNotBlank(descInfo)){
mapDescInfo = JsonUtil.decode2MapObject(descInfo);
}
Map<String, Map<String, String>> mapSugarInfo = new HashMap<>(); //需要友好展示的数据格式
if(StringUtils.isNotBlank(sugarInfo)){
mapSugarInfo = JsonUtil.decode(sugarInfo.getBytes(),
new TypeReference<Map<String, Map<String, String>>>(){}, "utf-8");
}
// 开始获取友好的展示信息
if(mapSugarInfo.size() > 0) {
sb.append("关键信息如下:\n");
}
for(String field : mapSugarInfo.keySet()) {
Map<String, Object> tmpDescInfo = new HashMap<>();
Map<String, Object> tmpDataInfo = new HashMap<>();
tmpDescInfo.putAll(mapDescInfo);
tmpDataInfo.putAll(mapDataInfo);
getObjectSugarInfo(tmpDescInfo, tmpDataInfo, field, mapSugarInfo.get(field),
sb, sb_key, field.equals(keyName), "");
}
}
/**
* 根据字段sugarField的命名规则从数据副本中获取字段值并进行转义
* @param objDesc 对象格式描述副本
* @param objData 数据对象副本
* @param sugarField 需要转义后展示在界面的字段
* @param alias 转义规则
* @param segment 如果该字段不为空,说明是参数化解析的递归
* @return
*/
private void getObjectSugarInfo(Map<String, Object> objDesc, Map<String, Object> objData,
String sugarField, Map<String, String> alias,
StringBuilder sb, StringBuilder sb_key, boolean isKeyField, String segment){
try {
String seg0;
if(StringUtils.isBlank(segment)) {
String[] segments = sugarField.split("\\.");
seg0 = segments[0];
objDesc = (Map<String, Object>) objDesc.get(seg0);
}else{
seg0 = segment;
}
String tp = objDesc.get("tp").toString();
if (baseClsList.contains(tp)) {
sb.append(String.format("[%s]- [%s]\n", alias.get("ka"), objData.get(seg0)));
if(isKeyField){
sb_key.append(String.format("%s,", objData.get(seg0)));
}
} else {
if(tp.equals(ParameterizedTypeStr)){ //参数化
String first = objData.get(seg0).toString().substring(0, 1);
if(first.equals("{")){
//如果是map,直接写进结果中
String v = JsonUtil.encodeString(objData.get(seg0));
sb.append(String.format("[%s]- [%s]\n", alias.get("ka"), v));
if(isKeyField){
sb_key.append(String.format("%s,", v));
}
}else if(first.equals("[")){
//如果是列表,则循环获取
List<Map<String, Object>> objDataList = (List<Map<String, Object>>)objData.get(seg0);
List<Map<String, Object>> objDescList = (List<Map<String, Object>>)objDesc.get("fd");
for(Map<String, Object> m : objDataList){
getObjectSugarInfo(objDescList.get(0), m, sugarField, alias, sb, sb_key, isKeyField, seg0);
}
}else{
logger.info("不支持的解析类型,直接拼接字段值。");
String v = JsonUtil.encodeString(objData.get(seg0));
sb.append(String.format("[%s]- [%s]\n", v));
if(isKeyField){
sb_key.append(String.format("%s,", v));
}
}
} else { //非参数化
objDesc = (Map<String, Object>) objDesc.get("fd");
// segment不为空的时候,是参数化属性递归获取下一层的内容,但是objData无需进行层次深入
if(StringUtils.isBlank(segment)){
objData = (Map<String, Object>) objData.get(seg0);
}
getObjectSugarInfo(objDesc, objData, sugarField.substring(seg0.length() + 1), alias, sb, sb_key, isKeyField, "");
}
}
}catch (Exception ex){
logger.error("获取友好转义的信息出现异常:", ex);
}
}
/**
* 根据规则转换属性值
* @param value 要进行转换的属性值
* @param regex 转换规则
* @return
*/
private String transferValue(String value, String regex){
return value;
}