As suggested by @sdeleuze (https://twitter.com/sdeleuze/status/1604218318902431744):

It would be great if Spring Framework supported different sets of beans configuration in the native image variant of the application - either through profiles or other mechanism.

My use case is following:

I am making a command line application (https://just.maciejwalkowiak.com/) that supports multiple commands. Some of them run some logic and finish immediately, some a long running commands that listen to file system events and in the background also start Spring as a web application.

Currently for all commands the application must be started as there is no way to set custom Spring profiles or web application type to SERVLET or NONE dynamically with Spring AOT support.

While the selection of the profile or web application type happens in the runtime, the set of required bean configurations is known at the build time.

A simplified piece of code illustrating how it is solved for the regular JAR build:

@SpringBootApplication
public class SpringNativeProfilesApplication {

    public static void main(String[] args) {

        SpringApplication app = new SpringApplication(SpringNativeProfilesApplication.class);

        if (Arrays.asList(args).contains("serve")) {
            app.setWebApplicationType(WebApplicationType.SERVLET);
        } else {
            app.setWebApplicationType(WebApplicationType.NONE);
        }

        app.run(args);
    }
}

Then I run it with:

$ java -jar app.jar

Or:

$ java -jar app.jar serve

The latter will fail as the web related beans were not generated with Spring AOT.

If I configure Spring AOT Maven Plugin to set "serve" argument and generate bean configuration as web application type servlet, the command that runs it as WebApplicationType.NONE will fail with:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'resourceHandlerMapping': Instantiation of supplied bean failed
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1236) ~[spring-native-profiles:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[spring-native-profiles:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[spring-native-profiles:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[spring-native-profiles:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-native-profiles:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-native-profiles:6.0.2]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-native-profiles:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-native-profiles:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-native-profiles:6.0.2]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) ~[spring-native-profiles:6.0.2]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915) ~[spring-native-profiles:6.0.2]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[spring-native-profiles:6.0.2]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[spring-native-profiles:3.0.0]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) ~[spring-native-profiles:3.0.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-native-profiles:3.0.0]
        at com.example.springnativeprofiles.SpringNativeProfilesApplication.main(SpringNativeProfilesApplication.java:30) ~[spring-native-profiles:na]
Caused by: java.lang.IllegalStateException: No ServletContext set
        at org.springframework.util.Assert.state(Assert.java:76) ~[na:na]
        at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.resourceHandlerMapping(WebMvcConfigurationSupport.java:581) ~[spring-native-profiles:6.0.2]
        at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport__BeanDefinitions.lambda$getResourceHandlerMappingInstanceSupplier$7(WebMvcConfigurationSupport__BeanDefinitions.java:166) ~[na:na]
        at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:68) ~[spring-native-profiles:6.0.2]
        at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:54) ~[spring-native-profiles:6.0.2]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$get$2(BeanInstanceSupplier.java:208) ~[na:na]
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:59) ~[spring-native-profiles:6.0.2]
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:47) ~[spring-native-profiles:6.0.2]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.invokeBeanSupplier(BeanInstanceSupplier.java:220) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:208) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[spring-native-profiles:6.0.2]
        ... 15 common frames omitted

A repository with sample code:

https://github.com/maciej-scratches/spring-framework-gh-29715

Comment From: sdeleuze

Thanks a lot for having taken the time to create this issue. Sorry for the delay but I needed some quality time to think about this non trivial issue.

I think the use case you describe here is a bit special, since the web application type is a kind a special case evaluated super early and leading to the creation of different kind of application contexts.

I have described in https://github.com/sdeleuze/demo-profile-aot what can be currently changed at runtime and what currently can't. I fully understand this can be confusing, and I will likely refine the reference documentation on this topic.

I have tried to describe in an extensive way in #29844 my proposal which is to support profiles enabled at build time, and for the reasons explained in the issue, I am not sure we should support changing profiles that impact the beans of the application context.

My proposal is to continue the discussion on #29844 side where I provided a more canonical example of profile usage with AOT/Native, and explained the reasons behind the limitation of the AOT mode, and where I will refine the scope depending on the discussions. As a consequence, I will close this issue as duplicated. Thanks for your feedback on the native support.