|
@@ -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 ");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|