@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; }
相关推荐
4.11.2 使用基于Java类的配置信息启动Spring容器 4.12 不同配置方式比较 4.13 小结 第5章 Spring容器高级主题 5.1 Spring容器技术内幕 5.1.1 内部工作机制 5.1.2 BeanDefinition 5.1.3 InstantiationStrategy 5.1.4 ...
4.11.2 使用基于Java类的配置信息启动Spring容器 4.12 不同配置方式比较 4.13 小结 第5章 Spring容器高级主题 5.1 Spring容器技术内幕 5.1.1 内部工作机制 5.1.2 BeanDefinition 5.1.3 InstantiationStrategy 5.1.4 ...
面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面 1.面向切面编程提供声明式事务管理 2.spring支持用户自定义的切面 面向切面编程(aop)是对面向对象编程(oop)的...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...
Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上...