使用Spring Security的朋友们有没有注意到这个框架的异常特别多?例如用户密码错误、密码过期、权限不足等等。控制台上打印着一堆异常堆栈信息,这不但覆盖了有价值的日志,也大大降低了程序的性能,而且这些错误堆栈信息自身的价值很小。
有没有一种方式避免打印这些异常堆栈呢?其实RuntimeException中有两个非常重要的参数:
-
enableSuppression
:指示是否将异常屏蔽(suppress),默认值为true,启用抑制的。当创建一个异常对象时,可以选择启用或禁用异常抑制。如果启用了异常抑制,那么在一个异常(称为“主异常”)抛出时,如果另一个异常(称为“被抑制的异常”)也发生,则被抑制的异常会被添加到主异常的“抑制异常”列表中。这样做的目的是为了记录被抑制的异常,同时仍然抛出主异常以便进行处理。 -
writableStackTrace
:指示是否保留堆栈跟踪信息。如果设置为true
,则表示保留堆栈跟踪信息;如果设置为false
,则表示不保留堆栈跟踪信息。默认情况下设置为true
。如果将其设置为false
,则可以在异常对象中保存空的堆栈跟踪信息,从而减少填充异常对象所需的空间和时间。
运行如下代码,观察修改writableStackTrace的效果:
public class Base1Exception extends RuntimeException {
public Base1Exception() {
super();
}
public Base1Exception(String message) {
// 第四个参数为: writableStackTrace
super(message, null, false, true);
}
}
public class Base2Exception extends RuntimeException {
public Base2Exception() {
super();
}
public Base2Exception(String message) {
// 第四个参数为: writableStackTrace
super(message, null, true, true);
}
public Base2Exception(String message, Throwable t) {
// 第四个参数为: writableStackTrace
super(message, t, false, true);
}
}
public class Demo1Application {
public static void main(String[] args) {
m1();
}
public static void m1() {
m2();
}
public static void m2() {
m3();
}
public static void m3() {
m4();
}
public static void m4() {
try {
throw new Base1Exception("Base1Exception 异常抛出");
} catch (Exception e) {
throw new Base2Exception("Base2Exception 异常抛出", e);
}
}
}
writableStackTrace=true (默认值) 的效果:
Exception in thread "main" com.example.demo.Base2Exception: Base2Exception 异常抛出
at com.example.demo.Demo1Application.m4(Demo1Application.java:26)
at com.example.demo.Demo1Application.m3(Demo1Application.java:19)
at com.example.demo.Demo1Application.m2(Demo1Application.java:15)
at com.example.demo.Demo1Application.m1(Demo1Application.java:10)
at com.example.demo.Demo1Application.main(Demo1Application.java:6)
Caused by: com.example.demo.Base1Exception: Base1Exception 异常抛出
at com.example.demo.Demo1Application.m4(Demo1Application.java:24)
... 4 more
writableStackTrace=false的效果:
Exception in thread "main" com.example.demo.Base2Exception: Base2Exception 异常抛出
Caused by: com.example.demo.Base1Exception: Base1Exception 异常抛出
由此可以发现, writableStackTrace有效的减少了日志的输出量。因此,建议在生产环境启用异常屏蔽和关闭一些业务异常的堆栈跟踪信息。但很遗憾,Spring Security 认证异常类并未重写 RuntimeException 的所有构造方法,特别是包含 enableSuppression 和 writableStackTrace 两个参数的构造方法。这导致 Spring Security 打印的日志特别多。 因此可以在你自己的工程中,通过覆写RuntimeException的所有构造方法,避免一些无效的堆栈打印。