Selaa lähdekoodia

新增Bean依赖分析

liukx 3 vuotta sitten
vanhempi
commit
c5ce44ee52

+ 237 - 0
elab-spring/src/main/java/com/elab/spring/componts/BeanAnalyse.java

@@ -0,0 +1,237 @@
+package com.elab.spring.componts;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.aop.support.AopUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.InjectionMetadata;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.core.annotation.AnnotationAttributes;
+import org.springframework.util.ReflectionUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.*;
+
+/**
+ * bean的依赖分析
+ *
+ * @author : liukx
+ * @time : 2020/9/18 - 11:38
+ */
+public class BeanAnalyse implements ApplicationContextAware {
+
+    private static Logger logger = LoggerFactory.getLogger(BeanAnalyse.class);
+    private ApplicationContext applicationContext;
+
+    private List<Class<? extends Annotation>> annoList;
+
+    private Map<Class, Class> classConvertMap = new HashMap<>();
+
+    private String[] excludePackages;
+
+    private Set<Class> clazzFieldList = new HashSet<>();
+
+    private Set<Class> basicClazzList = new HashSet<>();
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        this.applicationContext = applicationContext;
+    }
+
+    public BeanAnalyse(List<Class<? extends Annotation>> annotationList) {
+        this.annoList = annotationList;
+        basicClazzList.add(String.class);
+        basicClazzList.add(Integer.class);
+        basicClazzList.add(Long.class);
+        basicClazzList.add(Double.class);
+        basicClazzList.add(Boolean.class);
+    }
+
+    public void setExcludePackages(String[] excludePackages) {
+        this.excludePackages = excludePackages;
+    }
+
+    private void addData(Map<Class, Map<Class, Class>> classMap, Class classStr, Class fieldClass,
+        Class fieldClassImpl) {
+
+        Class convertClass = getClassConvertMap().get(fieldClassImpl);
+
+        if (convertClass != null) {
+            fieldClassImpl = convertClass;
+        }
+
+        Map<Class, Class> classClassMap = classMap.get(classStr);
+        if (classClassMap == null) {
+            classClassMap = new LinkedHashMap<>();
+            classMap.put(classStr, classClassMap);
+        }
+        classClassMap.put(fieldClass, fieldClassImpl);
+    }
+
+    private boolean isBasicType(Class clazz) {
+        return String.class.equals(clazz);
+    }
+
+    /**
+     * 是否排除
+     *
+     * @param clazz
+     * @param dependOnModel
+     * @return
+     */
+    private boolean isExclude(Class<?> clazz, BeanDependOnModel dependOnModel) {
+        Map<String, Set<Class>> excludeClassMap = dependOnModel.getExcludeClassMap();
+        if (this.excludePackages != null) {
+            for (int i = 0; i < this.excludePackages.length; i++) {
+                String name = clazz.getName();
+                String excludePackage = this.excludePackages[i];
+                if (name.startsWith(excludePackage)) {
+                    Set<Class> clazzList = excludeClassMap.get(excludePackage);
+                    if (clazzList == null) {
+                        clazzList = new HashSet<>();
+                        excludeClassMap.put(excludePackage, clazzList);
+                    }
+                    clazzList.add(clazz);
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * 获取bean的依赖
+     *
+     * @param clazz 类名
+     * @return
+     */
+    public BeanDependOnModel getBeanDependOn(Class clazz) {
+        BeanDependOnModel dependOnModel = new BeanDependOnModel();
+        dependOnModel.setClazz(clazz);
+        buildAutowiringMetadata(clazz, dependOnModel);
+        return dependOnModel;
+    }
+
+    private void buildAutowiringMetadata(Class clazz, BeanDependOnModel dependOnModel) {
+        Class<?> targetClass = clazz;
+
+        final LinkedList<InjectionMetadata.InjectedElement> currElements =
+            new LinkedList<InjectionMetadata.InjectedElement>();
+
+        ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
+            @Override
+            public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
+                AnnotationAttributes ann = findAutowiredAnnotation(field, annoList);
+                if (ann != null) {
+                    // 如果是静态方法
+                    if (Modifier.isStatic(field.getModifiers())) {
+                        if (logger.isWarnEnabled()) {
+                            logger.warn("Autowired annotation is not supported on static fields: " + field);
+                        }
+                        return;
+                    }
+
+                    Map<Class, Map<Class, Class>> fieldMapList = dependOnModel.getFieldMapList();
+                    // 类的名称
+                    Class<?> clazzName = field.getDeclaringClass();
+                    // 类的字段类型
+                    Class<?> fieldClazz = field.getType();
+                    if (fieldMapList.get(clazzName) == null || !clazzFieldList.contains(fieldClazz)) {
+                        // 是否属于需要排除的类
+                        if (!isExclude(fieldClazz, dependOnModel)) {
+                            // 判断是否是Value,Qualifier
+                            if (isBasicType(fieldClazz)) {
+                                Map<Class, Set<String>> annotationValueList = dependOnModel.getAnnotationValueList();
+                                if (field.getAnnotation(Qualifier.class) != null) {
+                                    addAnnoList(annotationValueList, Qualifier.class,
+                                        field.getAnnotation(Qualifier.class).value());
+                                } else if (field.getAnnotation(Value.class) != null) {
+                                    addAnnoList(annotationValueList, Value.class,
+                                        field.getAnnotation(Value.class).value());
+                                }
+                            } else {
+                                clazzFieldList.add(fieldClazz);
+                                try {
+                                    Class<?> aopClazz = getBeanClass(fieldClazz);
+                                    if (aopClazz != null) {
+                                        if (!isExclude(aopClazz, dependOnModel)) {
+                                            System.out.println(clazzName + "\t" + fieldClazz + "\t" + aopClazz);
+                                            clazzFieldList.add(aopClazz);
+                                            buildAutowiringMetadata(aopClazz, dependOnModel);
+                                        }
+                                        addData(fieldMapList, clazzName, fieldClazz, aopClazz);
+                                    }
+                                } catch (Exception e) {
+                                    System.out
+                                        .println("原因: " + e.getMessage() + "\t" + clazzName + " -> " + fieldClazz);
+                                }
+                            }
+                        } else {
+                            addData(fieldMapList, clazzName, fieldClazz, fieldClazz);
+                        }
+                    }
+                }
+            }
+
+            private void addAnnoList(Map<Class, Set<String>> annotationValueList, Class anno, String value) {
+                Set<String> annoList = annotationValueList.get(anno);
+                if (annoList == null) {
+                    annoList = new HashSet<>();
+                    annotationValueList.put(anno, annoList);
+                }
+                annoList.add(value);
+            }
+        });
+    }
+
+    private Class<?> getBeanClass(Class<?> fieldClazz) {
+        Object bean = applicationContext.getBean(fieldClazz);
+
+        Class<?> aopClazz = null;
+        if (AopUtils.isAopProxy(bean)) {
+            aopClazz = AopUtils.getTargetClass(bean);
+        } else {
+            aopClazz = bean.getClass();
+        }
+        return aopClazz;
+    }
+
+    public void setClassConvertMap(Map<Class, Class> classConvertMap) {
+        this.classConvertMap = classConvertMap;
+    }
+
+    public Map<Class, Class> getClassConvertMap() {
+        return classConvertMap;
+    }
+
+    private static AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao,
+        List<Class<? extends Annotation>> autowiredAnnotationTypes) {
+        if (ao.getAnnotations().length > 0) {
+            for (Class<? extends Annotation> type : autowiredAnnotationTypes) {
+                AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
+                if (attributes != null) {
+                    return attributes;
+                }
+            }
+        }
+        return null;
+    }
+
+    public void printClassLog(Class clazz){
+        BeanDependOnModel beanDependOn = this.getBeanDependOn(clazz);
+        Set<Class> dependOnClassList = beanDependOn.getDependOnClassList(excludePackages);
+        System.out.println("===================================");
+        System.out.println(clazz.getSimpleName() + ".class");
+        for (Class aClass : dependOnClassList) {
+            System.out.println(", " + aClass.getSimpleName() + ".class ");
+        }
+    }
+}

+ 99 - 0
elab-spring/src/main/java/com/elab/spring/componts/BeanDependOnModel.java

@@ -0,0 +1,99 @@
+package com.elab.spring.componts;
+
+import java.util.*;
+
+/**
+ * bean的依赖结构图
+ *
+ * @author : liukx
+ * @time : 2020/9/21 - 11:18
+ */
+public class BeanDependOnModel {
+
+    /**
+     * 类的名称
+     */
+    private Class clazz;
+
+    /**
+     * 字段对应的名称
+     * K -> 接口
+     * V -> 具体实现
+     */
+    private Map<Class, Map<Class, Class>> fieldMapList = new LinkedHashMap<>();
+
+    /**
+     * 注解对应的名称
+     */
+    private Map<Class, Set<String>> annotationValueList = new HashMap<>();
+
+    /**
+     * 被排除的包名对应的类名
+     */
+    private Map<String, Set<Class>> excludeClassMap = new LinkedHashMap<>();
+
+    public Map<String, Set<Class>> getExcludeClassMap() {
+        return excludeClassMap;
+    }
+
+    public void setExcludeClassMap(Map<String, Set<Class>> excludeClassMap) {
+        this.excludeClassMap = excludeClassMap;
+    }
+
+    public Class getClazz() {
+        return clazz;
+    }
+
+    public void setClazz(Class clazz) {
+        this.clazz = clazz;
+    }
+
+    public Map<Class, Map<Class, Class>> getFieldMapList() {
+        return fieldMapList;
+    }
+
+    public void setFieldMapList(Map<Class, Map<Class, Class>> fieldMapList) {
+        this.fieldMapList = fieldMapList;
+    }
+
+    public Map<Class, Set<String>> getAnnotationValueList() {
+        return annotationValueList;
+    }
+
+    public void setAnnotationValueList(Map<Class, Set<String>> annotationValueList) {
+        this.annotationValueList = annotationValueList;
+    }
+
+    public Set<Class> getDependOnClassList() {
+        return getDependOnClassList(null);
+    }
+
+    private boolean isExcludePackages(String[] excludePackages, Class clazz) {
+        if (excludePackages == null || excludePackages.length == 0) {
+            return false;
+        }
+        for (int i = 0; i < excludePackages.length; i++) {
+            String name = clazz.getName();
+            String excludePackage = excludePackages[i];
+            if (name.startsWith(excludePackage)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public Set<Class> getDependOnClassList(String[] excludePackages) {
+
+        Set<Class> clazzList = new HashSet<>();
+        Map<Class, Map<Class, Class>> fieldMapList = getFieldMapList();
+        fieldMapList.keySet().forEach((key) -> {
+            Map<Class, Class> classClassMap = fieldMapList.get(key);
+            classClassMap.forEach((K, V) -> {
+                if (!isExcludePackages(excludePackages, V)) {
+                    clazzList.add(V);
+                }
+            });
+        });
+        return clazzList;
+    }
+}

+ 2 - 1
elab-spring/src/main/java/com/elab/spring/intercept/SQLMonitorPostCallback.java

@@ -34,9 +34,10 @@ public class SQLMonitorPostCallback implements SQLPostProcess {
             // 从请求参数中抓取可靠信息
             Object requestParams = sqlResult.getRequestParams();
             try {
+                sqlMonitorDTO.setAffectedRows(DataUtils.getDefaultValue(sqlResult.getResult(), 0));
+                // 如果没有id的话可能会报错
                 String id = org.apache.commons.beanutils.BeanUtils.getProperty(requestParams, "id");
                 sqlMonitorDTO.setDataId(id);
-                sqlMonitorDTO.setAffectedRows(DataUtils.getDefaultValue(sqlResult.getResult(), 0));
             } catch (Exception e) {
 
             }

+ 12 - 0
elab-spring/src/test/java/com/elab/spring/intercept/SQLMonitorPostCallbackTest.java

@@ -1,7 +1,19 @@
 package com.elab.spring.intercept;
 
+import com.alibaba.fastjson.JSONObject;
+import com.elab.core.spring.common.utils.BeanUtils;
 import junit.framework.TestCase;
+import org.junit.Test;
+
+import java.lang.reflect.InvocationTargetException;
 
 public class SQLMonitorPostCallbackTest extends TestCase {
 
+    @Test
+    public void test() throws Exception {
+        JSONObject jsonObject = new JSONObject();
+        String id = org.apache.commons.beanutils.BeanUtils.getProperty(jsonObject, "id");
+        System.out.println(id);
+    }
+
 }