我一整天都在拔头发。我终于找到了解决方法,但我真的想知道它为什么会发生。
我有一个带有一堆依赖项的spring boot应用程序(activemq,hibernate,terracotta等),它们在Eclipse内部完美运行,我使用默认的spring boot maven插件构建它:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
输入:
mvn clean package
它构建了一个可运行的uberjar,当我运行它时,我可以看到它连接到ActiveMQ,然后它使用Hibernate连接到数据库,然后当它尝试连接到Terracotta缓存时,我得到:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataCacheRegistry' defined in class path resource [com/algomi/ase/terracotta/DataCacheRegistryConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.algomi.infra.server.datacache.DataCacheRegistry]: Factory method 'dataCacheRegistry' threw exception; nested exception is java.lang.RuntimeException: Cannot create module because of error with DataCache configuration for module: AseCalculatorRestService
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1128) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1023) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1128) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1056) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
... 27 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.algomi.infra.server.datacache.DataCacheRegistry]: Factory method 'dataCacheRegistry' threw exception; nested exception is java.lang.RuntimeException: Cannot create module because of error with DataCache configuration for module: AseCalculatorRestService
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
... 40 common frames omitted
Caused by: java.lang.RuntimeException: Cannot create module because of error with DataCache configuration for module: AseCalculatorRestService
at com.algomi.infra.server.datacache.DatacacheFactory.buildDataCache(DatacacheFactory.java:72) ~[infra-server-common-1.2.7.jar!/:1.2.7]
at com.algomi.infra.server.datacache.DatacacheFactory.buildDataCaches(DatacacheFactory.java:32) ~[infra-server-common-1.2.7.jar!/:1.2.7]
at com.algomi.ase.terracotta.DataCacheRegistryConfig.dataCacheRegistry(DataCacheRegistryConfig.java:23) ~[classes!/:0.0.2-SNAPSHOT]
at com.algomi.ase.terracotta.DataCacheRegistryConfig$$EnhancerBySpringCGLIB$$780857d9.CGLIB$dataCacheRegistry$0(<generated>) ~[classes!/:0.0.2-SNAPSHOT]
at com.algomi.ase.terracotta.DataCacheRegistryConfig$$EnhancerBySpringCGLIB$$780857d9$$FastClassBySpringCGLIB$$35534a1e.invoke(<generated>) ~[classes!/:0.0.2-SNAPSHOT]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356) ~[spring-context-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
at com.algomi.ase.terracotta.DataCacheRegistryConfig$$EnhancerBySpringCGLIB$$780857d9.dataCacheRegistry(<generated>) ~[classes!/:0.0.2-SNAPSHOT]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ~[spring-beans-4.3.3.RELEASE.jar!/:4.3.3.RELEASE]
... 41 common frames omitted
Caused by: java.lang.reflect.InvocationTargetException: null
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_60]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_60]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_60]
at java.lang.reflect.Constructor.newInstance(Constructor.java:422) ~[na:1.8.0_60]
at com.algomi.infra.server.datacache.DatacacheFactory.buildDataCache(DatacacheFactory.java:68) ~[infra-server-common-1.2.7.jar!/:1.2.7]
... 53 common frames omitted
Caused by: net.sf.ehcache.CacheException: Unable to load class net.sf.ehcache.terracotta.StandaloneTerracottaClusteredInstanceFactory. Initial cause was null
at net.sf.ehcache.util.ClassLoaderUtil.createNewInstance(ClassLoaderUtil.java:109) ~[ehcache-core-2.6.11.jar!/:na]
at net.sf.ehcache.terracotta.TerracottaClusteredInstanceHelper.newClusteredInstanceFactory(TerracottaClusteredInstanceHelper.java:176) ~[ehcache-core-2.6.11.jar!/:na]
at net.sf.ehcache.terracotta.TerracottaClient.createNewClusteredInstanceFactory(TerracottaClient.java:186) ~[ehcache-core-2.6.11.jar!/:na]
at net.sf.ehcache.terracotta.TerracottaClient.createClusteredInstanceFactory(TerracottaClient.java:138) ~[ehcache-core-2.6.11.jar!/:na]
at net.sf.ehcache.CacheManager.doInit(CacheManager.java:432) ~[ehcache-core-2.6.11.jar!/:na]
at net.sf.ehcache.CacheManager.init(CacheManager.java:377) ~[ehcache-core-2.6.11.jar!/:na]
at net.sf.ehcache.CacheManager.<init>(CacheManager.java:317) ~[ehcache-core-2.6.11.jar!/:na]
at com.capxd.infra.common.model.EhcacheManager.getCacheManager(EhcacheManager.java:42) ~[messaging-2.1.1.jar!/:na]
at com.capxd.infra.common.model.EhcacheManager.getBackingCache(EhcacheManager.java:27) ~[messaging-2.1.1.jar!/:na]
at com.capxd.infra.common.model.EhcacheDataCache.getBackingCache(EhcacheDataCache.java:63) ~[messaging-2.1.1.jar!/:na]
at com.capxd.infra.common.model.EhcacheDataCache.<init>(EhcacheDataCache.java:43) ~[messaging-2.1.1.jar!/:na]
... 58 common frames omitted
Caused by: java.lang.ExceptionInInitializerError: null
at net.sf.ehcache.terracotta.StandaloneTerracottaClusteredInstanceFactory.<init>(StandaloneTerracottaClusteredInstanceFactory.java:37) ~[ehcache-terracotta-2.6.11.jar!/:na]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_60]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_60]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_60]
at java.lang.reflect.Constructor.newInstance(Constructor.java:422) ~[na:1.8.0_60]
at net.sf.ehcache.util.ClassLoaderUtil.createNewInstance(ClassLoaderUtil.java:92) ~[ehcache-core-2.6.11.jar!/:na]
... 68 common frames omitted
Caused by: java.lang.RuntimeException: java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at com.terracotta.express.ClientFactoryImpl.<init>(ClientFactoryImpl.java:93) ~[terracotta-toolkit-1.6-runtime-5.10.0.jar!/:na]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_60]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_60]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_60]
at java.lang.reflect.Constructor.newInstance(Constructor.java:422) ~[na:1.8.0_60]
at java.lang.Class.newInstance(Class.java:442) ~[na:1.8.0_60]
at org.terracotta.express.Util.getImplInstance(Util.java:11) ~[terracotta-toolkit-1.6-runtime-5.10.0.jar!/:na]
at org.terracotta.express.ClientFactory.<clinit>(ClientFactory.java:14) ~[terracotta-toolkit-1.6-runtime-5.10.0.jar!/:na]
... 74 common frames omitted
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1931) ~[na:1.8.0_60]
at org.springframework.boot.loader.jar.JarURLConnection.extractFullSpec(JarURLConnection.java:257) ~[ase-calculator-rest-service-0.0.2-20161110.103558-5.jar:0.0.2-SNAPSHOT]
at org.springframework.boot.loader.jar.JarURLConnection.get(JarURLConnection.java:228) ~[ase-calculator-rest-service-0.0.2-20161110.103558-5.jar:0.0.2-SNAPSHOT]
at org.springframework.boot.loader.jar.Handler.openConnection(Handler.java:88) ~[ase-calculator-rest-service-0.0.2-20161110.103558-5.jar:0.0.2-SNAPSHOT]
at java.net.URL.openConnection(URL.java:972) ~[na:1.8.0_60]
at java.net.URL.openStream(URL.java:1038) ~[na:1.8.0_60]
at com.terracotta.express.ClientFactoryImpl.handleJarUrl(ClientFactoryImpl.java:102) ~[terracotta-toolkit-1.6-runtime-5.10.0.jar!/:na]
at com.terracotta.express.ClientFactoryImpl.<init>(ClientFactoryImpl.java:84) ~[terracotta-toolkit-1.6-runtime-5.10.0.jar!/:na]
... 81 common frames omitted
我下载了兵马俑的所有源代码,然后是Spring loader,最终发现问题出在方法中:
private static String extractFullSpec(URL url, String pathFromRoot) {
String file = url.getFile();
int separatorIndex = file.indexOf(SEPARATOR);
if (separatorIndex < 0) {
return "";
}
int specIndex = separatorIndex + SEPARATOR.length() + pathFromRoot.length();
return file.substring(specIndex);
}
此方法位于org.springframework.boot.loader.jar.JarURLConnection
中的spring-boot-loader-1.4.1.RELEASE.jar
。问题似乎在传入参数url
中。以下罐子(据我所知,每隔一个罐子)加载没有问题:
file:/C:/Dev/Repos/state-engine/calculator-rest-service/target/calculator-rest-service-0.0.2-SNAPSHOT.jar!/BOOT-INF/lib/spring-boot-starter-validation-1.4.1.RELEASE.jar!/
file:/C:/Dev/Repos/state-engine/calculator-rest-service/target/calculator-rest-service-0.0.2-SNAPSHOT.jar!/BOOT-INF/lib/evo-inflector-1.2.1.jar!/
file:/C:/Dev/Repos/state-engine/calculator-rest-service/target/calculator-rest-service-0.0.2-SNAPSHOT.jar!/BOOT-INF/lib/hibernate-c3p0-3.6.10.Final.jar!/
然后兵马俑失败了:
file:/C:/Dev/Repos/state-engine/calculator-rest-service/target/calculator-rest-service-0.0.2-SNAPSHOT.jar!/BOOT-INF/lib/terracotta-toolkit-1.6-runtime-5.10.0.jar!
StringIndexOutOfBoundsException
发生了,因为据我所知,方法中假设所有网址都以“!/”结尾,但是兵马俑的网址缺少尾随的“/”。
解决方法是在我的pom中添加以下内容以使Launcher成为PropertiesLauncher:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout>
</configuration>
</plugin>
</plugins>
</build>
将我的兵马俑罐子放在一个单独的libs文件夹中,用java -Dloader.path=C:/temp/libs/lib -jar xxx
运行我的罐子。
虽然必须让我的兵马俑罐子放在一个单独的libs文件夹中,但是当我的其他罐子从我的uberjar里面完全加载时,这很烦人。
我是如何让uberjar在其中使用赤陶和使用JarLauncher而不是使用PropertiesLauncher ???