zoukankan      html  css  js  c++  java
  • Java异常处理设计(二)

    考虑对JDK的底层堆栈信息进行处理,一种是重写JDK的Throwable,另一种是在原错误堆栈信息上进行“二次加工”。目前这两种方式我都实现了,效果非常好。

    这篇文章主要记录对错误堆栈进行“二次加工”的实现过程。

    从大量的实际错误日志分析出发:

    首先,追根溯源,找到错误是从哪个地方new出来的。

    例如
    com.jfinal.plugin.activerecord.ActiveRecordException: java.lang.ClassCastException: com.alibaba.druid.sql.visitor.SQLEvalVisitorImpl cannot be cast to com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitor
     at com.jfinal.plugin.activerecord.Db.paginate(Db.java:554)
     at com.jfinal.plugin.activerecord.Db.paginate(Db.java:593)
     at com.simple.sqpt.services.FWCXService.doGetHouseInfo(FWCXService.java:172)

    那么是在Db.paginate(Db.java:554)这一行new出来的,后面有:
    Caused by: java.lang.ClassCastException: com.alibaba.druid.sql.visitor.SQLEvalVisitorImpl cannot be cast to com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitor
     at com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock.accept0(SQLServerSelectQueryBlock.java:39)
     at com.alibaba.druid.sql.ast.SQLObjectImpl.accept(SQLObjectImpl.java:40)
    说明这个new出来的错误,是包裹了另外一个错误,可能是有new ActiveRecordException(e);然后这个e是一个ClassCastException类型错误
    因为只有一个Caused by,可以肯定,这个(ClassCastException) e 是源头,是从:
    SQLServerSelectQueryBlock.accept0(SQLServerSelectQueryBlock.java:39)这里new出来的。

    应用的栈信息可能夹在中间,比如:

    org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is com.ibm.websphere.ce.cm.StaleConnectionException: The Network Adapter could not establish the connectionDSRA0010E: SQL State = 61000, Error Code = 20
      at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:82)
      at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:577)
      at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:641)
      at org.springframework.jdbc.core.JdbcTemplate.queryForInt(JdbcTemplate.java:759)
      at com.proj.webc.persist.framework.BaseDAO.queryForCount(BaseDAO.java:142)
      at com.proj.webc.persist.office.dao.OfficeDAO.queryBackUsersCountByCondition(OfficeDAO.java:734)
      at com.proj.webc.logic.office.OfficeManagerImpl.queryCountOfficeByCondition(OfficeManagerImpl.java:79)
      at com.proj.webc.present.orderquery.action.FrontOrderQueryAction.doAction(FrontOrderQueryAction.java:118)
      at com.proj.webc.framework.BaseAction.execute(BaseAction.java:205)
      at sun.reflect.GeneratedMethodAccessor81.invoke(Unknown Source)
      at java.lang.reflect.Method.invoke(Method.java:600)
      at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450)
      at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289)

    像这种,其实我们只能操纵应用之前的错误信息,应用之后的,超出了我们的管理范围。 比如上面这个例子,在com.proj.**之前的org.springframework.**是我们可以管理的, 但是后面的sun.reflect.**,java.lang.**,com.opensymphony.**都超出了应用的可视范围。 (除非从源头控制,比如com.opensymphony.**的源码,最上层,应该是webContainer,例如websphere下,最外层的栈信息都是com.ibm.**开头)

    分析上面的错误信息,我们可以操作的最外层,是 com.proj.webc.framework.BaseAction.execute(BaseAction.java) 我们可以在这个地方做工作,把它管辖之下的错误信息进行整理,例如可以把 org.springframework.**这种信息都过滤掉。

    如果是用log工具,我们就有控制权。

    综上分析,对于最上层,紧跟着错误信息的地方,只需要追溯到错误new出来之前的前几个轨迹即可。 一般来说,只需要跟踪和new出来错误的那个类在同一个api包之中的,比如上面这个例子, 只需要跟踪到第二行 com.jfinal.plugin.activerecord.Db.paginate(Db.java:593)即可。

    对于Caused by,是非常核心的错误出处,一般是在应用之中的,可采取和上面一样的处理方式,如果是调用第三方api抛出的错误,如上面那个例子。 其实捕获栈信息的意义不是很大,但是也可以少量捕捉一些,比如一前一尾。但是尾巴不好判断,所以考虑到性能,只捕捉前面2行就够意思了。后面的话 要逐行判断,如果是本应用的类,则捕捉。

    捕捉到最后,是三个点:  ... 39 more 这样,Caused by就处理完成了。如果后面还有Caused by,也用该方法继续捕捉。

    综上,其实就一个方法: 检测非 at开头的字符串,记录其信息。(可设定长度大小,比如小于1000)

    对于 at开头的字符串,判断是否为本应用+特定api的前缀,是则保留。

    特殊处理: 保留紧跟着非 at开头的字符串的2行栈信息,

    保留出现本应用+特定api前缀那一行的前3行信息。

    算法复杂度,假设有100行,一行比较30次char(用startWith),总共for循环100次,每次比较一个startWith,

    每次循环假设还做一个5个if的判断,那么一共比较的次数为500+3000=3500,对CPU来说,应该不成问题。

  • 相关阅读:
    Neither BindingResult nor plain target object for bean name 'command' available as request attribute
    a href 相对路径 与绝对路径
    sql with as用法详解
    union和union all的区别
    从此不再惧怕URI编码:JavaScript及C# URI编码详解
    Server.UrlEncode、HttpUtility.UrlDecode的区别
    两种获取connectionString的方式
    微软SQLHelper.cs类 中文版
    web.config connectionStrings 数据库连接字符串的解释
    SQL Server 事务处理 回滚事务
  • 原文地址:https://www.cnblogs.com/zollty/p/3430743.html
Copyright © 2011-2022 走看看