@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; }
相关推荐
在Java开发中,Spring容器(也称为ApplicationContext或BeanFactory)扮演着重要角色,它通过控制反转(Inversion of Control, IOC)和依赖注入(Dependency Injection, DI)的概念,帮助开发者构建松散耦合的系统。...
Spring框架的核心特性包括轻量级、控制反转(IoC)、面向切面编程(AOP)、容器化管理和框架集合,使其在与其他框架的整合上非常灵活。 在Spring中,bean的注入与装配是核心概念之一,有多种方式可以实现,例如XML...
1. **IoC(控制反转)**:IoC是Spring的核心特性,它将对象的创建和管理从代码中分离出来,由Spring容器负责。当使用反射时,Spring可以根据XML或Java配置文件中的定义,动态地创建和装配Bean。 2. **Bean的生命...
反射是Java中的一种强大工具,允许程序在运行时检查类、接口、字段和方法的信息,甚至可以动态创建对象和调用方法。Spring AOP则是一种设计模式,用于分离关注点,通过代理模式实现横切关注点,如日志、事务管理等。...
反射允许程序在运行时动态获取类的信息并调用其方法。例如,`java.lang.Class`类代表了Java类的信息,可以使用`Class.forName()`加载指定类,`Class.getMethod()`找到类的方法,然后通过`Method.invoke()`来执行这个...
Spring框架是Java开发中不可或缺的一部分,它通过提供两种核心特性——控制反转(IoC)和面向切面编程(AOP)来简化应用的构建。理解并掌握这两种技术对于任何Java开发者来说都至关重要。 **控制反转(IoC)**,也...
Spring框架是Java开发中最常用的轻量级开源框架之一,它以IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)为核心,极大地简化了企业级应用的开发工作。在最新版本的...
Spring框架是Java开发中最常用的轻量级开源框架之一,它以其强大的依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)能力而著名。源码分析是理解Spring工作原理的关键,能...
2. `spring-core`模块:包含了核心工具类,提供基本的反射和类型转换支持,是其他模块的基础。 3. `spring-beans`模块:定义了Bean工厂,是容器的核心,负责Bean的实例化、配置和管理。 4. `spring-aop`模块:实现了...
当我们声明一个Bean为切面并配置通知时,Spring容器会在需要的时候自动创建AOP代理。当通过代理调用目标方法时,Spring会先执行通知,然后转发到实际的目标方法。这个过程称为拦截器链,每个通知相当于一个拦截器,...
1. spring-core:核心模块,包括IoC容器的基础类、反射工具类和资源加载器等。 2. spring-beans:bean工厂,负责bean的创建、配置和管理。 3. spring-context:上下文模块,扩展了bean工厂,提供了事件发布、国际化...
在Spring中,IOC意味着应用程序不再直接创建对象,而是将对象的创建和管理交给了Spring容器。容器根据配置(如XML、Java配置类或注解)来创建和装配这些对象。注解是Spring中的一种重要配置方式,它使得代码更加简洁...
8. **spring-core.jar**:核心工具模块,包含了Spring框架的基础类和通用工具,如类型转换系统、反射和资源加载等。 9. **spring-tx.jar**:事务管理模块提供了编程和声明式事务管理的支持,适用于本地事务和分布式...
Spring 的核心特性包括控制反转(Inversion of Control, IoC)和面向切面编程(Aspect-Oriented Programming, AOP)。 【Spring 的优点】 1. **低侵入式设计**:Spring 采用接口驱动的编程方式,使得应用代码对...
Spring框架是Java开发中不可或缺的一部分,它以依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)为核心,极大地简化了企业级应用的开发。本篇文章将深入探讨Spring框架的...
Spring AOP模块是Spring实现切面编程的关键,它允许开发者定义横切关注点,如日志、事务管理等,并将这些关注点与业务逻辑分离。AOP的使用可以显著减少代码重复,提高代码的复用性。 此外,Spring框架还提供了面向...
IOC,即控制反转,它将对象的创建和管理权从代码中分离出来,交由Spring容器负责。这降低了对象间的耦合度,使得开发者可以专注于业务逻辑的编写。DI(依赖注入)是IOC的一种具体实现,通过容器在运行时动态地将依赖...
面向切面编程(AOP)允许开发者将横切关注点(例如日志和事务管理)与业务逻辑分离,通过预定义的方式来减少代码重复,并提高模块化。 二、Spring中Bean的配置和生命周期管理 Spring中的Bean是被IoC容器管理的Java...
Spring AOP支持注解和XML配置两种方式来定义切面,使得代码结构更清晰,降低了模块间的耦合。 8. **tx** 事务管理模块提供了一种声明式和编程式的事务处理方式,使得开发者可以轻松地管理事务的边界,保证数据的...
5. **排序与比较**:`org.springframework.core.order`和`org.springframework.core.type`包提供了排序算法和类型比较机制,对于Spring容器中bean的排序和类型检查起到了关键作用。 6. **事件驱动**:`org.spring...