Spring Boot可运行的jar无法加载兵马俑

时间:2016-11-10 18:21:53

标签: spring spring-boot classloader terracotta urlclassloader

我一整天都在拔头发。我终于找到了解决方法,但我真的想知道它为什么会发生。

我有一个带有一堆依赖项的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 ???

0 个答案:

没有答案