Skip to content

Latest commit

 

History

History
145 lines (112 loc) · 5.19 KB

记一次类加载时机的坑.md

File metadata and controls

145 lines (112 loc) · 5.19 KB

记一次类加载时机的坑

写了一个导出报表的工具,工具见 common-utils 项目。其中需要对格式化的实现类进行自动注册到工厂,但是第一版写出来并没有按照实际设想的方式运行,具体看正文。



自动注册工厂[Don't work]

工厂类

@Slf4j
public class FieldFormatterFactory {
    private static Map<Class, FormatterHelper> formatterCacheMap = new HashMap<>(32);

    public static <T> FieldFormatter<T> get(@NonNull Class<T> kls) {
        if (formatterCacheMap.containsKey(kls)) {
            return formatterCacheMap.get(kls);
        }
        return formatterCacheMap.get(Object.class);
    }

    public synchronized static void register(@NonNull Class kls, @NonNull FormatterHelper fieldFormatter) {
        if (formatterCacheMap.containsKey(kls)) {
            throw new FieldFormatterDuplicateException(String.format("valueType: %s, exist: %s[%s], new: %s[%s]", kls.getName(),
                    formatterCacheMap.get(kls).getClass().getName(), formatterCacheMap.get(kls).getClass().getClassLoader(),
                    fieldFormatter.getClass().getName(), fieldFormatter.getClass().getClassLoader()));
        }
        formatterCacheMap.put(kls, fieldFormatter);
        log.info(String.format("valueType: %s, new: %s[%s]", kls.getName(),
                fieldFormatter.getClass().getName(), fieldFormatter.getClass().getClassLoader()));
    }
}

formatter 实现类

public class DefaultFieldFormatter extends AbstractFieldFormatter<Object> {

    static{
        FieldFormatterFactory.register(Object.class, new DefaultFieldFormatter());
    }

    @Override
    public Set<Class> getValueTypes() {
        Set<Class> kls = new HashSet<>();
        kls.add(Object.class);
        return kls;
    }

    @Override
    public String apply(ColMata colMata, Object o) {
        return ObjectUtils.defaultIfNull(o, "").toString();
    }
}

最初设计时,是希望 Formatter 实现类在加载的时候能自动执行 static 代码块,将自己注册到工厂里,但是运行单元测试时,工厂内并没有实现类,导致了空指针。

因为注册方法如果被调用是会有日志输出的,但是实际上没有,所以判断是类的 static 代码块没有执行

自动注册工厂

工厂,通过反射扫描指定的类

@Slf4j
public class FieldFormatterFactory {
    private static Map<Class, FormatterHelper> formatterCacheMap = new HashMap<>(32);

    static {
        Reflections reflections = new Reflections(FieldFormatterFactory.class.getPackage().getName());
        Set<Class<? extends FormatterHelper>> classes = reflections.getSubTypesOf(FormatterHelper.class);
        classes.forEach(formatter -> {
            try {
                if (Modifier.isAbstract(formatter.getModifiers())) {
                    log.info("{} is abstract class, skipped.", formatter.getName());
                    return;
                }

                FormatterHelper formatterHelper = formatter.newInstance();
                Set<Class> klsSet = formatterHelper.getValueTypes();

                klsSet.forEach(valueType -> {
                    register(valueType, formatterHelper);
                });

            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        });
    }

    public static <T> FieldFormatter<T> get(@NonNull Class<T> kls) {
        if (formatterCacheMap.containsKey(kls)) {
            return formatterCacheMap.get(kls);
        }
        return formatterCacheMap.get(Object.class);
    }

    public synchronized static void register(@NonNull Class kls, @NonNull FormatterHelper fieldFormatter) {
        if (formatterCacheMap.containsKey(kls)) {
            throw new FieldFormatterDuplicateException(String.format("valueType: %s, exist: %s[%s], new: %s[%s]", kls.getName(),
                    formatterCacheMap.get(kls).getClass().getName(), formatterCacheMap.get(kls).getClass().getClassLoader(),
                    fieldFormatter.getClass().getName(), fieldFormatter.getClass().getClassLoader()));
        }
        formatterCacheMap.put(kls, fieldFormatter);
        log.info(String.format("valueType: %s, new: %s[%s]", kls.getName(),
                fieldFormatter.getClass().getName(), fieldFormatter.getClass().getClassLoader()));
    }
}
public class DefaultFieldFormatter extends AbstractFieldFormatter<Object> {

    @Override
    public Set<Class> getValueTypes() {
        Set<Class> kls = new HashSet<>();
        kls.add(Object.class);
        return kls;
    }

    @Override
    public String apply(ColMata colMata, Object o) {
        return ObjectUtils.defaultIfNull(o, "").toString();
    }
}

参考

  1. 解析 Java 类和对象的初始化过程
  2. 深入理解Java虚拟机