Spring Native 可以正式使用了么?
一、前言
hello 大家好,我是如梦技术(春哥 L.cm
),大家可能在很多开源项目里看到过我的身影。今天我带领大家实战一下spring-native
。内容偏硬核,建议大家坐稳扶好(关注、收藏)。
对 Graalvm
和 Spring native
我们一直都有关注,并且已经发表过多篇公众号文章。对于 demo 级别的使用这里不做过多介绍,感兴趣的可以查看冷神(pig 冷冷)之前的文章 Spring Native 入门实战。
二、spring native
2.1 graalvm native image 配置生成
在spring native
项目(mica-native-test
)编译之后会生成下面的这些 graalvm native image 配置。
可以对动态代理、反射、资源文件和序列化进行配置。
2.2 spring native hints
spring native
开放了很多的hints
,用于对native image
不支持的动态代理、反射、资源文件等进行配置。主要的hints
如下图:
这些 hits 会将我们自定义的配置生成到proxy-config.json
、reflect-config.json
、resource-config.json
、serialization-config.json
中。
三、mica 的适配
本节文章拿mica
的部分组件作为示例,来介绍spring native hints
的使用。
3.1 mica-ip2region
mica-ip2region
中涉及到一个 ip 地址信息的ip2region.db
文件,所以我们需要自定义资源文件的配置。
首先给mica-ip2region
添加spring-native
依赖。
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>${spring-native.version}</version>
<scope>provided</scope>
</dependency>
然后在Ip2regionConfiguration
代码中添加NativeHint
注解配置ip2region.db
资源文件。
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(Ip2regionProperties.class)
@NativeHint(resources = @ResourceHint(patterns = "^ip2region/ip2region.db"))
public class Ip2regionConfiguration {
@Bean
public Ip2regionSearcher ip2regionSearcher(ResourceLoader resourceLoader,
Ip2regionProperties properties) {
return new Ip2regionSearcherImpl(resourceLoader, properties);
}
}
再次编译spring native
项目(mica-native-test
)我们可以看见ip2region.db
文件已经添加进resource-config.json
。
最后运行项目:
测试mica-ip2region
(完美):
3.2 mica-captcha
mica-captcha
主要是几个字体文件需要添加下面的配置,具体过程同上这里不做过多描述。
@NativeHint(resources = @ResourceHint(patterns = "^fonts/.*.ttf"))
注意:由于验证码涉及到字体和 awt 会涉及到下面2个问题。
以
docker
编译运行native image
会遇到字体问题需要安装字体:
yum install fontconfig -y && fc-cache --force
更多详见:https://github.com/oracle/graal/issues/817
java.lang.UnsatisfiedLinkError: no awt in java.library.path
异常目前graalvm 21.1.0
mac 上还是有问题。具体详见:https://github.com/oracle/graal/issues/2842
3.3 mica-caffeine
由于caffeine
中使用了不少的unsafe
,所以添加了 mica-caffeine 依赖之后,mica-native-test
能启动成功都折腾了我很长时间。各种报错,不过都有提示,我们可以按照提示添加Hints
,如下图:
在添加下面这么多Hints
之后终于可以启动成功了!!!
@NativeHint(types = {
@TypeHint(types = CaffeineAutoCacheManager.class, access = AccessBits.ALL),
@TypeHint(types = CaffeineCacheManager.class, access = AccessBits.ALL),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.UnsafeAccess",
fields = @FieldHint(name = "UNSAFE", allowUnsafeAccess = true),
access = AccessBits.PUBLIC_METHODS
),
@TypeHint(types = Thread.class, access = AccessBits.DECLARED_FIELDS),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.PS",
fields = {
@FieldHint(name = "key", allowUnsafeAccess = true),
@FieldHint(name = "value", allowUnsafeAccess = true)
},
access = AccessBits.DECLARED_CONSTRUCTORS
),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.PSA",
fields = @FieldHint(name = "accessTime", allowUnsafeAccess = true),
access = AccessBits.DECLARED_CONSTRUCTORS
),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.PSW",
fields = @FieldHint(name = "writeTime", allowUnsafeAccess = true),
access = AccessBits.DECLARED_CONSTRUCTORS
),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.StripedBuffer",
fields = {@FieldHint(name = "tableBusy", allowUnsafeAccess = true)},
access = AccessBits.ALL
),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.PSWMS", access = AccessBits.DECLARED_CONSTRUCTORS),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.SSA", access = AccessBits.ALL),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.SSLA", access = AccessBits.DECLARED_CONSTRUCTORS),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.SSLMSW", access = AccessBits.DECLARED_CONSTRUCTORS),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.SSMSW", access = AccessBits.DECLARED_CONSTRUCTORS),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.BoundedBuffer", access = AccessBits.ALL),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.BoundedBuffer$RingBuffer", access = AccessBits.ALL),
@TypeHint(typeNames = "com.github.benmanes.caffeine.cache.BLCHeader$DrainStatusRef",
fields = @FieldHint(name = "drainStatus", allowUnsafeAccess = true),
access = AccessBits.ALL
)
})
喜大普奔,可以了???真的吗???caffeine
cache 读取缓存又开始报异常了!!!
至此再也不想折腾了,周末的上午全在折腾这玩意了。
四、总结
spring-native
目前还是处于孵化阶段,如果是未使用第三方组件简单的项目大家可以试试,稍大型建议大家还是再等等。我们也会持续关注并输出相关文章。
啊,又是一个充实的周末!欢迎大家关注我们,我是春哥,咱们下次再见!