Micronaut 和 Java 邮件 API

Geo*_*kas 5 java email docker graalvm micronaut

我们正在尝试将部分单体应用迁移到微服务,我们决定使用 micronaut。我们现在正在提取一个电子邮件服务,该服务提供一些输入将呈现电子邮件并与 SMTP 服务器通信以发送它们。

为此,我们使用 Java Mail,当我们尝试创建 GraalVM docker 映像时,它似乎存在一些问题。有没有人设法做到这一点,或者根本不可能让它发挥作用?

一些附加信息:

Dockerfile:

FROM oracle/graalvm-ce:19.2.0 as graalvm
COPY . /home/app/email-service
WORKDIR /home/app/email-service
RUN gu install native-image
RUN native-image --no-server -cp build/libs/email-service-*.jar

FROM frolvlad/alpine-glibc
EXPOSE 8080
COPY --from=graalvm /home/app/email-service .
ENTRYPOINT ["./email-service"]
Run Code Online (Sandbox Code Playgroud)

本机-image.properties:

JDBC 驱动程序、redis、kafka 和 thymeleaf 还进行了其他一些“惰性”初始化。

Args = --initialize-at-run-time=io.micronaut.views.thymeleaf.ThymeleafFactory \
       --initialize-at-run-time=io.micronaut.views.thymeleaf.ThymeleafViewsRenderer \
       --initialize-at-run-time=io.micronaut.views.velocity.VelocityViewsRenderer \
       --initialize-at-run-time=io.micronaut.configuration.lettuce.session.$RedisHttpSessionConfigurationDefinition \
       --initialize-at-run-time=io.micronaut.configuration.kafka.embedded.KafkaEmbedded \
       --initialize-at-run-time=oracle.jdbc.driver.OracleDriver \
       --initialize-at-run-time=java.sql.DriverManager \
       --initialize-at-run-time=org.hibernate.jpa.HibernatePersistenceProvider \
       --initialize-at-run-time=com.sun.mail.util.MailLogger \
       -H:IncludeResources=logback.xml|application.yml \
       -H:Name=email-service \
       -H:Class=com.acme.MySuperDuperApplication
Run Code Online (Sandbox Code Playgroud)

Micronaut 版本: 1.2.0
Java 邮件版本: 1.6.2 ( com.sun.mail:javax.mail:1.6.2)

本机图像编译错误:

Warning: Aborting stand-alone image build. com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of com.sun.mail.util.MailLogger are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use -H:+TraceClassInitialization.
Detailed message:
Trace: 
    at parsing javax.mail.internet.MailDateFormat.access$000(MailDateFormat.java:149)
Call path from entry point to javax.mail.internet.MailDateFormat.access$000(): 
    at javax.mail.internet.MailDateFormat.access$000(MailDateFormat.java:149)
    at javax.mail.internet.MailDateFormat$AbstractDateParser.parse(MailDateFormat.java:426)
    at javax.mail.internet.MailDateFormat.parse(MailDateFormat.java:251)
    at java.text.DateFormat.parse(DateFormat.java:364)
    at freemarker.core.JavaTemplateDateFormat.parse(JavaTemplateDateFormat.java:49)
    at freemarker.core.JavaTemplateDateFormat.parse(JavaTemplateDateFormat.java:33)
    at freemarker.core.BuiltInsForMultipleTypes$dateBI$DateParser.parse(BuiltInsForMultipleTypes.java:204)
    at freemarker.core.BuiltInsForMultipleTypes$dateBI$DateParser.get(BuiltInsForMultipleTypes.java:167)
    at freemarker.ext.beans.HashAdapter.get(HashAdapter.java:73)
    at freemarker.ext.beans.HashAdapter$1$1$1.getValue(HashAdapter.java:124)
    at sun.security.ssl.SSLSocketImpl$NotifyHandshakeThread.run(SSLSocketImpl.java:2687)
    at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
    at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
    at com.oracle.svm.core.code.IsolateEnterStub.PosixJavaThreads_pthreadStartRoutine_e1f4a8c0039f8337338252cd8734f63a79b5e3df(generated:0)
Run Code Online (Sandbox Code Playgroud)

Geo*_*kas 0

在尝试了一些不同的方法之后,我发布了最终对我们有用的方法,以便其他人可以得到帮助。

首先,我们升级到了 micronaut 的最新版本(2.3.4目前),并且我们也使用了com.sun.mail:jakarta.mail2.0.0目前)的最新版本。其次,我们的 nativeImage 参数如下(省略了一些其他依赖项):

--report-unsupported-elements-at-runtime
-H:+ReportExceptionStackTraces
-H:-DeleteLocalSymbols
-H:+PreserveFramePointer
-H:IncludeResources=META-INF/mailcap
-H:IncludeResources=META-INF/mailcap.default
-H:IncludeResources=META-INF/javamail.default.address.map
-H:IncludeResources=META-INF/javamail.charset.map
-H:IncludeResources=META-INF/javamail.default.providers
-H:IncludeResources=META-INF/services/javax.mail.Provider
Run Code Online (Sandbox Code Playgroud)

然后我们必须使用以下方法标记一些用于自省的类@TypeHint

--report-unsupported-elements-at-runtime
-H:+ReportExceptionStackTraces
-H:-DeleteLocalSymbols
-H:+PreserveFramePointer
-H:IncludeResources=META-INF/mailcap
-H:IncludeResources=META-INF/mailcap.default
-H:IncludeResources=META-INF/javamail.default.address.map
-H:IncludeResources=META-INF/javamail.charset.map
-H:IncludeResources=META-INF/javamail.default.providers
-H:IncludeResources=META-INF/services/javax.mail.Provider
Run Code Online (Sandbox Code Playgroud)

最后,我们有一个 SMTP Sender bean,我们必须在其上配置 mailcap(因此资源包含可能不能很好地工作):

@TypeHit({
  SMTPTransport.class,
  MimeMultipart.class,
  MailcapCommandMap.class,
  text_html.class,
  multipart_mixed.class,
  handler_base.class,
  image_gif.class,
  image_jpeg.class,
  message_rfc822.class,
  text_xml.class,
  text_plain.class
})
Run Code Online (Sandbox Code Playgroud)

完成所有这些后,我们就能够创建一个可以毫无问题地发送电子邮件的本机映像。