ApplicationContextAotGenerator uses a GenerationContext to analyze an ApplicationContext. The generation context provides the necessary infrastructure to generate "files" (i.e. source code and resources). It's part of spring-core.

As part of this analysis, an ApplicationContextInitializer is generated and serves as the entry point for running an optimized version of the specified ApplicationContext at runtime. Additional files may be generated and needs extra help in terms of naming conventions.

The current API has a ClassName for the ApplicationContextInitializer as well as a target Class and a name for naming conventions purposes. I think that, at the very least, we should gather these in some sort of naming conventions strategy. Because we need to get a reference to the initializer classname, we could return something rather than void.

There is the use case that ApplicationContextGenerator is called for dedicated contexts (such as the management context in Spring Boot). In this case we want to pass along the GenerationContext so that it records all resources/files in a single place and an updated naming strategy.

Comment From: snicoll

Another example is the getAotProcessor on AotProcessor that's used by the management context stuff in Spring Boot to only get the target application.

Comment From: snicoll

We've discussed passing the target/name pair as constructor arguments of ApplicationContextGenerator. I don't think that works as we'd still need to get those values somehow and that would leave what we have in AotProcessor.

https://github.com/snicoll/spring-framework/commit/88428edb3dd47891adc962d1efbfd44b223f6b98 is an attempt at making the naming strategy a separate, third argument. In short BeanFactoryNamingConvention hides the target/name pair and offer a way to generate class names for the bean factory at hand. The default implementation delegates to ClassNameGenerator (although the contract does not specify it strictly, which is a problem as it is a stateful thing).

Experimenting with this reveals several interesting things:

  • Tests don't really care what the name of the entry point is as they rely on the fact that the first thing (initializer) that registers a class is the entry point.
  • Returning the initializer class name rather than passing it works really well (and the implementation is in control over the name like all the other ones)
  • That Class<?> target and String name can be abstracted behind a strategy interface except for one use case. The naming strategy returning the bean factory name is a little odd as a result.

This works relatively nicely up to a point where we need to process another context as part of processing the context of the application. When this happens, the only reliable callback we have is GenerationContext. We don't have the third argument anymore (the naming convention) so we're stuffed.

GenerationContext already has ClassNameGenerator. We could update GeneratingContext to provide a higher level class that encapsulates this + the naming convention for the bean factory. If we do that, we need to be able to change the naming convention when processing a child context, and yet keeping the current created objects so that clashes are identified properly.

Spring Native had a fork option on the context where the naming convention can be changed. I never really liked the name but everything seems to point in the direction of some sort of feature like that.

Comment From: snicoll

I also believe that tightening this will help us remove the AOT package name (__) altogether. #28585 is related.

Comment From: snicoll

Another thing to note is that the "name" uniqueness is not enforced upfront. If you try to generate multiple contexts with the name Test, you'd end up with __TestBeanDefinitions and TestBeanDefinitions1 rather than __TestBeanDefinitions and Test1BeanDefinitions .

This goes in the direction again of the context being in charge of the registered names and their uniqueness. Unfortunately GenerationContext is in spring-core and does not know anything about the bean factory.

Comment From: snicoll

Yet another thing. If we process multiple contexts against the same bean, and that bean requires autowiring, then we invoke multiple times AutowiredAnnotationBeanPostProcessor which leads to the same file being created multiple times with the same name.

The original design had the idea of registering that a processor already ran. Right now, it's not obvious to me what is "static" and what is bean factory specific (and therefore should be qualified).