反射应用-异常处理

/ 默认分类 / 0 条评论 / 915浏览

在处理全局异常的时候,我想做的是同时支持自定义异常的捕获处理,这个时候我需要获取当前捕获的异常,然后比较识别当前是哪一个异常,如果没有找到对应的自定义异常则为全局通用异常


    @ExceptionHandler(Exception.class)
    public R dealGlobalExcep(Exception e) throws IOException {

        if(!CentralConfigValue.env.equals("prod"))
        {
            e.printStackTrace();
        }
        WhatSoftError error = SystemUtil.combineError(e);
        //发送告警邮件
        Map<String,Object> valueMap = new HashMap<>();

        BasicResp basicResp = CommonUtil.isKonownExcep(e) ? ((HuiExcep)(e)).getBasicResp() : null;
        if(basicResp != null)
        {
            valueMap.put("code",basicResp.getCode());
        }
        else
        {
            valueMap.put("code","1");
        }

        valueMap.put("msg", error.getErrname());
        valueMap.put("cluster", CommonUtil.getCurrentServerIp());
        valueMap.put("info", error.getInfo());
        valueMap.put("happentime", new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()));
        emailUtil.sendApiAlertMail(valueMap);
        log.error(error.toString());
        //如果不是null则为自定义的异常
        if(basicResp != null)
        {
            return R.fail()
                    .codeMsg(basicResp);
        }
        //否则为全局通用异常
        else
        {
            return R.fail()
                    .codeMsg(BasicResp.FAIL);
        }
    }

这里需要实现的是,按照指定的包获取包下的所有类class


public class SystemUtil {


    private SystemUtil() {
    }

    static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss");

    public static WhatSoftError combineError(Exception e) throws IOException {
        final WhatSoftError[] whatSoftError = {null};
        List<String> errorList = new ArrayList<>();
        StackTraceElement[] stackTrace = e.getStackTrace();
        int stackLen = stackTrace.length;
        if (stackLen >= 6) {
            for (int i = 0; i < 6; i++) {
                errorList.add("[" + sdf.format(new Date()) + "] Line:" + stackTrace[i].getLineNumber() + " " + stackTrace[i].getClassName() + "." + stackTrace[i].getMethodName() + "(...)");
            }
        } else if (stackLen >= 1 && stackLen < 5) {
            for (int i = 0; i < stackLen; i++) {
                errorList.add("[" + sdf.format(new Date()) + "] Line:" + stackTrace[i].getLineNumber() + " " + stackTrace[i].getClassName() + "." + stackTrace[i].getMethodName() + "(...)");
            }
        } else {
            errorList.add("[" + sdf.format(new Date()) + "] no stack call information");
        }

        Set<Class<?>> excepClassList = SystemUtil.getClasses("cn.whatsoft.exception");
        excepClassList.forEach(excep -> {
            try {
                if (e.getClass().isInstance(excep.newInstance())) {
                    whatSoftError[0] = new WhatSoftError(excep.cast(e).toString(), errorList);
                }
            } catch (InstantiationException e1) {
                e1.printStackTrace();
            } catch (IllegalAccessException e1) {
                e1.printStackTrace();
            }
        });
        return whatSoftError[0] == null ? new WhatSoftError(e.toString(), errorList) : whatSoftError[0];
    }


    public static Set<Class<?>> getClasses(String packageName) throws IOException {
        Set<Class<?>> classSet = new HashSet<>();
        Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageName.replace(".", "/"));
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            if (url != null) {
                String protocol = url.getProtocol();
                if (protocol.equals("file")) {
                    String packagePath = url.getPath().replaceAll("%20", " ");
                    addClassExcludeSonPackage(classSet, packagePath, packageName);
                } else if (protocol.equals("jar")) {
                    JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                    if (jarURLConnection != null) {
                        JarFile jarFile = jarURLConnection.getJarFile();
                        if (jarFile != null) {
                            Enumeration<JarEntry> jarEntries = jarFile.entries();
                            while (jarEntries.hasMoreElements()) {
                                JarEntry jarEntry = jarEntries.nextElement();
                                String jarEntryName = jarEntry.getName();
                                if (jarEntryName.endsWith(".class")) {
                                    String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
                                    doAddClass(classSet, className);
                                }
                            }
                        }
                    }
                }
            }
        }

        return classSet;
    }

    private static void addClassExcludeSonPackage(Set<Class<?>> classSet, String packagePath, String packageName) {
        File[] files = new File(packagePath).listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
            }
        });
        for (File file : files) {
            String fileName = file.getName();
            if (file.isFile()) {
                String className = fileName.substring(0, fileName.lastIndexOf("."));
                if (MyStringUtil.isNotEmpty(packageName)) {
                    className = packageName + "." + className;
                }
                doAddClass(classSet, className);
            } else {
                System.out.println(file.getName() +  "是子包,已跳过");
            }
        }
    }


    private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) {
        File[] files = new File(packagePath).listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
            }
        });
        for (File file : files) {
            String fileName = file.getName();
            if (file.isFile()) {
                String className = fileName.substring(0, fileName.lastIndexOf("."));
                if (MyStringUtil.isNotEmpty(packageName)) {
                    className = packageName + "." + className;
                }
                doAddClass(classSet, className);
            } else {
                String subPackagePath = fileName;
                if (MyStringUtil.isNotEmpty(packagePath)) {
                    subPackagePath = packagePath + "/" + subPackagePath;
                }
                String subPackageName = fileName;
                if (MyStringUtil.isNotEmpty(packageName)) {
                    subPackageName = packageName + "." + subPackageName;
                }
                addClass(classSet, subPackagePath, subPackageName);
            }
        }
    }

    public static Class<?> loadClass(String className, boolean isInitialized) {
        Class<?> cls;
        try {
            cls = Class.forName(className, isInitialized, getClassLoader());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return cls;
    }

    public static Class<?> loadClass(String className) {
        return loadClass(className, true);
    }

    private static void doAddClass(Set<Class<?>> classSet, String className) {
        Class<?> cls = loadClass(className, false);
        classSet.add(cls);
    }

}

这里有一个技巧,这一步

BasicResp basicResp = CommonUtil.isKonownExcep(e) ? ((HuiExcep)(e)).getBasicResp() : null;

因为我们捕获的异常e是不确定的,所以这里我们无法e.getBasicResp(),因为这里的e是Exception,方法就是让我们的所有的自定义异常实现同一个接口,这样就可以直接类型转换了

public interface HuiExcep {

    BasicResp getBasicResp();

}


@Data
@AllArgsConstructor
@NoArgsConstructor
public class QueryALonelyExcep extends RuntimeException implements HuiExcep {

    BasicResp basicResp;

    Boolean isSendEmail;

    String emailTitle;

    public QueryALonelyExcep(BasicResp basicResp, Boolean isSendEmail) {
        this.basicResp = basicResp;
        this.isSendEmail = isSendEmail;
    }

}

我用反射写过类似于springbootcache这样的缓存框架,也写过很多小工具,说真的,如果你真正掌握了反射技术,你看待所有技术框架以及开发很多应用功能的角度都会发生很大的改变(当然我的路还很远),一起打怪踩坑变强吧!!