JBPM 异常分析.
JBPM 4.0
使用hibernate 3.6.0
作为数据持久框架,该版本依赖的javassist版本为3.12.0.GA
Hibernate中的每个Entity
其实都是代理过的类,由javassit
生成一个代理类
去继承Entity
类。
举个例子
public class Phone { |
你会发现
执行UserImplProxy.class.getDeclaredMethods()
后
你会发现返回结果“多出”一个synthetic bridge
方法getPhone()Lcom/project/pangu/cache/Phone; 0x1041 [public synthetic bridge]
(Java几种生成synthetic方法的情况,)
javassit
在代理目标类时,会把目标类中定义的所有方法都查询出来,形成Map<String,Method>
javassist 3.12.0.GA
private static void getMethods(HashMap hash, Class clazz) { |
Map的key
最终格式为:methodName:paramsTypes+returnType
javassit 3.16.0.GA
private static void getMethods(HashMap hash, Class clazz, Set visitedClasses) { |
Map的key
最终格式为:methodName:paramsTypes
当使用javaassist 3.12.0.GA
时,由于遍历目标类的方法时,Map使用的key为methodName:paramsTypes+returnType
,可以保证每个方法都能被代理到
由于项目中实际运行时使用的javassist
版本是3.16.0.GA
,(某个小伙伴引入的第三方库中使用javassist-3.16.0.GA
,覆盖了jbpm所依赖的javassist-3.12.0.GA
)
当遍历目标类的方法时,Map使用的key为methodName:paramsTypes
,当出现同名
,同形参
的方法时,这个时候能被代理到的方法和Class#getDeclaredMethods()
返回的顺序有关,该方法注释如下
Returns an array containing Method objects reflecting all the declared methods of the class or interface represented by this Class object, including public, protected, default (package) access, and private methods, but excluding inherited methods.
If this Class object represents a type that has multiple declared methods with the same name and parameter types, but different return types, then the returned array has a Method object for each such method.
If this Class object represents a type that has a class initialization method, then the returned array does not have a corresponding Method object.
If this Class object represents a class or interface with no declared methods, then the returned array has length 0.
If this Class object represents an array type, a primitive type, or void, then the returned array has length 0.
The elements in the returned array are not sorted and are not in any particular order (重点,返回数组中的元素没有排序,也没有特定顺序)
所以当执行下面代码时,有一定几率执行的方法不是代理过方法
UserImplProxy proxy = JavassistProxy(new UserImplProxy()); |
所以导致jbmp执行相关操作时,查询对象实体时,有一定几率导致返回为空(没有被代理,那么就不会触发查询)