使用mybatis后导致注入失败(OGNL导致的并发安全问题)
使用mybatis后导致注入失败(OGNL导致的并发安全问题)上诉异常堆栈信息在并发环境下果然重现出现,根据异常信息代码执行至该行代码时发生异常:多线程并发环境下的压测代码公司后端采用Mybatis作为数据访问层 所使用版本为3.2.3。线上环境业务系统在运行过程中出现了一个令人困惑的异常 该异常时而出现时而不出现,构造各种OGNL表达式为空等特殊情况均不会重现该异常。具体异常堆栈信息如下:List的size()方法明显是public为何还会出现不可访问的异常。该问题并不是每一次都会出现,经过多次尝试,该异常一直未在测试环境重现。该接口在完整调用链路中的出错次数占总调用次数的比率为0.01% 无意中联想到并发问题在周期性时间内往往是概率性发生。编写模拟多线程环境并发读取公司列表测试代码:
来自:知乎,作者:蓬蒿
链接:https://zhuanlan.zhihu.com/p/30085658
mybatis是一个开源的轻量级半自动化ORM框架,使得面向对象应用程序与关系数据库的映射变得更加容易。MyBatis使用xml描述符或注解将对象与存储过程或SQL语句相结合。Mybatis最大优点是应用程序与Sql进行解耦,sql语句是写在Xml Mapper文件中。
OGNL表达式在Mybatis当中应用非常广泛,其表达式的灵活性使得动态Sql功能的非常强大。OGNL是Object-Graph Navigation language的缩写,代表对象图导航语言。OGNL是一种EL表达式语言,用于设置和获取Java对象的属性,并且可以对列表进行投影选择以及执行lambda表达式。Ognl类提供了许多简便方法用于执行表达式的。Struts2发布的每个版本都会出现的新的高危可执行漏洞也是因为它使用了灵活的OGNL表达式。
公司后端采用Mybatis作为数据访问层 所使用版本为3.2.3。线上环境业务系统在运行过程中出现了一个令人困惑的异常 该异常时而出现时而不出现,构造各种OGNL表达式为空等特殊情况均不会重现该异常。具体异常堆栈信息如下:
List的size()方法明显是public为何还会出现不可访问的异常。该问题并不是每一次都会出现,经过多次尝试,该异常一直未在测试环境重现。该接口在完整调用链路中的出错次数占总调用次数的比率为0.01% 无意中联想到并发问题在周期性时间内往往是概率性发生。
编写模拟多线程环境并发读取公司列表测试代码:
多线程并发环境下的压测代码
上诉异常堆栈信息在并发环境下果然重现出现,根据异常信息代码执行至该行代码时发生异常:
Caused by: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [1] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class java.util.Collections$SingletonList with modifiers "public"]
at org.apache.ibatis.ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:837)
异常信息表明OgnlRuntime类不能够访问java.util.Collections的私有成员SingletonList。查看源代码发现能够抛出MethodFailedException异常可以锁定在invokeMethod方法内部。
invokeMethod方法代码
问题出现在method实际上是一个共享变量,也就是例子中的
public int java.util.Collections$SingletonList.size()
方法
当第一个线程t1至(1)行代码允许method方法可以被调用,第二个线程t2执行至(2)将method的方法设置为不可以访问。接着t1又开始执行到(3)行的时候就会发生该异常。这是一个很典型的同步问题。
Ognl2.7已经修复了该问题,因为ognl源码是直接打包内嵌在mybatis包中,mybatis3.3.0版本中也已经进行了修复升级。(划重点)
对了,在这里说一下,我目前是在职Java开发,如果你现在正在学习Java,了解Java,渴望成为一名合格的Java开发工程师,在入门学习Java的过程当中缺乏基础入门的视频教程,可以关注并私信我:01。获取。我这里有最新的Java基础全套视频教程。