Micronaut DI 不适用于 Maven 中内置的 Graal Native Image
Micronaut DI does not work with Graal Native Image built in Maven
我在 Micronaut 上有一个最小的应用程序,它看起来像这样:
@Introspected
public class BookRequestHandler extends MicronautRequestHandler<Book, BookSaved> {
@Inject
private BookService service;
@Override
public BookSaved execute(Book input) {
return service.process(input);
}
}
@Singleton
@Introspected
public class BookService {
public BookSaved process(Book input) {
BookSaved bookSaved = new BookSaved();
bookSaved.setName(input.getName());
bookSaved.setIsbn(UUID.randomUUID().toString());
return bookSaved;
}
}
- 运行时和 DTO 类。
我的项目使用 Micronaut 的插件在 Graal Native Image 上成功构建并 运行s - ./mvnm
但我正在尝试使用 native-image 直接通过 Docker 容器构建。图像正在发生!但是如果我尝试调用 lambda,我会收到一个错误,指出没有找到依赖注入字段:( 这个文件是从 Micronaut 的 Gradle 版本重制的:
# STEP 1: Packaging project .jar in Docker image 'builder'
FROM maven:3.6.3-jdk-8 as build
COPY . /home/application
WORKDIR /home/application
RUN mvn clean package
# STEP 2: Downloading Graal and C libraries in Docker image 'graalvm'
FROM amazonlinux:2018.03 as graal
ENV LANG en_US.UTF-8
ENV JDK_VERSION java8
ENV GRAAL_VERSION 21.0.0.2
ENV GRAAL_FILENAME graalvm-ce-${JDK_VERSION}-linux-amd64-${GRAAL_VERSION}.tar.gz
RUN yum install -y gcc gcc-c++ libc6-dev zlib1g-dev curl bash zlib zlib-devel zip
RUN curl -4 -L https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-${GRAAL_VERSION}/${GRAAL_FILENAME} -o /tmp/${GRAAL_FILENAME}
RUN tar -zxvf /tmp/${GRAAL_FILENAME} -C /tmp
RUN mv /tmp/graalvm-ce-${JDK_VERSION}-${GRAAL_VERSION} /usr/lib/graalvm
RUN rm -rf /tmp/*
CMD ["/usr/lib/graalvm/bin/native-image"]
# STEP 3: Building and zipping a Native Image with bootstrap file
FROM graal
COPY --from=build /home/application/ /home/application/
WORKDIR /home/application
RUN /usr/lib/graalvm/bin/gu install native-image
RUN /usr/lib/graalvm/bin/native-image --no-fallback --no-server -jar target/MicronautGraal-0.1.jar -H:Name=micronaut-graal -H:Class=com.example.BookLambdaRuntime
RUN chmod 777 bootstrap
RUN chmod 777 micronaut-graal
RUN zip -j micronaut-graal.zip bootstrap micronaut-graal
EXPOSE 8080
ENTRYPOINT ["/home/application/complete"]
错误本身:
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for field [service] of class: com.example.BookRequestHandler
Message: Error setting field value: No field 'service' found for type: com.example.BookRequestHandler
我确定问题不在代码中,因为它将 运行 并通过 ./mvnm 插件工作。我在应用程序构建中遗漏了什么吗?我通过插件生成的图像比直接通过 native-image 多了 500kb。
如果有任何帮助,我将不胜感激。谢谢!
这是一个 JVM 限制,我们不能在不使用反射的情况下注入私有字段。
您有 2 个选择:
- 将字段包设为私有而不是私有
- 将
@ReflectiveAccess
添加到该字段以生成必要的 graal 反射元数据
添加注释处理器路径 - graal 并在继承者中显式声明验证和注入后问题消失了:
<annotationProcessorPaths>
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-graal</artifactId>
<version>${micronaut.version}</version>
</path>
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-inject-java</artifactId>
<version>${micronaut.version}</version>
</path>
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-validation</artifactId>
<version>${micronaut.version}</version>
</path>
</annotationProcessorPaths>
使用时应考虑通过构造函数进行注入,这是GraalVM原生应用的推荐方式。
@Introspected
public class BookRequestHandler extends MicronautRequestHandler<Book, BookSaved> {
private final BookService service;
@Inject
public BookRequestHandler(BookService service) {
this.service = service;
}
@Override
public BookSaved execute(Book input) {
return service.process(input);
}
}
我在 Micronaut 上有一个最小的应用程序,它看起来像这样:
@Introspected
public class BookRequestHandler extends MicronautRequestHandler<Book, BookSaved> {
@Inject
private BookService service;
@Override
public BookSaved execute(Book input) {
return service.process(input);
}
}
@Singleton
@Introspected
public class BookService {
public BookSaved process(Book input) {
BookSaved bookSaved = new BookSaved();
bookSaved.setName(input.getName());
bookSaved.setIsbn(UUID.randomUUID().toString());
return bookSaved;
}
}
- 运行时和 DTO 类。
我的项目使用 Micronaut 的插件在 Graal Native Image 上成功构建并 运行s - ./mvnm
但我正在尝试使用 native-image 直接通过 Docker 容器构建。图像正在发生!但是如果我尝试调用 lambda,我会收到一个错误,指出没有找到依赖注入字段:( 这个文件是从 Micronaut 的 Gradle 版本重制的:
# STEP 1: Packaging project .jar in Docker image 'builder'
FROM maven:3.6.3-jdk-8 as build
COPY . /home/application
WORKDIR /home/application
RUN mvn clean package
# STEP 2: Downloading Graal and C libraries in Docker image 'graalvm'
FROM amazonlinux:2018.03 as graal
ENV LANG en_US.UTF-8
ENV JDK_VERSION java8
ENV GRAAL_VERSION 21.0.0.2
ENV GRAAL_FILENAME graalvm-ce-${JDK_VERSION}-linux-amd64-${GRAAL_VERSION}.tar.gz
RUN yum install -y gcc gcc-c++ libc6-dev zlib1g-dev curl bash zlib zlib-devel zip
RUN curl -4 -L https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-${GRAAL_VERSION}/${GRAAL_FILENAME} -o /tmp/${GRAAL_FILENAME}
RUN tar -zxvf /tmp/${GRAAL_FILENAME} -C /tmp
RUN mv /tmp/graalvm-ce-${JDK_VERSION}-${GRAAL_VERSION} /usr/lib/graalvm
RUN rm -rf /tmp/*
CMD ["/usr/lib/graalvm/bin/native-image"]
# STEP 3: Building and zipping a Native Image with bootstrap file
FROM graal
COPY --from=build /home/application/ /home/application/
WORKDIR /home/application
RUN /usr/lib/graalvm/bin/gu install native-image
RUN /usr/lib/graalvm/bin/native-image --no-fallback --no-server -jar target/MicronautGraal-0.1.jar -H:Name=micronaut-graal -H:Class=com.example.BookLambdaRuntime
RUN chmod 777 bootstrap
RUN chmod 777 micronaut-graal
RUN zip -j micronaut-graal.zip bootstrap micronaut-graal
EXPOSE 8080
ENTRYPOINT ["/home/application/complete"]
错误本身:
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for field [service] of class: com.example.BookRequestHandler
Message: Error setting field value: No field 'service' found for type: com.example.BookRequestHandler
我确定问题不在代码中,因为它将 运行 并通过 ./mvnm 插件工作。我在应用程序构建中遗漏了什么吗?我通过插件生成的图像比直接通过 native-image 多了 500kb。
如果有任何帮助,我将不胜感激。谢谢!
这是一个 JVM 限制,我们不能在不使用反射的情况下注入私有字段。
您有 2 个选择:
- 将字段包设为私有而不是私有
- 将
@ReflectiveAccess
添加到该字段以生成必要的 graal 反射元数据
添加注释处理器路径 - graal 并在继承者中显式声明验证和注入后问题消失了:
<annotationProcessorPaths>
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-graal</artifactId>
<version>${micronaut.version}</version>
</path>
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-inject-java</artifactId>
<version>${micronaut.version}</version>
</path>
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-validation</artifactId>
<version>${micronaut.version}</version>
</path>
</annotationProcessorPaths>
使用时应考虑通过构造函数进行注入,这是GraalVM原生应用的推荐方式。
@Introspected
public class BookRequestHandler extends MicronautRequestHandler<Book, BookSaved> {
private final BookService service;
@Inject
public BookRequestHandler(BookService service) {
this.service = service;
}
@Override
public BookSaved execute(Book input) {
return service.process(input);
}
}