尝试spring3.0的新特性,在原本是spring207,spring256混杂的工程里引入了spring3.x然后很简单的一个bean初始化失败,报以下异常
Caused by: java.lang.reflect.MalformedParameterizedTypeException at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.validateConstructorArguments(Unknown Source) at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.<init>(Unknown Source) at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.make(Unknown Source) at sun.reflect.generics.factory.CoreReflectionFactory.makeParameterizedType(Unknown Source) at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Unknown Source) at sun.reflect.generics.tree.ClassTypeSignature.accept(Unknown Source) at sun.reflect.generics.repository.ClassRepository.getSuperInterfaces(Unknown Source) at java.lang.Class.getGenericInterfaces(Unknown Source) at org.springframework.core.GenericTypeResolver.getTypeVariableMap(GenericTypeResolver.java:151) at org.springframework.core.GenericTypeResolver.resolveParameterType(GenericTypeResolver.java:81) at org.springframework.beans.GenericTypeAwarePropertyDescriptor.getWriteMethodParameter(GenericTypeAwarePropertyDescriptor.java:109) at org.springframework.beans.GenericTypeAwarePropertyDescriptor.getPropertyType(GenericTypeAwarePropertyDescriptor.java:91) at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:138) at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:386) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1289) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1250) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1010) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472) ... 14 more
然后找出抛出异常的jdk源码
private void validateConstructorArguments() { TypeVariable[] formals = this.rawType.getTypeParameters(); if (formals.length != this.actualTypeArguments.length) { throw new MalformedParameterizedTypeException(); } for (int i = 0; i < this.actualTypeArguments.length; ++i); }
利用jdk的fastdebug版本可以看到formals.length == 0 而this.actualTypeArguments.length ==1
并且:
actualTypeArguments 是 【interface org.springframework.core.task.TaskExecutor】
rawType 是【interface org.springframework.beans.factory.FactoryBean】并且不具有泛型参数,故猜测这里需要一个泛型参数是TaskExecutor的FactoryBean。
ok,下面开始找出这个bean的实例化是如何进行的,这个bean是spring3.0中新提供的,配置方式如下:
<task:executor id="myExecutor" pool-size="5"/>
通过debug跟踪到spring的BeanDefinitionParserDelegate这个类,然后看如下这个方法
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = ele.getNamespaceURI(); NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
为了跟踪这个bean的默认bean实现,我们看他的NamespaceHandler是什么,通过看DefaultNamespaceHandlerResolver这个类可以得知,所有的handler都是从META-INF/spring.handlers文件中读出的,同时如果你打开了debug log的话可以看到他会打印出所有默认的handler,例如打印如下
Loaded mappings [{http://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler, http://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler, http://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler, http://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler, http://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler, http://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler, http://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler, http://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler, http://www.springframework.org/schema/jms=org.springframework.jms.config.JmsNamespaceHandler, http://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler, http://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler}]
这里就有我这次使用到的TaskNamespaceHandler 然后依次找到了 ExecutorBeanDefinitionParser这个类,看到里面的getBeanClassName方法返回的是org.springframework.scheduling.config.TaskExecutorFactoryBean。同时这个类实现了FactoryBean<TaskExecutor>这个接口。发现原来已经给了一个带泛型的FactoryBean了。那到底是哪里的问题呢,继续跟踪。。
借助jdk源码以及fastdebug版本,跟踪到sun.reflect.generics.repository.ClassRepository 和 sun.reflect.generics.factory.CoreReflectionFactory这个2个类,看到里面有对应的泛型信息,但是取到的却不对,继续跟踪到Class这个类,其中核心的会使用这个方法
public TypeVariable<Class<T>>[] getTypeParameters() { if (getGenericSignature() != null) return (TypeVariable<Class<T>>[])getGenericInfo().getTypeParameters(); else return (TypeVariable<Class<T>>[])new TypeVariable[0]; }
debug看到第一个if没通过,所以返回一个空的,那第一个getGenericSignature方法就至关重要了。下面debug这个方法,以下是方法签名:
// Generic signature handling private native String getGenericSignature();
一看是native方法,好吧直接断了我继续debug的耐心了。不过到这里已经有了一些眉目了,针对这个问题产生的原因,既然是从class的本地元信息中获得泛型信息,那说明这个class文件可能真的就不存在这些元信息,那这样可能就是jar包污染了。然后将spring 207 256的jar包都删除,只保留3.0的,重新debug发现,这次native就有返回值了。程序不再报错了。
总结:以后遇到这个异常,多半先检查下jar包版本是否存在多个版本,然后最后统一只使用到其中的一个版本来测试,这种问题太难排查了,先把环境搞干净了再debug吧。