静态方法抛出运行时异常导致反射生成实例失败
场景还原
1. 启动时,static属性获取时便打印了异常,不过没有注意到。
2. 之后在异常无法捕获之处既无正常往下走到return,也没有被Catch捕获异常,甚至在该行无法Step in进入debug,最终被外层的finally块处理。
生成实例失败的类
public class InnerPositionThread extends MonitorThread {
Logger logger = LoggerFactory.getLogger(getClass());
private static Map<String, List<BlockField>> blockAttrCfg = BlockUtils.getBlocks("innerposition.xml");
}
抛出运行时异常的方法
public class BlockUtils {
public static Map<String, List<BlockField>> getBlocks(String templateName) {
try {
// do something
}
} catch (Exception var14) {
var14.printStackTrace();
throw new RuntimeException(var14);
}
}
无法捕获异常之处
try {
Object monitor;
// 下面这行将会异常
monitor = (IfMonitor)Class.forName(mClass).newInstance();
return null;
} catch (Exception var4) {
log.error("启动监视器失败 " + config.getName() + " (" + monitorKey + ")", var4);
return getStartFalseResponse(config, monitorKey, isCreate ? "监视器已建立,激活失败" : "启动监视器失败");
}
重试
另起工程简化示例进行查看原因。
接口
public interface InterfaceA {
void functionA();
}
类
静态属性初始化抛出异常
public class ClassImplA implements InterfaceA {
private static Logger logger = LoggerFactory.getLogger(ClassImplA.class);
private static Long staticProperties = initStaticProperties();
private static Long initStaticProperties() {
throw new RuntimeException("ClassImplA throw runtime exception");
}
@Override
public void functionA() {
logger.info("function A be called!");
}
}
测试main方法
public static void main(String[] args) {
logger.info("start main");
Object classAImpl;
String className = ClassImplA.class.getName();
logger.info("start get class A");
try {
classAImpl = (InterfaceA)Class.forName(className).newInstance();
((InterfaceA)classAImpl).functionA();
} catch (Exception e) {
logger.error("catch exception反射失败" + e.getMessage());
} catch (Error e) {
logger.error("catch error反射失败" + e.getMessage());
} finally {
logger.info("in finally end get class A");
}
logger.info("end main");
}
测试输出
六月 02, 2020 2:34:52 下午 forname.MainTest main
信息: start main
六月 02, 2020 2:34:52 下午 forname.MainTest main
信息: start get class A
六月 02, 2020 2:34:52 下午 forname.MainTest main
严重: catch error反射失败null
六月 02, 2020 2:34:52 下午 forname.MainTest main
信息: in finally end get class A
六月 02, 2020 2:34:52 下午 forname.MainTest main
信息: end main
观察捕获到Error,而非Exception,打印堆栈可见,其最终抛出的错误是ExceptionInInitializerError
。
java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at forname.MainTest.main(MainTest.java:16)
Caused by: java.lang.RuntimeException: ClassImplA throw runtime exception
at forname.ClassImplA.initStaticProperties(ClassImplA.java:12)
at forname.ClassImplA.<clinit>(ClassImplA.java:9)
... 3 more
通过查看该类的继承发现ExceptionInInitializerError
继承LinkageError
,再继承Error
,最终继承Throwable
,所以该ExceptionInInitializerError
不会被Exception
的catch块捕获。
结论
通过请教他人得知:
- 这类Error必须干掉,不能带进程序,
- static属性初始化也不允许抛出异常,
- catch块也不能去抓取
error
或者Throwable
的错误。