一个项目升级到springboot4,构建成原生镜像后各种问题,经过一番摸索,终于解决了。
1、ehcache配置问题:
异常信息:
Caused by: org.ehcache.xml.exceptions.XmlConfigurationException: Error parsing XML configuration at file:/workspace/config-common/ehcache3.xml at org.ehcache.xml.XmlConfiguration.<init>(XmlConfiguration.java:127) at org.ehcache.xml.XmlConfiguration.<init>(XmlConfiguration.java:93) at org.ehcache.jsr107.EhcacheCachingProvider$ConfigSupplier.getConfiguration(EhcacheCachingProvider.java:346) ... 160 more Caused by: javax.xml.bind.JAXBException - with linked exception: [java.lang.NoSuchMethodException: com.sun.xml.bind.v2.ContextFactory.createContext([Ljava.lang.Class;, java.util.Map)] at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:305) at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:286) at javax.xml.bind.ContextFinder.find(ContextFinder.java:409) at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721) at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662) at org.ehcache.xml.ConfigurationParser.<init>(ConfigurationParser.java:118) at org.ehcache.xml.XmlConfiguration.<init>(XmlConfiguration.java:117) ... 162 more解决方法,JAXB 实现版本不匹配:需要确保引入的 JAXB 实现与 Ehcache 3 兼容,并且支持 Native。
但我正好想更换成redis缓存,所以直接更换了。
2、问题如下:
Caused by: org.postgresql.util.PSQLException: FATAL: password authentication failed for user "${spring.datasource.username}" at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:835) at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:307) at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:365) at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:52) at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:290)我是在一个配置文件里配置了spring.datasource.username,另一个配置文件引用这个变量,构建原生镜像后它解析不了这个值。
解决方法是设置两个环境变量,DB_USER, DB_PASSWORD,这样在K8S里还可以加密,比较好。
3、各类ClassNotFound异常,如:
Caused by: java.lang.IllegalStateException: Cannot load driver class: com.xcmg.finance.tmp.common.datasource.DynamicDataSource at org.springframework.util.Assert.state(Assert.java:102) at org.springframework.boot.jdbc.autoconfigure.DataSourceProperties.findDriverClassName(DataSourceProperties.java:187) at org.springframework.boot.jdbc.autoconfigure.DataSourceProperties.determineDriverClassName(DataSourceProperties.java:177) at org.springframework.boot.jdbc.autoconfigure.PropertiesJdbcConnectionDetails.getDriverClassName(PropertiesJdbcConnectionDetails.java:51) at org.springframework.boot.jdbc.autoconfigure.DataSourceConfiguration.createDataSource(DataSourceConfiguration.java:63)这类异常很是头疼,摸索了很久,终于知道原因:Springboot4构建 原生镜像时,会先启动应用,根据启动应用用到了哪些构件,它会把相应的构件包含进去,用不到的,会被丢弃,所以,我们要设置一个正确的profiles.active让它把正式启动时用到的所有类都加载进去。
解决方法:设置一个环境变量再构建:
exportSPRING_PROFILES_ACTIVE=common,logging,local,logging mvn spring-boot:build-image-Dmaven.test.skip=true-Pxcmg,native4、方法不允许反射的问题
Caused by: org.graalvm.nativeimage.MissingReflectionRegistrationError: Cannot reflectively invoke method 'public void com.zaxxer.hikari.HikariConfig.setDriverClassName(java.lang.String)'. To allow this operation, add the following to the 'reflection' section of 'reachability-metadata.json' and rebuild the native image: { "type": "com.zaxxer.hikari.HikariConfig", "methods": [ { "name": "setDriverClassName", "parameterTypes": [ "java.lang.String" ] } ] } The 'reachability-metadata.json' file should be located in 'META-INF/native-image/<group-id>/<artifact-id>/' of your project. For further help, see https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection at org.graalvm.nativeimage.builder/com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils.reportInvokedExecutable(MissingReflectionRegistrationUtils.java:110)解决方法:
添加一个文件,META-INF/native-image///reachability-metadata.json
内容如下:
{ "reflection": [ { "type": "com.zaxxer.hikari.HikariConfig", "allDeclaredConstructors": true, "allDeclaredMethods": true, "allPublicConstructors": true, "allPublicMethods": true, "fields": [ { "name": "driverClassName", "allowWrite": true }, { "name": "jdbcUrl", "allowWrite": true }, { "name": "username", "allowWrite": true }, { "name": "password", "allowWrite": true }, { "name": "maximumPoolSize", "allowWrite": true }, { "name": "minimumIdle", "allowWrite": true }, { "name": "idleTimeout", "allowWrite": true }, { "name": "connectionTimeout", "allowWrite": true }, { "name": "validationTimeout", "allowWrite": true }, { "name": "maxLifetime", "allowWrite": true }, { "name": "poolName", "allowWrite": true } ] }, { "type": "com.zaxxer.hikari.HikariDataSource", "allDeclaredConstructors": true, "allDeclaredMethods": true, "allPublicConstructors": true, "allPublicMethods": true }, { "type": "org.postgresql.Driver", "allDeclaredConstructors": true, "allDeclaredMethods": true }, { "type": "org.postgresql.jdbc.PgDriver", "allDeclaredConstructors": true, "allDeclaredMethods": true } ] }我的完整路径:src/main/resources/META-INF/native-image/com.xcmg.finance.tmp/tmp-base-service/tmp-base-service/reachability-metadata.json
5、类在heap中找不到
日志如下:
[INFO] [creator] Fatal error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: An object of type 'org.apache.logging.slf4j.SLF4JServiceProvider' was found in the image heap. This type, however, is marked for initialization at image run time for the following reason: classes are initialized at run time by default. [INFO] [creator] This is not allowed for correctness reasons: All objects that are stored in the image heap must be initialized at build time. [INFO] [creator] [INFO] [creator] You now have two options to resolve this: [INFO] [creator] [INFO] [creator] 1) If it is intended that objects of type 'org.apache.logging.slf4j.SLF4JServiceProvider' are persisted in the image heap, add [INFO] [creator] [INFO] [creator] '--initialize-at-build-time=org.apache.logging.slf4j.SLF4JServiceProvider' [INFO] [creator] [INFO] [creator] to the native-image arguments. Note that initializing new types can store additional objects to the heap. It is advised to check the static fields of 'org.apache.logging.slf4j.SLF4JServiceProvider' to see if they are safe for build-time initialization, and that they do not contain any sensitive data that should not become part of the image. [INFO] [creator] [INFO] [creator] 2) If these objects should not be stored in the image heap, you can use [INFO] [creator] [INFO] [creator] '--trace-object-instantiation=org.apache.logging.slf4j.SLF4JServiceProvider' [INFO] [creator]解决方法:
在spring-boot-maven plugin中添加参数,把相应的包名加进去。
如:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> <configuration> <image> <!-- 自定义应用镜像名称(可选) --> <name>10.16.10.28:8085/tmp/${project.artifactId}:${project.version}</name> <env> <BP_DEPENDENCY_MIRROR>https://irmp.xcmglease.com:9443/download</BP_DEPENDENCY_MIRROR> <BP_NATIVE_IMAGE_BUILD_ARGUMENTS>--initialize-at-build-time=org.springframework.boot.logging.log4j,org.slf4j,org.apache.logging.slf4j,org.apache.logging.log4j,io.netty.util.internal.logging --initialize-at-run-time=io.lettuce.core.resource.KqueueProvider,io.netty.util.internal.SystemPropertyUtil,com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration</BP_NATIVE_IMAGE_BUILD_ARGUMENTS> <JAVA_TOOL_OPTIONS>-Dfile.encoding=UTF-8 -Duser.timezone=Asia/Shanghai -XX:MaxRAMPercentage=75.0 -XX:InitialRAMPercentage=50.0 -XX:MaxMetaspaceSize=512m -XX:+UseStringDeduplication -XX:+ExitOnOutOfMemoryError -Dspring.aot.enabled=true -XX:+PrintCommandLineFlags</JAVA_TOOL_OPTIONS> </env> </image> </configuration> </plugin>本类错误会很多,出现一个加一个包名进去再试就好了。