spring-projects / spring-framework

Spring Framework
https://spring.io/projects/spring-framework
Apache License 2.0
56.25k stars 37.98k forks source link

Support bean override features with AOT #32933

Open sbrannen opened 3 months ago

sbrannen commented 3 months ago

Overview

Although @MockitoBean and @MockitoSpyBean will not work out-of-the-box within a GraalVM native image due to their dependency on Mockito, the general Bean Override support for tests should ideally work within a native image.

In light of that, we need to ensure that basic usage of @TestBean is supported within a native image, and (if applicable) we will need to document known use cases that are not supported for some reason.

To achieve that, we need to introduce a smoke test application that makes use of @TestBean and verify the expected behavior when the associated tests are run within a native image against Spring Framework 6.2 snapshots or milestones.

We also have to ensure that the necessary runtime hints are registered for the bean override support. For example, we will need tests which verify that reflection hints are registered for the BeanOverrideContextCustomizerFactory, etc.

As a bare minimum, TestContextAotGeneratorIntegrationTests.endToEndTests() must be modified to include test classes that utilize the basic features of @TestBean.

Related Issues

snicoll commented 3 months ago

I've requalified this issue to investigate how much of these features can be supported by AOT on the JVM and in a native image.

sbrannen commented 4 days ago

In order to get the ball rolling, I started experimenting with AOT/native support for test bean overrides.

Current experimental work on this issue can be viewed in the following feature branch.

There are several issues we will need to address, including, but not limited to, the following.

As a side note, we should keep in mind that a ContextCustomizer currently cannot be made "AOT aware", since that can potentially affect how we implement the feature regarding our use of bean definitions and manually registered singletons.

In the first commit on the aforementioned feature branch (https://github.com/sbrannen/spring-framework/commit/b8f69ebe40f5fd8cf01e3f3cdf4dcbf2e8eeacbe), I switched to registering bean override infrastructure beans as singletons instead of via bean definitions with the infrastructure role. I'm not suggesting that's necessarily what we want to do in the end, but doing so allows our @TestBean and @DummyBean tests to work in AOT mode.

In the second commit in that feature branch (https://github.com/sbrannen/spring-framework/commit/102ec94a7e29a757510913163ed22e6e2763b185), I introduced a different approach to creating bean override instances which allows a concrete OverrideMetadata implementation to update the override BeanDefinition so that it is suitable for use in AOT -- for example, by registering a static factory method that is responsible for creating the bean instance. I verified this approach works for @TestBean and @DummyBean; however, getting this approach to work for @⁠MockitoBean or @⁠MockitoSpyBean will be significantly more involved.

In any case, we at least now have some topics that we can discuss.

sbrannen commented 3 days ago

In a third commit on my feature branch (https://github.com/sbrannen/spring-framework/commit/fb1caf5d8bee86dd1f44003e3991fa9010d51a35), I added support for registering GraalVM native image runtime hints for every BeanOverrideProcessor configured via @BeanOverride.

In addition, I have confirmed that the @TestBean feature works in AOT mode on the JVM as well as in a native image, using 6.2.0-SNAPSHOT builds from the feature branch and Spring Boot 3.4.0-M2.