added support for large number of bean registrations during AoT Compilation
This commit is contained in:
parent
e828bbbb0a
commit
4f2ae0a4df
|
@ -65,21 +65,53 @@ class BeanRegistrationsAotContribution
|
|||
|
||||
@Override
|
||||
public void applyTo(GenerationContext generationContext,
|
||||
BeanFactoryInitializationCode beanFactoryInitializationCode) {
|
||||
BeanFactoryInitializationCode beanFactoryInitializationCode) {
|
||||
|
||||
GeneratedClass generatedClass = generationContext.getGeneratedClasses()
|
||||
.addForFeature("BeanFactoryRegistrations", type -> {
|
||||
type.addJavadoc("Register bean definitions for the bean factory.");
|
||||
type.addModifiers(Modifier.PUBLIC);
|
||||
});
|
||||
BeanRegistrationsCodeGenerator codeGenerator = new BeanRegistrationsCodeGenerator(generatedClass);
|
||||
GeneratedMethod generatedBeanDefinitionsMethod = new BeanDefinitionsRegistrationGenerator(
|
||||
generationContext, codeGenerator, this.registrations).generateRegisterBeanDefinitionsMethod();
|
||||
beanFactoryInitializationCode.addInitializer(generatedBeanDefinitionsMethod.toMethodReference());
|
||||
GeneratedMethod generatedAliasesMethod = codeGenerator.getMethods().add("registerAliases",
|
||||
this::generateRegisterAliasesMethod);
|
||||
beanFactoryInitializationCode.addInitializer(generatedAliasesMethod.toMethodReference());
|
||||
generateRegisterHints(generationContext.getRuntimeHints(), this.registrations);
|
||||
int partitionSize = 5000;
|
||||
int total = registrations.size();
|
||||
int parts = (total + partitionSize - 1) / partitionSize;
|
||||
|
||||
for (int part = 0; part < parts; part++) {
|
||||
int start = part * partitionSize;
|
||||
int end = Math.min(start + partitionSize, total);
|
||||
List<Registration> slice = registrations.subList(start, end);
|
||||
|
||||
final int partNumber = part;
|
||||
String feature = "BeanFactoryRegistrations" + (part > 0 ? (part + 1) : "1");
|
||||
GeneratedClass generatedClass = generationContext.getGeneratedClasses()
|
||||
.addForFeature(feature, type -> {
|
||||
type.addJavadoc("Register bean definitions (slice " + (partNumber + 1) + ").");
|
||||
type.addModifiers(Modifier.PUBLIC);
|
||||
});
|
||||
|
||||
BeanRegistrationsCodeGenerator codeGen = new BeanRegistrationsCodeGenerator(generatedClass);
|
||||
BeanDefinitionsRegistrationGenerator generator = new BeanDefinitionsRegistrationGenerator(
|
||||
generationContext, codeGen, slice);
|
||||
|
||||
GeneratedMethod generatedBeanDefinitionsMethod = generator.generateRegisterBeanDefinitionsMethod();
|
||||
MethodReference beanDefsRef = generatedBeanDefinitionsMethod.toMethodReference();
|
||||
beanFactoryInitializationCode.addInitializer(beanDefsRef);
|
||||
|
||||
|
||||
GeneratedMethod aliases = codeGen.getMethods()
|
||||
.add("registerAliases", method -> generateRegisterAliasesMethodForSlice(method, slice));
|
||||
beanFactoryInitializationCode.addInitializer(aliases.toMethodReference());
|
||||
generateRegisterHints(generationContext.getRuntimeHints(), slice);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateRegisterAliasesMethodForSlice(MethodSpec.Builder method, List<Registration> slice) {
|
||||
method.addJavadoc("Register the aliases.");
|
||||
method.addModifiers(Modifier.PUBLIC);
|
||||
method.addParameter(DefaultListableBeanFactory.class, BEAN_FACTORY_PARAMETER_NAME);
|
||||
CodeBlock.Builder code = CodeBlock.builder();
|
||||
slice.forEach(registration -> {
|
||||
for (String alias : registration.aliases()) {
|
||||
code.addStatement("$L.registerAlias($S, $S)", BEAN_FACTORY_PARAMETER_NAME,
|
||||
registration.beanName(), alias);
|
||||
}
|
||||
});
|
||||
method.addCode(code.build());
|
||||
}
|
||||
|
||||
private void generateRegisterAliasesMethod(MethodSpec.Builder method) {
|
||||
|
|
|
@ -246,6 +246,25 @@ class BeanRegistrationsAotContributionTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyToWithVeryLargeBeanDefinitionsCreatesSlices() {
|
||||
BeanRegistrationsAotContribution contribution = createContribution(30000, i -> "testBean" + i);
|
||||
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
|
||||
compileMultipleClasses((consumer, compiled) -> {
|
||||
assertThat(compiled.getSourceFile(".*BeanFactoryRegistrations"))
|
||||
.contains("Register the bean definitions from 0 to 999.",
|
||||
"// Registration is sliced to avoid exceeding size limit");
|
||||
DefaultListableBeanFactory freshBeanFactory = new DefaultListableBeanFactory();
|
||||
consumer.accept(freshBeanFactory);
|
||||
for (int i = 0; i <30000; i++) {
|
||||
String beanName = "testBean" + i;
|
||||
assertThat(freshBeanFactory.containsBeanDefinition(beanName)).isTrue();
|
||||
assertThat(freshBeanFactory.getBean(beanName)).isInstanceOf(TestBean.class);
|
||||
}
|
||||
assertThat(freshBeanFactory.getBeansOfType(TestBean.class)).hasSize(30000);
|
||||
});
|
||||
}
|
||||
|
||||
private BeanRegistrationsAotContribution createContribution(int size, Function<Integer, String> beanNameFactory) {
|
||||
List<Registration> registrations = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
@ -289,6 +308,31 @@ class BeanRegistrationsAotContributionTests {
|
|||
result.accept(compiled.getInstance(Consumer.class), compiled));
|
||||
}
|
||||
|
||||
private void compileMultipleClasses(BiConsumer<Consumer<DefaultListableBeanFactory>, Compiled> result) {
|
||||
MethodSpec.Builder acceptMethod = MethodSpec.methodBuilder("accept")
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addParameter(DefaultListableBeanFactory.class, "beanFactory");
|
||||
|
||||
ArgumentCodeGenerator beanFactory = ArgumentCodeGenerator.of(DefaultListableBeanFactory.class, "beanFactory");
|
||||
ClassName className = this.beanFactoryInitializationCode.getClassName();
|
||||
|
||||
for (MethodReference initializer : this.beanFactoryInitializationCode.getInitializers()) {
|
||||
CodeBlock codeBlock = initializer.toInvokeCodeBlock(beanFactory, className);
|
||||
acceptMethod.addStatement(codeBlock);
|
||||
}
|
||||
|
||||
this.beanFactoryInitializationCode.getTypeBuilder().set(type -> {
|
||||
type.addModifiers(Modifier.PUBLIC);
|
||||
type.addSuperinterface(ParameterizedTypeName.get(Consumer.class, DefaultListableBeanFactory.class));
|
||||
type.addMethod(acceptMethod.build());
|
||||
});
|
||||
|
||||
this.generationContext.writeGeneratedContent();
|
||||
|
||||
TestCompiler.forSystem().with(this.generationContext).compile(compiled ->
|
||||
result.accept(compiled.getInstance(Consumer.class), compiled));
|
||||
}
|
||||
|
||||
private BeanRegistrationsAotContribution createContribution(RegisteredBean registeredBean,
|
||||
BeanDefinitionMethodGenerator methodGenerator,String... aliases) {
|
||||
return new BeanRegistrationsAotContribution(
|
||||
|
|
Loading…
Reference in New Issue