17
17
package org .springframework .beans .factory .aot ;
18
18
19
19
import java .util .List ;
20
+ import java .util .function .BiConsumer ;
20
21
21
22
import javax .lang .model .element .Modifier ;
22
23
@@ -52,6 +53,10 @@ class BeanRegistrationsAotContribution
52
53
53
54
private static final String BEAN_FACTORY_PARAMETER_NAME = "beanFactory" ;
54
55
56
+ private static final int MAX_REGISTRATIONS_PER_FILE = 5000 ;
57
+
58
+ private static final int MAX_REGISTRATIONS_PER_METHOD = 1000 ;
59
+
55
60
private static final ArgumentCodeGenerator argumentCodeGenerator = ArgumentCodeGenerator
56
61
.of (DefaultListableBeanFactory .class , BEAN_FACTORY_PARAMETER_NAME );
57
62
@@ -67,21 +72,59 @@ class BeanRegistrationsAotContribution
67
72
public void applyTo (GenerationContext generationContext ,
68
73
BeanFactoryInitializationCode beanFactoryInitializationCode ) {
69
74
70
- GeneratedClass generatedClass = generationContext .getGeneratedClasses ()
71
- .addForFeature ("BeanFactoryRegistrations" , type -> {
72
- type .addJavadoc ("Register bean definitions for the bean factory." );
73
- type .addModifiers (Modifier .PUBLIC );
74
- });
75
+ GeneratedClass generatedClass = createBeanFactoryRegistrationClass (generationContext );
75
76
BeanRegistrationsCodeGenerator codeGenerator = new BeanRegistrationsCodeGenerator (generatedClass );
76
- GeneratedMethod generatedBeanDefinitionsMethod = new BeanDefinitionsRegistrationGenerator (
77
- generationContext , codeGenerator , this . registrations ). generateRegisterBeanDefinitionsMethod ( );
77
+ GeneratedMethod generatedBeanDefinitionsMethod = generateBeanRegistrationCode ( generationContext ,
78
+ generatedClass , codeGenerator );
78
79
beanFactoryInitializationCode .addInitializer (generatedBeanDefinitionsMethod .toMethodReference ());
79
80
GeneratedMethod generatedAliasesMethod = codeGenerator .getMethods ().add ("registerAliases" ,
80
81
this ::generateRegisterAliasesMethod );
81
82
beanFactoryInitializationCode .addInitializer (generatedAliasesMethod .toMethodReference ());
82
83
generateRegisterHints (generationContext .getRuntimeHints (), this .registrations );
83
84
}
84
85
86
+ private GeneratedMethod generateBeanRegistrationCode (GenerationContext generationContext , GeneratedClass mainGeneratedClass , BeanRegistrationsCodeGenerator mainCodeGenerator ) {
87
+ if (this .registrations .size () < MAX_REGISTRATIONS_PER_FILE ) {
88
+ return generateBeanRegistrationClass (generationContext , mainCodeGenerator , 0 , this .registrations .size ());
89
+ }
90
+ else {
91
+ return mainGeneratedClass .getMethods ().add ("registerBeanDefinitions" , method -> {
92
+ method .addJavadoc ("Register the bean definitions." );
93
+ method .addModifiers (Modifier .PUBLIC );
94
+ method .addParameter (DefaultListableBeanFactory .class , BEAN_FACTORY_PARAMETER_NAME );
95
+ CodeBlock .Builder body = CodeBlock .builder ();
96
+ Registration .doWithSlice (this .registrations , MAX_REGISTRATIONS_PER_FILE , (start , end ) -> {
97
+ GeneratedClass sliceGeneratedClass = createBeanFactoryRegistrationClass (generationContext );
98
+ BeanRegistrationsCodeGenerator sliceCodeGenerator = new BeanRegistrationsCodeGenerator (sliceGeneratedClass );
99
+ GeneratedMethod generatedMethod = generateBeanRegistrationClass (generationContext , sliceCodeGenerator , start , end );
100
+ body .addStatement (generatedMethod .toMethodReference ().toInvokeCodeBlock (argumentCodeGenerator ));
101
+ });
102
+ method .addCode (body .build ());
103
+ });
104
+ }
105
+ }
106
+
107
+ private GeneratedMethod generateBeanRegistrationClass (GenerationContext generationContext ,
108
+ BeanRegistrationsCodeGenerator codeGenerator , int start , int end ) {
109
+
110
+ return codeGenerator .getMethods ().add ("registerBeanDefinitions" , method -> {
111
+ method .addJavadoc ("Register the bean definitions." );
112
+ method .addModifiers (Modifier .PUBLIC );
113
+ method .addParameter (DefaultListableBeanFactory .class , BEAN_FACTORY_PARAMETER_NAME );
114
+ List <Registration > sliceRegistrations = this .registrations .subList (start , end );
115
+ new BeanDefinitionsRegistrationGenerator (
116
+ generationContext , codeGenerator , sliceRegistrations , start ).generateBeanRegistrationsCode (method );
117
+ });
118
+ }
119
+
120
+ private static GeneratedClass createBeanFactoryRegistrationClass (GenerationContext generationContext ) {
121
+ return generationContext .getGeneratedClasses ()
122
+ .addForFeature ("BeanFactoryRegistrations" , type -> {
123
+ type .addJavadoc ("Register bean definitions for the bean factory." );
124
+ type .addModifiers (Modifier .PUBLIC );
125
+ });
126
+ }
127
+
85
128
private void generateRegisterAliasesMethod (MethodSpec .Builder method ) {
86
129
method .addJavadoc ("Register the aliases." );
87
130
method .addModifiers (Modifier .PUBLIC );
@@ -117,6 +160,28 @@ String beanName() {
117
160
return this .registeredBean .getBeanName ();
118
161
}
119
162
163
+ /**
164
+ * Invoke an action for each slice of the given {@code registrations}. The
165
+ * {@code action} is invoked for each slice with the start and end index of the
166
+ * given list of registrations. Elements to process can be retrieved using
167
+ * {@link List#subList(int, int)}.
168
+ * @param registrations the registrations to process
169
+ * @param sliceSize the size of a slice
170
+ * @param action the action to invoke for each slice
171
+ */
172
+ static void doWithSlice (List <Registration > registrations , int sliceSize ,
173
+ BiConsumer <Integer , Integer > action ) {
174
+
175
+ int index = 0 ;
176
+ int end = 0 ;
177
+ while (end < registrations .size ()) {
178
+ int start = index * sliceSize ;
179
+ end = Math .min (start + sliceSize , registrations .size ());
180
+ action .accept (start , end );
181
+ index ++;
182
+ }
183
+ }
184
+
120
185
}
121
186
122
187
@@ -144,6 +209,10 @@ public GeneratedMethods getMethods() {
144
209
145
210
}
146
211
212
+ /**
213
+ * Generate code for bean registrations. Limited to {@value #MAX_REGISTRATIONS_PER_METHOD}
214
+ * beans per method to avoid hitting a limit.
215
+ */
147
216
static final class BeanDefinitionsRegistrationGenerator {
148
217
149
218
private final GenerationContext generationContext ;
@@ -152,44 +221,38 @@ static final class BeanDefinitionsRegistrationGenerator {
152
221
153
222
private final List <Registration > registrations ;
154
223
224
+ private final int globalStart ;
225
+
155
226
156
227
BeanDefinitionsRegistrationGenerator (GenerationContext generationContext ,
157
- BeanRegistrationsCodeGenerator codeGenerator , List <Registration > registrations ) {
228
+ BeanRegistrationsCodeGenerator codeGenerator , List <Registration > registrations , int globalStart ) {
158
229
159
230
this .generationContext = generationContext ;
160
231
this .codeGenerator = codeGenerator ;
161
232
this .registrations = registrations ;
233
+ this .globalStart = globalStart ;
162
234
}
163
235
164
-
165
- GeneratedMethod generateRegisterBeanDefinitionsMethod () {
166
- return this .codeGenerator .getMethods ().add ("registerBeanDefinitions" , method -> {
167
- method .addJavadoc ("Register the bean definitions." );
168
- method .addModifiers (Modifier .PUBLIC );
169
- method .addParameter (DefaultListableBeanFactory .class , BEAN_FACTORY_PARAMETER_NAME );
170
- if (this .registrations .size () <= 1000 ) {
171
- generateRegisterBeanDefinitionMethods (method , this .registrations );
172
- }
173
- else {
174
- Builder code = CodeBlock .builder ();
175
- code .add ("// Registration is sliced to avoid exceeding size limit\n " );
176
- int index = 0 ;
177
- int end = 0 ;
178
- while (end < this .registrations .size ()) {
179
- int start = index * 1000 ;
180
- end = Math .min (start + 1000 , this .registrations .size ());
181
- GeneratedMethod sliceMethod = generateSliceMethod (start , end );
182
- code .addStatement (sliceMethod .toMethodReference ().toInvokeCodeBlock (
183
- argumentCodeGenerator , this .codeGenerator .getClassName ()));
184
- index ++;
185
- }
186
- method .addCode (code .build ());
187
- }
188
- });
236
+ void generateBeanRegistrationsCode (MethodSpec .Builder method ) {
237
+ if (this .registrations .size () <= 1000 ) {
238
+ generateRegisterBeanDefinitionMethods (method , this .registrations );
239
+ }
240
+ else {
241
+ Builder code = CodeBlock .builder ();
242
+ code .add ("// Registration is sliced to avoid exceeding size limit\n " );
243
+ Registration .doWithSlice (this .registrations , MAX_REGISTRATIONS_PER_METHOD ,
244
+ (start , end ) -> {
245
+ GeneratedMethod sliceMethod = generateSliceMethod (start , end );
246
+ code .addStatement (sliceMethod .toMethodReference ().toInvokeCodeBlock (
247
+ argumentCodeGenerator , this .codeGenerator .getClassName ()));
248
+ });
249
+ method .addCode (code .build ());
250
+ }
189
251
}
190
252
191
253
private GeneratedMethod generateSliceMethod (int start , int end ) {
192
- String description = "Register the bean definitions from %s to %s." .formatted (start , end - 1 );
254
+ String description = "Register the bean definitions from %s to %s."
255
+ .formatted (this .globalStart + start , this .globalStart + end - 1 );
193
256
List <Registration > slice = this .registrations .subList (start , end );
194
257
return this .codeGenerator .getMethods ().add ("registerBeanDefinitions" , method -> {
195
258
method .addJavadoc (description );
0 commit comments