一:DefaultBeanDefinitionDocumentReader 解析BeanDefinition
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.xml; /** * Default implementation of the {@link BeanDefinitionDocumentReader} interface that * reads bean definitions according to the "spring-beans" DTD and XSD format * (Spring's default XML bean definition format). * * <p>The structure, elements, and attribute names of the required XML document * are hard-coded in this class. (Of course a transform could be run if necessary * to produce this format). {@code <beans>} does not need to be the root * element of the XML document: this class will parse all bean definition elements * in the XML file, regardless of the actual root element. * * @author Rod Johnson * @author Juergen Hoeller * @author Rob Harrop * @author Erik Wiersma * @since 18.12.2003 */ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT; public static final String NESTED_BEANS_ELEMENT = "beans"; public static final String ALIAS_ELEMENT = "alias"; public static final String NAME_ATTRIBUTE = "name"; public static final String ALIAS_ATTRIBUTE = "alias"; public static final String IMPORT_ELEMENT = "import"; public static final String RESOURCE_ATTRIBUTE = "resource"; public static final String PROFILE_ATTRIBUTE = "profile"; protected final Log logger = LogFactory.getLog(getClass()); private XmlReaderContext readerContext; private BeanDefinitionParserDelegate delegate; /** * This implementation parses bean definitions according to the "spring-beans" XSD * (or DTD, historically). * <p>Opens a DOM Document; then initializes the default settings * specified at the {@code <beans/>} level; then parses the contained bean definitions. */ @Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); } /** * Return the descriptor for the XML resource that this parser works on. */ protected final XmlReaderContext getReaderContext() { return this.readerContext; } /** * Invoke the {@link org.springframework.beans.factory.parsing.SourceExtractor} to pull the * source metadata from the supplied {@link Element}. */ protected Object extractSource(Element ele) { return getReaderContext().extractSource(ele); } /** * Register each bean definition within the given root {@code <beans/>} element. */ protected void doRegisterBeanDefinitions(Element root) { // Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; } protected BeanDefinitionParserDelegate createDelegate( XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); delegate.initDefaults(root, parentDelegate); return delegate; } /** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document */ protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } } /** * Parse an "import" element and load the bean definitions * from the given resource into the bean factory. */ protected void importBeanDefinitionResource(Element ele) { String location = ele.getAttribute(RESOURCE_ATTRIBUTE); if (!StringUtils.hasText(location)) { getReaderContext().error("Resource location must not be empty", ele); return; } // Resolve system properties: e.g. "${user.dir}" location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); Set<Resource> actualResources = new LinkedHashSet<Resource>(4); // Discover whether the location is an absolute or relative URI boolean absoluteLocation = false; try { absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException ex) { // cannot convert to an URI, considering the location relative // unless it is the well-known Spring prefix "classpath*:" } // Absolute or relative? if (absoluteLocation) { try { int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]"); } } catch (BeanDefinitionStoreException ex) { getReaderContext().error( "Failed to import bean definitions from URL location [" + location + "]", ele, ex); } } else { // No URL -> considering resource location as relative to the current file. try { int importCount; Resource relativeResource = getReaderContext().getResource().createRelative(location); if (relativeResource.exists()) { importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } else { String baseLocation = getReaderContext().getResource().getURL().toString(); importCount = getReaderContext().getReader().loadBeanDefinitions( StringUtils.applyRelativePath(baseLocation, location), actualResources); } if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]"); } } catch (IOException ex) { getReaderContext().error("Failed to resolve current resource location", ele, ex); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, ex); } } Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]); getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); } /** * Process the given alias element, registering the alias with the registry. */ protected void processAliasRegistration(Element ele) { String name = ele.getAttribute(NAME_ATTRIBUTE); String alias = ele.getAttribute(ALIAS_ATTRIBUTE); boolean valid = true; if (!StringUtils.hasText(name)) { getReaderContext().error("Name must not be empty", ele); valid = false; } if (!StringUtils.hasText(alias)) { getReaderContext().error("Alias must not be empty", ele); valid = false; } if (valid) { try { getReaderContext().getRegistry().registerAlias(name, alias); } catch (Exception ex) { getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, ex); } getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); } } /** * Process the given bean element, parsing the bean definition * and registering it with the registry. */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } } /** * Allow the XML to be extensible by processing any custom element types first, * before we start to process the bean definitions. This method is a natural * extension point for any other custom pre-processing of the XML. * <p>The default implementation is empty. Subclasses can override this method to * convert custom elements into standard Spring bean definitions, for example. * Implementors have access to the parser's bean definition reader and the * underlying XML resource, through the corresponding accessors. * @see #getReaderContext() */ protected void preProcessXml(Element root) { } /** * Allow the XML to be extensible by processing any custom element types last, * after we finished processing the bean definitions. This method is a natural * extension point for any other custom post-processing of the XML. * <p>The default implementation is empty. Subclasses can override this method to * convert custom elements into standard Spring bean definitions, for example. * Implementors have access to the parser's bean definition reader and the * underlying XML resource, through the corresponding accessors. * @see #getReaderContext() */ protected void postProcessXml(Element root) { } }
二:BeanDefinitionParserDelegate 解析Element 获取BeanDefinitionHolder
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475/* * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.xml; /** * Stateful delegate class used to parse XML bean definitions. * Intended for use by both the main parser and any extension * {@link BeanDefinitionParser BeanDefinitionParsers} or * {@link BeanDefinitionDecorator BeanDefinitionDecorators}. * * @author Rob Harrop * @author Juergen Hoeller * @author Rod Johnson * @author Mark Fisher * @author Gary Russell * @since 2.0 * @see ParserContext * @see DefaultBeanDefinitionDocumentReader */ public class BeanDefinitionParserDelegate { public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans"; public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; "; /** * Value of a T/F attribute that represents true. * Anything else represents false. Case seNsItive. */ public static final String TRUE_VALUE = "true"; public static final String FALSE_VALUE = "false"; public static final String DEFAULT_VALUE = "default"; public static final String DESCRIPTION_ELEMENT = "description"; public static final String AUTOWIRE_NO_VALUE = "no"; public static final String AUTOWIRE_BY_NAME_VALUE = "byName"; public static final String AUTOWIRE_BY_TYPE_VALUE = "byType"; public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor"; public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect"; public static final String DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE = "all"; public static final String DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE = "simple"; public static final String DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE = "objects"; public static final String NAME_ATTRIBUTE = "name"; public static final String BEAN_ELEMENT = "bean"; public static final String META_ELEMENT = "meta"; public static final String ID_ATTRIBUTE = "id"; public static final String PARENT_ATTRIBUTE = "parent"; public static final String CLASS_ATTRIBUTE = "class"; public static final String ABSTRACT_ATTRIBUTE = "abstract"; public static final String SCOPE_ATTRIBUTE = "scope"; private static final String SINGLETON_ATTRIBUTE = "singleton"; public static final String LAZY_INIT_ATTRIBUTE = "lazy-init"; public static final String AUTOWIRE_ATTRIBUTE = "autowire"; public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate"; public static final String PRIMARY_ATTRIBUTE = "primary"; public static final String DEPENDENCY_CHECK_ATTRIBUTE = "dependency-check"; public static final String DEPENDS_ON_ATTRIBUTE = "depends-on"; public static final String INIT_METHOD_ATTRIBUTE = "init-method"; public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method"; public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method"; public static final String FACTORY_BEAN_ATTRIBUTE = "factory-bean"; public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg"; public static final String INDEX_ATTRIBUTE = "index"; public static final String TYPE_ATTRIBUTE = "type"; public static final String VALUE_TYPE_ATTRIBUTE = "value-type"; public static final String KEY_TYPE_ATTRIBUTE = "key-type"; public static final String PROPERTY_ELEMENT = "property"; public static final String REF_ATTRIBUTE = "ref"; public static final String VALUE_ATTRIBUTE = "value"; public static final String LOOKUP_METHOD_ELEMENT = "lookup-method"; public static final String REPLACED_METHOD_ELEMENT = "replaced-method"; public static final String REPLACER_ATTRIBUTE = "replacer"; public static final String ARG_TYPE_ELEMENT = "arg-type"; public static final String ARG_TYPE_MATCH_ATTRIBUTE = "match"; public static final String REF_ELEMENT = "ref"; public static final String IDREF_ELEMENT = "idref"; public static final String BEAN_REF_ATTRIBUTE = "bean"; public static final String LOCAL_REF_ATTRIBUTE = "local"; public static final String PARENT_REF_ATTRIBUTE = "parent"; public static final String VALUE_ELEMENT = "value"; public static final String NULL_ELEMENT = "null"; public static final String ARRAY_ELEMENT = "array"; public static final String LIST_ELEMENT = "list"; public static final String SET_ELEMENT = "set"; public static final String MAP_ELEMENT = "map"; public static final String ENTRY_ELEMENT = "entry"; public static final String KEY_ELEMENT = "key"; public static final String KEY_ATTRIBUTE = "key"; public static final String KEY_REF_ATTRIBUTE = "key-ref"; public static final String VALUE_REF_ATTRIBUTE = "value-ref"; public static final String PROPS_ELEMENT = "props"; public static final String PROP_ELEMENT = "prop"; public static final String MERGE_ATTRIBUTE = "merge"; public static final String QUALIFIER_ELEMENT = "qualifier"; public static final String QUALIFIER_ATTRIBUTE_ELEMENT = "attribute"; public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init"; public static final String DEFAULT_MERGE_ATTRIBUTE = "default-merge"; public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire"; public static final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check"; public static final String DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE = "default-autowire-candidates"; public static final String DEFAULT_INIT_METHOD_ATTRIBUTE = "default-init-method"; public static final String DEFAULT_DESTROY_METHOD_ATTRIBUTE = "default-destroy-method"; protected final Log logger = LogFactory.getLog(getClass()); private final XmlReaderContext readerContext; private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition(); private final ParseState parseState = new ParseState(); /** * Stores all used bean names so we can enforce uniqueness on a per * beans-element basis. Duplicate bean ids/names may not exist within the * same level of beans element nesting, but may be duplicated across levels. */ private final Set<String> usedNames = new HashSet<String>(); /** * Create a new BeanDefinitionParserDelegate associated with the supplied * {@link XmlReaderContext}. */ public BeanDefinitionParserDelegate(XmlReaderContext readerContext) { Assert.notNull(readerContext, "XmlReaderContext must not be null"); this.readerContext = readerContext; } /** * Get the {@link XmlReaderContext} associated with this helper instance. */ public final XmlReaderContext getReaderContext() { return this.readerContext; } /** * Get the {@link Environment} associated with this helper instance. * @deprecated in favor of {@link XmlReaderContext#getEnvironment()} */ @Deprecated public final Environment getEnvironment() { return this.readerContext.getEnvironment(); } /** * Invoke the {@link org.springframework.beans.factory.parsing.SourceExtractor} to pull the * source metadata from the supplied {@link Element}. */ protected Object extractSource(Element ele) { return this.readerContext.extractSource(ele); } /** * Report an error with the given message for the given source element. */ protected void error(String message, Node source) { this.readerContext.error(message, source, this.parseState.snapshot()); } /** * Report an error with the given message for the given source element. */ protected void error(String message, Element source) { this.readerContext.error(message, source, this.parseState.snapshot()); } /** * Report an error with the given message for the given source element. */ protected void error(String message, Element source, Throwable cause) { this.readerContext.error(message, source, this.parseState.snapshot(), cause); } /** * Initialize the default settings assuming a {@code null} parent delegate. */ public void initDefaults(Element root) { initDefaults(root, null); } /** * Initialize the default lazy-init, autowire, dependency check settings, * init-method, destroy-method and merge settings. Support nested 'beans' * element use cases by falling back to the given parent in case the * defaults are not explicitly set locally. * @see #populateDefaults(DocumentDefaultsDefinition, DocumentDefaultsDefinition, org.w3c.dom.Element) * @see #getDefaults() */ public void initDefaults(Element root, BeanDefinitionParserDelegate parent) { populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root); this.readerContext.fireDefaultsRegistered(this.defaults); } /** * Populate the given DocumentDefaultsDefinition instance with the default lazy-init, * autowire, dependency check settings, init-method, destroy-method and merge settings. * Support nested 'beans' element use cases by falling back to <literal>parentDefaults</literal> * in case the defaults are not explicitly set locally. * @param defaults the defaults to populate * @param parentDefaults the parent BeanDefinitionParserDelegate (if any) defaults to fall back to * @param root the root element of the current bean definition document (or nested beans element) */ protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) { String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { // Potentially inherited from outer <beans> sections, otherwise falling back to false. lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE); } defaults.setLazyInit(lazyInit); String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE); if (DEFAULT_VALUE.equals(merge)) { // Potentially inherited from outer <beans> sections, otherwise falling back to false. merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE); } defaults.setMerge(merge); String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE); if (DEFAULT_VALUE.equals(autowire)) { // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'. autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE); } defaults.setAutowire(autowire); // Don't fall back to parentDefaults for dependency-check as it's no longer supported in // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it. defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE)); if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) { defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates()); } if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) { defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setInitMethod(parentDefaults.getInitMethod()); } if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) { defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)); } else if (parentDefaults != null) { defaults.setDestroyMethod(parentDefaults.getDestroyMethod()); } defaults.setSource(this.readerContext.extractSource(root)); } /** * Return the defaults definition object, or {@code null} if the * defaults have been initialized yet. */ public DocumentDefaultsDefinition getDefaults() { return this.defaults; } /** * Return the default settings for bean definitions as indicated within * the attributes of the top-level {@code <beans/>} element. */ public BeanDefinitionDefaults getBeanDefinitionDefaults() { BeanDefinitionDefaults bdd = new BeanDefinitionDefaults(); bdd.setLazyInit("TRUE".equalsIgnoreCase(this.defaults.getLazyInit())); bdd.setDependencyCheck(this.getDependencyCheck(DEFAULT_VALUE)); bdd.setAutowireMode(this.getAutowireMode(DEFAULT_VALUE)); bdd.setInitMethodName(this.defaults.getInitMethod()); bdd.setDestroyMethodName(this.defaults.getDestroyMethod()); return bdd; } /** * Return any patterns provided in the 'default-autowire-candidates' * attribute of the top-level {@code <beans/>} element. */ public String[] getAutowireCandidatePatterns() { String candidatePattern = this.defaults.getAutowireCandidates(); return (candidatePattern != null ? StringUtils.commaDelimitedListToStringArray(candidatePattern) : null); } /** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } /** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; } /** * Validate that the specified bean name and aliases have not been used already * within the current level of beans element nesting. */ protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement) { String foundName = null; if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) { foundName = beanName; } if (foundName == null) { foundName = CollectionUtils.findFirstMatch(this.usedNames, aliases); } if (foundName != null) { error("Bean name '" + foundName + "' is already used in this <beans> element", beanElement); } this.usedNames.add(beanName); this.usedNames.addAll(aliases); } /** * Parse the bean definition itself, without regard to name or aliases. May return * {@code null} if problems occurred during the parsing of the bean definition. */ public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); }
//创建用于承载AbstractBeanDefinition类型的GenericBeanDefinition AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//硬编码解析默认bean的各种属性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析元数据 parseMetaElements(ele, bd);
//解析lookup-method属性 parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析replace-method属性 parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析构造函数参数 parseConstructorArgElements(ele, bd);
//解析property子元素 parsePropertyElements(ele, bd);
//解析qualifier子元素 parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; } /** * Apply the attributes of the given bean element to the given bean * definition. * @param ele bean declaration element * @param beanName bean name * @param containingBean containing bean definition * @return a bean definition initialized according to the bean element attributes */ public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) { if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); } else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); } else if (containingBean != null) { // Take default from containing bean in case of an inner bean definition. bd.setScope(containingBean.getScope()); } if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); } String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { lazyInit = this.defaults.getLazyInit(); } bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE); bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); } String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE); if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) { String candidatePattern = this.defaults.getAutowireCandidates(); if (candidatePattern != null) { String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } else { bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate)); } if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); } if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) { String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE); if (!"".equals(initMethodName)) { bd.setInitMethodName(initMethodName); } } else { if (this.defaults.getInitMethod() != null) { bd.setInitMethodName(this.defaults.getInitMethod()); bd.setEnforceInitMethod(false); } } if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) { String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE); bd.setDestroyMethodName(destroyMethodName); } else { if (this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } } if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); } if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); } return bd; } /** * Create a bean definition for the given class name and parent name. * @param className the name of the bean class * @param parentName the name of the bean's parent bean * @return the newly created bean definition * @throws ClassNotFoundException if bean class resolution was attempted but failed */ protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) throws ClassNotFoundException { return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader()); } public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) { NodeList nl = ele.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) { Element metaElement = (Element) node; String key = metaElement.getAttribute(KEY_ATTRIBUTE); String value = metaElement.getAttribute(VALUE_ATTRIBUTE); BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value); attribute.setSource(extractSource(metaElement)); attributeAccessor.addMetadataAttribute(attribute); } } } @SuppressWarnings("deprecation") public int getAutowireMode(String attValue) { String att = attValue; if (DEFAULT_VALUE.equals(att)) { att = this.defaults.getAutowire(); } int autowire = AbstractBeanDefinition.AUTOWIRE_NO; if (AUTOWIRE_BY_NAME_VALUE.equals(att)) { autowire = AbstractBeanDefinition.AUTOWIRE_BY_NAME; } else if (AUTOWIRE_BY_TYPE_VALUE.equals(att)) { autowire = AbstractBeanDefinition.AUTOWIRE_BY_TYPE; } else if (AUTOWIRE_CONSTRUCTOR_VALUE.equals(att)) { autowire = AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR; } else if (AUTOWIRE_AUTODETECT_VALUE.equals(att)) { autowire = AbstractBeanDefinition.AUTOWIRE_AUTODETECT; } // Else leave default value. return autowire; } public int getDependencyCheck(String attValue) { String att = attValue; if (DEFAULT_VALUE.equals(att)) { att = this.defaults.getDependencyCheck(); } if (DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE.equals(att)) { return AbstractBeanDefinition.DEPENDENCY_CHECK_ALL; } else if (DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE.equals(att)) { return AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS; } else if (DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE.equals(att)) { return AbstractBeanDefinition.DEPENDENCY_CHECK_SIMPLE; } else { return AbstractBeanDefinition.DEPENDENCY_CHECK_NONE; } } /** * Parse constructor-arg sub-elements of the given bean element. */ public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) { parseConstructorArgElement((Element) node, bd); } } } /** * Parse property sub-elements of the given bean element. */ public void parsePropertyElements(Element beanEle, BeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { parsePropertyElement((Element) node, bd); } } } /** * Parse qualifier sub-elements of the given bean element. */ public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) { parseQualifierElement((Element) node, bd); } } } /** * Parse lookup-override sub-elements of the given bean element. */ public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) { Element ele = (Element) node; String methodName = ele.getAttribute(NAME_ATTRIBUTE); String beanRef = ele.getAttribute(BEAN_ELEMENT); LookupOverride override = new LookupOverride(methodName, beanRef); override.setSource(extractSource(ele)); overrides.addOverride(override); } } } /** * Parse replaced-method sub-elements of the given bean element. */ public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) { Element replacedMethodEle = (Element) node; String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE); String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE); ReplaceOverride replaceOverride = new ReplaceOverride(name, callback); // Look for arg-type match elements. List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT); for (Element argTypeEle : argTypeEles) { String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE); match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle)); if (StringUtils.hasText(match)) { replaceOverride.addTypeIdentifier(match); } } replaceOverride.setSource(extractSource(replacedMethodEle)); overrides.addOverride(replaceOverride); } } } /** * Parse a constructor-arg element. */ public void parseConstructorArgElement(Element ele, BeanDefinition bd) { String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE); String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(indexAttr)) { try { int index = Integer.parseInt(indexAttr); if (index < 0) { error("'index' cannot be lower than 0", ele); } else { try { this.parseState.push(new ConstructorArgumentEntry(index)); Object value = parsePropertyValue(ele, bd, null); ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { error("Ambiguous constructor-arg entries for index " + index, ele); } else { bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder); } } finally { this.parseState.pop(); } } } catch (NumberFormatException ex) { error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele); } } else { try { this.parseState.push(new ConstructorArgumentEntry()); Object value = parsePropertyValue(ele, bd, null); ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); } finally { this.parseState.pop(); } } } /** * Parse a property element. */ public void parsePropertyElement(Element ele, BeanDefinition bd) { String propertyName = ele.getAttribute(NAME_ATTRIBUTE); if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName)); try { if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } Object val = parsePropertyValue(ele, bd, propertyName); PropertyValue pv = new PropertyValue(propertyName, val); parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } } /** * Parse a qualifier element. */ public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) { String typeName = ele.getAttribute(TYPE_ATTRIBUTE); if (!StringUtils.hasLength(typeName)) { error("Tag 'qualifier' must have a 'type' attribute", ele); return; } this.parseState.push(new QualifierEntry(typeName)); try { AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName); qualifier.setSource(extractSource(ele)); String value = ele.getAttribute(VALUE_ATTRIBUTE); if (StringUtils.hasLength(value)) { qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value); } NodeList nl = ele.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) { Element attributeEle = (Element) node; String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE); String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE); if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) { BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue); attribute.setSource(extractSource(attributeEle)); qualifier.addMetadataAttribute(attribute); } else { error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle); return; } } } bd.addQualifier(qualifier); } finally { this.parseState.pop(); } } /** * Get the value of a property element. May be a list etc. * Also used for constructor arguments, "propertyName" being null in this case. */ public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; // Should only have one child element: ref, value, list, etc. NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { // Child element is what we're looking for. if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } else if (hasValueAttribute) { TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) { return parsePropertySubElement(subElement, bd); } else { // Neither child element nor "ref" or "value" attribute found. error(elementName + " must specify a ref or value", ele); return null; } } public Object parsePropertySubElement(Element ele, BeanDefinition bd) { return parsePropertySubElement(ele, bd, null); } /** * Parse a value, ref or collection sub-element of a property or * constructor-arg element. * @param ele subelement of property element; we don't know which yet * @param defaultValueType the default type (class name) for any * {@code <value>} tag that might be created */ public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { if (!isDefaultNamespace(ele)) { return parseNestedCustomElement(ele, bd); } else if (nodeNameEquals(ele, BEAN_ELEMENT)) { BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } else if (nodeNameEquals(ele, REF_ELEMENT)) { // A generic reference to any name of any bean. String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false; if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in the same XML file. refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in a parent context. refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); toParent = true; if (!StringUtils.hasLength(refName)) { error("'bean', 'local' or 'parent' is required for <ref> element", ele); return null; } } } if (!StringUtils.hasText(refName)) { error("<ref> element contains empty target attribute", ele); return null; } RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); ref.setSource(extractSource(ele)); return ref; } else if (nodeNameEquals(ele, IDREF_ELEMENT)) { return parseIdRefElement(ele); } else if (nodeNameEquals(ele, VALUE_ELEMENT)) { return parseValueElement(ele, defaultValueType); } else if (nodeNameEquals(ele, NULL_ELEMENT)) { // It's a distinguished null value. Let's wrap it in a TypedStringValue // object in order to preserve the source location. TypedStringValue nullHolder = new TypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { return parseArrayElement(ele, bd); } else if (nodeNameEquals(ele, LIST_ELEMENT)) { return parseListElement(ele, bd); } else if (nodeNameEquals(ele, SET_ELEMENT)) { return parseSetElement(ele, bd); } else if (nodeNameEquals(ele, MAP_ELEMENT)) { return parseMapElement(ele, bd); } else if (nodeNameEquals(ele, PROPS_ELEMENT)) { return parsePropsElement(ele); } else { error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } } /** * Return a typed String value Object for the given 'idref' element. */ public Object parseIdRefElement(Element ele) { // A generic reference to any name of any bean. String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in the same XML file. refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { error("Either 'bean' or 'local' is required for <idref> element", ele); return null; } } if (!StringUtils.hasText(refName)) { error("<idref> element contains empty target attribute", ele); return null; } RuntimeBeanNameReference ref = new RuntimeBeanNameReference(refName); ref.setSource(extractSource(ele)); return ref; } /** * Return a typed String value Object for the given value element. */ public Object parseValueElement(Element ele, String defaultTypeName) { // It's a literal value. String value = DomUtils.getTextValue(ele); String specifiedTypeName = ele.getAttribute(TYPE_ATTRIBUTE); String typeName = specifiedTypeName; if (!StringUtils.hasText(typeName)) { typeName = defaultTypeName; } try { TypedStringValue typedValue = buildTypedStringValue(value, typeName); typedValue.setSource(extractSource(ele)); typedValue.setSpecifiedTypeName(specifiedTypeName); return typedValue; } catch (ClassNotFoundException ex) { error("Type class [" + typeName + "] not found for <value> element", ele, ex); return value; } } /** * Build a typed String value Object for the given raw value. * @see org.springframework.beans.factory.config.TypedStringValue */ protected TypedStringValue buildTypedStringValue(String value, String targetTypeName) throws ClassNotFoundException { ClassLoader classLoader = this.readerContext.getBeanClassLoader(); TypedStringValue typedValue; if (!StringUtils.hasText(targetTypeName)) { typedValue = new TypedStringValue(value); } else if (classLoader != null) { Class<?> targetType = ClassUtils.forName(targetTypeName, classLoader); typedValue = new TypedStringValue(value, targetType); } else { typedValue = new TypedStringValue(value, targetTypeName); } return typedValue; } /** * Parse an array element. */ public Object parseArrayElement(Element arrayEle, BeanDefinition bd) { String elementType = arrayEle.getAttribute(VALUE_TYPE_ATTRIBUTE); NodeList nl = arrayEle.getChildNodes(); ManagedArray target = new ManagedArray(elementType, nl.getLength()); target.setSource(extractSource(arrayEle)); target.setElementTypeName(elementType); target.setMergeEnabled(parseMergeAttribute(arrayEle)); parseCollectionElements(nl, target, bd, elementType); return target; } /** * Parse a list element. */ public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) { String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); NodeList nl = collectionEle.getChildNodes(); ManagedList<Object> target = new ManagedList<Object>(nl.getLength()); target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); target.setMergeEnabled(parseMergeAttribute(collectionEle)); parseCollectionElements(nl, target, bd, defaultElementType); return target; } /** * Parse a set element. */ public Set<Object> parseSetElement(Element collectionEle, BeanDefinition bd) { String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); NodeList nl = collectionEle.getChildNodes(); ManagedSet<Object> target = new ManagedSet<Object>(nl.getLength()); target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); target.setMergeEnabled(parseMergeAttribute(collectionEle)); parseCollectionElements(nl, target, bd, defaultElementType); return target; } protected void parseCollectionElements( NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) { for (int i = 0; i < elementNodes.getLength(); i++) { Node node = elementNodes.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) { target.add(parsePropertySubElement((Element) node, bd, defaultElementType)); } } } /** * Parse a map element. */ public Map<Object, Object> parseMapElement(Element mapEle, BeanDefinition bd) { String defaultKeyType = mapEle.getAttribute(KEY_TYPE_ATTRIBUTE); String defaultValueType = mapEle.getAttribute(VALUE_TYPE_ATTRIBUTE); List<Element> entryEles = DomUtils.getChildElementsByTagName(mapEle, ENTRY_ELEMENT); ManagedMap<Object, Object> map = new ManagedMap<Object, Object>(entryEles.size()); map.setSource(extractSource(mapEle)); map.setKeyTypeName(defaultKeyType); map.setValueTypeName(defaultValueType); map.setMergeEnabled(parseMergeAttribute(mapEle)); for (Element entryEle : entryEles) { // Should only have one value child element: ref, value, list, etc. // Optionally, there might be a key child element. NodeList entrySubNodes = entryEle.getChildNodes(); Element keyEle = null; Element valueEle = null; for (int j = 0; j < entrySubNodes.getLength(); j++) { Node node = entrySubNodes.item(j); if (node instanceof Element) { Element candidateEle = (Element) node; if (nodeNameEquals(candidateEle, KEY_ELEMENT)) { if (keyEle != null) { error("<entry> element is only allowed to contain one <key> sub-element", entryEle); } else { keyEle = candidateEle; } } else { // Child element is what we're looking for. if (nodeNameEquals(candidateEle, DESCRIPTION_ELEMENT)) { // the element is a <description> -> ignore it } else if (valueEle != null) { error("<entry> element must not contain more than one value sub-element", entryEle); } else { valueEle = candidateEle; } } } } // Extract key from attribute or sub-element. Object key = null; boolean hasKeyAttribute = entryEle.hasAttribute(KEY_ATTRIBUTE); boolean hasKeyRefAttribute = entryEle.hasAttribute(KEY_REF_ATTRIBUTE); if ((hasKeyAttribute && hasKeyRefAttribute) || ((hasKeyAttribute || hasKeyRefAttribute)) && keyEle != null) { error("<entry> element is only allowed to contain either " + "a 'key' attribute OR a 'key-ref' attribute OR a <key> sub-element", entryEle); } if (hasKeyAttribute) { key = buildTypedStringValueForMap(entryEle.getAttribute(KEY_ATTRIBUTE), defaultKeyType, entryEle); } else if (hasKeyRefAttribute) { String refName = entryEle.getAttribute(KEY_REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error("<entry> element contains empty 'key-ref' attribute", entryEle); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(entryEle)); key = ref; } else if (keyEle != null) { key = parseKeyElement(keyEle, bd, defaultKeyType); } else { error("<entry> element must specify a key", entryEle); } // Extract value from attribute or sub-element. Object value = null; boolean hasValueAttribute = entryEle.hasAttribute(VALUE_ATTRIBUTE); boolean hasValueRefAttribute = entryEle.hasAttribute(VALUE_REF_ATTRIBUTE); boolean hasValueTypeAttribute = entryEle.hasAttribute(VALUE_TYPE_ATTRIBUTE); if ((hasValueAttribute && hasValueRefAttribute) || ((hasValueAttribute || hasValueRefAttribute)) && valueEle != null) { error("<entry> element is only allowed to contain either " + "'value' attribute OR 'value-ref' attribute OR <value> sub-element", entryEle); } if ((hasValueTypeAttribute && hasValueRefAttribute) || (hasValueTypeAttribute && !hasValueAttribute) || (hasValueTypeAttribute && valueEle != null)) { error("<entry> element is only allowed to contain a 'value-type' " + "attribute when it has a 'value' attribute", entryEle); } if (hasValueAttribute) { String valueType = entryEle.getAttribute(VALUE_TYPE_ATTRIBUTE); if (!StringUtils.hasText(valueType)) { valueType = defaultValueType; } value = buildTypedStringValueForMap(entryEle.getAttribute(VALUE_ATTRIBUTE), valueType, entryEle); } else if (hasValueRefAttribute) { String refName = entryEle.getAttribute(VALUE_REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error("<entry> element contains empty 'value-ref' attribute", entryEle); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(entryEle)); value = ref; } else if (valueEle != null) { value = parsePropertySubElement(valueEle, bd, defaultValueType); } else { error("<entry> element must specify a value", entryEle); } // Add final key and value to the Map. map.put(key, value); } return map; } /** * Build a typed String value Object for the given raw value. * @see org.springframework.beans.factory.config.TypedStringValue */ protected final Object buildTypedStringValueForMap(String value, String defaultTypeName, Element entryEle) { try { TypedStringValue typedValue = buildTypedStringValue(value, defaultTypeName); typedValue.setSource(extractSource(entryEle)); return typedValue; } catch (ClassNotFoundException ex) { error("Type class [" + defaultTypeName + "] not found for Map key/value type", entryEle, ex); return value; } } /** * Parse a key sub-element of a map element. */ protected Object parseKeyElement(Element keyEle, BeanDefinition bd, String defaultKeyTypeName) { NodeList nl = keyEle.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { // Child element is what we're looking for. if (subElement != null) { error("<key> element must not contain more than one value sub-element", keyEle); } else { subElement = (Element) node; } } } return parsePropertySubElement(subElement, bd, defaultKeyTypeName); } /** * Parse a props element. */ public Properties parsePropsElement(Element propsEle) { ManagedProperties props = new ManagedProperties(); props.setSource(extractSource(propsEle)); props.setMergeEnabled(parseMergeAttribute(propsEle)); List<Element> propEles = DomUtils.getChildElementsByTagName(propsEle, PROP_ELEMENT); for (Element propEle : propEles) { String key = propEle.getAttribute(KEY_ATTRIBUTE); // Trim the text value to avoid unwanted whitespace // caused by typical XML formatting. String value = DomUtils.getTextValue(propEle).trim(); TypedStringValue keyHolder = new TypedStringValue(key); keyHolder.setSource(extractSource(propEle)); TypedStringValue valueHolder = new TypedStringValue(value); valueHolder.setSource(extractSource(propEle)); props.put(keyHolder, valueHolder); } return props; } /** * Parse the merge attribute of a collection element, if any. */ public boolean parseMergeAttribute(Element collectionElement) { String value = collectionElement.getAttribute(MERGE_ATTRIBUTE); if (DEFAULT_VALUE.equals(value)) { value = this.defaults.getMerge(); } return TRUE_VALUE.equals(value); } public BeanDefinition parseCustomElement(Element ele) { return parseCustomElement(ele, null); } public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); } public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) { return decorateBeanDefinitionIfRequired(ele, definitionHolder, null); } public BeanDefinitionHolder decorateBeanDefinitionIfRequired( Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) { BeanDefinitionHolder finalDefinition = definitionHolder; // Decorate based on custom attributes first. NamedNodeMap attributes = ele.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Node node = attributes.item(i); finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } // Decorate based on custom nested elements. NodeList children = ele.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } } return finalDefinition; } public BeanDefinitionHolder decorateIfRequired( Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(node); if (!isDefaultNamespace(namespaceUri)) { NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler != null) { return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd)); } else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node); } else { // A custom namespace, not to be handled by Spring - maybe "xml:...". if (logger.isDebugEnabled()) { logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]"); } } } return originalDef; } private BeanDefinitionHolder parseNestedCustomElement(Element ele, BeanDefinition containingBd) { BeanDefinition innerDefinition = parseCustomElement(ele, containingBd); if (innerDefinition == null) { error("Incorrect usage of element '" + ele.getNodeName() + "' in a nested manner. " + "This tag cannot be used nested inside <property>.", ele); return null; } String id = ele.getNodeName() + BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(innerDefinition); if (logger.isDebugEnabled()) { logger.debug("Using generated bean name [" + id + "] for nested custom element '" + ele.getNodeName() + "'"); } return new BeanDefinitionHolder(innerDefinition, id); } /** * Get the namespace URI for the supplied node. * <p>The default implementation uses {@link Node#getNamespaceURI}. * Subclasses may override the default implementation to provide a * different namespace identification mechanism. * @param node the node */ public String getNamespaceURI(Node node) { return node.getNamespaceURI(); } /** * Get the local name for the supplied {@link Node}. * <p>The default implementation calls {@link Node#getLocalName}. * Subclasses may override the default implementation to provide a * different mechanism for getting the local name. * @param node the {@code Node} */ public String getLocalName(Node node) { return node.getLocalName(); } /** * Determine whether the name of the supplied node is equal to the supplied name. * <p>The default implementation checks the supplied desired name against both * {@link Node#getNodeName()} and {@link Node#getLocalName()}. * <p>Subclasses may override the default implementation to provide a different * mechanism for comparing node names. * @param node the node to compare * @param desiredName the name to check for */ public boolean nodeNameEquals(Node node, String desiredName) { return desiredName.equals(node.getNodeName()) || desiredName.equals(getLocalName(node)); } public boolean isDefaultNamespace(String namespaceUri) { return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri)); } public boolean isDefaultNamespace(Node node) { return isDefaultNamespace(getNamespaceURI(node)); } private boolean isCandidateElement(Node node) { return (node instanceof Element && (isDefaultNamespace(node) || !isDefaultNamespace(node.getParentNode()))); } }
三:AbstractBeanDefinition 类
上面完成了对XML文档到GenericBeanDefinition的转换,也就是到这来,XML中所有的配置都可以在GenericBeanDefinition的实例类中找到对应的配置。
GenericBeanDefinition只是子类实现,而大部分的通用属性都保存在了AbstractBeanDefinition中,那么我们再次通过AbstractBeanDefinition的属性来看下解析了哪些对应的配置。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.support; /** * Base class for concrete, full-fledged {@link BeanDefinition} classes, * factoring out common properties of {@link GenericBeanDefinition}, * {@link RootBeanDefinition}, and {@link ChildBeanDefinition}. * * <p>The autowire constants match the ones defined in the * {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory} * interface. * * @author Rod Johnson * @author Juergen Hoeller * @author Rob Harrop * @author Mark Fisher * @see GenericBeanDefinition * @see RootBeanDefinition * @see ChildBeanDefinition */ @SuppressWarnings("serial") public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable { /** * Constant for the default scope name: {@code ""}, equivalent to singleton * status unless overridden from a parent bean definition (if applicable). */ public static final String SCOPE_DEFAULT = ""; /** * Constant that indicates no autowiring at all. * @see #setAutowireMode */ public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO; /** * Constant that indicates autowiring bean properties by name. * @see #setAutowireMode */ public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; /** * Constant that indicates autowiring bean properties by type. * @see #setAutowireMode */ public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE; /** * Constant that indicates autowiring a constructor. * @see #setAutowireMode */ public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR; /** * Constant that indicates determining an appropriate autowire strategy * through introspection of the bean class. * @see #setAutowireMode * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies, * use annotation-based autowiring for clearer demarcation of autowiring needs. */ @Deprecated public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT; /** * Constant that indicates no dependency check at all. * @see #setDependencyCheck */ public static final int DEPENDENCY_CHECK_NONE = 0; /** * Constant that indicates dependency checking for object references. * @see #setDependencyCheck */ public static final int DEPENDENCY_CHECK_OBJECTS = 1; /** * Constant that indicates dependency checking for "simple" properties. * @see #setDependencyCheck * @see org.springframework.beans.BeanUtils#isSimpleProperty */ public static final int DEPENDENCY_CHECK_SIMPLE = 2; /** * Constant that indicates dependency checking for all properties * (object references as well as "simple" properties). * @see #setDependencyCheck */ public static final int DEPENDENCY_CHECK_ALL = 3; /** * Constant that indicates the container should attempt to infer the * {@link #setDestroyMethodName destroy method name} for a bean as opposed to * explicit specification of a method name. The value {@value} is specifically * designed to include characters otherwise illegal in a method name, ensuring * no possibility of collisions with legitimately named methods having the same * name. * <p>Currently, the method names detected during destroy method inference * are "close" and "shutdown", if present on the specific bean class. */ public static final String INFER_METHOD = "(inferred)"; private volatile Object beanClass;
//bean的作用范围,对应bean的属性scope private String scope = SCOPE_DEFAULT;
//是否是抽象,对应bean属性abstract private boolean abstractFlag = false;
//是否延迟加载,对应bean属性lazy-init private boolean lazyInit = false;
//自动注入模式,对应bean属性autowire private int autowireMode = AUTOWIRE_NO; private int dependencyCheck = DEPENDENCY_CHECK_NONE; private String[] dependsOn; private boolean autowireCandidate = true;
//自动装配时当出现多个bean候选者时,将作为首选者,对应bean属性primary private boolean primary = false; private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<String, AutowireCandidateQualifier>(0); private boolean nonPublicAccessAllowed = true; private boolean lenientConstructorResolution = true; private String factoryBeanName;
//对应bean属性factory-method private String factoryMethodName;
//记录构造函数注入属性,对应bean属性constructor-arg private ConstructorArgumentValues constructorArgumentValues;
//普通属性集合 private MutablePropertyValues propertyValues; private MethodOverrides methodOverrides = new MethodOverrides();
//初始化方法,对应bean属性init-method private String initMethodName;
//销毁方法,对应bean属性destory-method private String destroyMethodName; private boolean enforceInitMethod = true; private boolean enforceDestroyMethod = true; private boolean synthetic = false; private int role = BeanDefinition.ROLE_APPLICATION; private String description; private Resource resource; /** * Create a new AbstractBeanDefinition with default settings. */ protected AbstractBeanDefinition() { this(null, null); } /** * Create a new AbstractBeanDefinition with the given * constructor argument values and property values. */ protected AbstractBeanDefinition(ConstructorArgumentValues cargs, MutablePropertyValues pvs) { setConstructorArgumentValues(cargs); setPropertyValues(pvs); } /** * Create a new AbstractBeanDefinition as a deep copy of the given * bean definition. * @param original the original bean definition to copy from */ protected AbstractBeanDefinition(BeanDefinition original) { setParentName(original.getParentName()); setBeanClassName(original.getBeanClassName()); setScope(original.getScope()); setAbstract(original.isAbstract()); setLazyInit(original.isLazyInit()); setFactoryBeanName(original.getFactoryBeanName()); setFactoryMethodName(original.getFactoryMethodName()); setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues())); setPropertyValues(new MutablePropertyValues(original.getPropertyValues())); setRole(original.getRole()); setSource(original.getSource()); copyAttributesFrom(original); if (original instanceof AbstractBeanDefinition) { AbstractBeanDefinition originalAbd = (AbstractBeanDefinition) original; if (originalAbd.hasBeanClass()) { setBeanClass(originalAbd.getBeanClass()); } setAutowireMode(originalAbd.getAutowireMode()); setDependencyCheck(originalAbd.getDependencyCheck()); setDependsOn(originalAbd.getDependsOn()); setAutowireCandidate(originalAbd.isAutowireCandidate()); setPrimary(originalAbd.isPrimary()); copyQualifiersFrom(originalAbd); setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed()); setLenientConstructorResolution(originalAbd.isLenientConstructorResolution()); setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides())); setInitMethodName(originalAbd.getInitMethodName()); setEnforceInitMethod(originalAbd.isEnforceInitMethod()); setDestroyMethodName(originalAbd.getDestroyMethodName()); setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod()); setSynthetic(originalAbd.isSynthetic()); setResource(originalAbd.getResource()); } else { setResourceDescription(original.getResourceDescription()); } } /** * Override settings in this bean definition (presumably a copied parent * from a parent-child inheritance relationship) from the given bean * definition (presumably the child). * <ul> * <li>Will override beanClass if specified in the given bean definition. * <li>Will always take {@code abstract}, {@code scope}, * {@code lazyInit}, {@code autowireMode}, {@code dependencyCheck}, * and {@code dependsOn} from the given bean definition. * <li>Will add {@code constructorArgumentValues}, {@code propertyValues}, * {@code methodOverrides} from the given bean definition to existing ones. * <li>Will override {@code factoryBeanName}, {@code factoryMethodName}, * {@code initMethodName}, and {@code destroyMethodName} if specified * in the given bean definition. * </ul> */ public void overrideFrom(BeanDefinition other) { if (StringUtils.hasLength(other.getBeanClassName())) { setBeanClassName(other.getBeanClassName()); } if (StringUtils.hasLength(other.getScope())) { setScope(other.getScope()); } setAbstract(other.isAbstract()); setLazyInit(other.isLazyInit()); if (StringUtils.hasLength(other.getFactoryBeanName())) { setFactoryBeanName(other.getFactoryBeanName()); } if (StringUtils.hasLength(other.getFactoryMethodName())) { setFactoryMethodName(other.getFactoryMethodName()); } getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues()); getPropertyValues().addPropertyValues(other.getPropertyValues()); setRole(other.getRole()); setSource(other.getSource()); copyAttributesFrom(other); if (other instanceof AbstractBeanDefinition) { AbstractBeanDefinition otherAbd = (AbstractBeanDefinition) other; if (otherAbd.hasBeanClass()) { setBeanClass(otherAbd.getBeanClass()); } setAutowireMode(otherAbd.getAutowireMode()); setDependencyCheck(otherAbd.getDependencyCheck()); setDependsOn(otherAbd.getDependsOn()); setAutowireCandidate(otherAbd.isAutowireCandidate()); setPrimary(otherAbd.isPrimary()); copyQualifiersFrom(otherAbd); setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed()); setLenientConstructorResolution(otherAbd.isLenientConstructorResolution()); getMethodOverrides().addOverrides(otherAbd.getMethodOverrides()); if (StringUtils.hasLength(otherAbd.getInitMethodName())) { setInitMethodName(otherAbd.getInitMethodName()); setEnforceInitMethod(otherAbd.isEnforceInitMethod()); } if (otherAbd.getDestroyMethodName() != null) { setDestroyMethodName(otherAbd.getDestroyMethodName()); setEnforceDestroyMethod(otherAbd.isEnforceDestroyMethod()); } setSynthetic(otherAbd.isSynthetic()); setResource(otherAbd.getResource()); } else { setResourceDescription(other.getResourceDescription()); } } /** * Apply the provided default values to this bean. * @param defaults the defaults to apply */ public void applyDefaults(BeanDefinitionDefaults defaults) { setLazyInit(defaults.isLazyInit()); setAutowireMode(defaults.getAutowireMode()); setDependencyCheck(defaults.getDependencyCheck()); setInitMethodName(defaults.getInitMethodName()); setEnforceInitMethod(false); setDestroyMethodName(defaults.getDestroyMethodName()); setEnforceDestroyMethod(false); } /** * Specify the bean class name of this bean definition. */ @Override public void setBeanClassName(String beanClassName) { this.beanClass = beanClassName; } /** * Return the current bean class name of this bean definition. */ @Override public String getBeanClassName() { Object beanClassObject = this.beanClass; if (beanClassObject instanceof Class) { return ((Class<?>) beanClassObject).getName(); } else { return (String) beanClassObject; } } /** * Specify the class for this bean. */ public void setBeanClass(Class<?> beanClass) { this.beanClass = beanClass; } /** * Return the class of the wrapped bean, if already resolved. * @return the bean class, or {@code null} if none defined * @throws IllegalStateException if the bean definition does not define a bean class, * or a specified bean class name has not been resolved into an actual Class */ public Class<?> getBeanClass() throws IllegalStateException { Object beanClassObject = this.beanClass; if (beanClassObject == null) { throw new IllegalStateException("No bean class specified on bean definition"); } if (!(beanClassObject instanceof Class)) { throw new IllegalStateException( "Bean class name [" + beanClassObject + "] has not been resolved into an actual Class"); } return (Class<?>) beanClassObject; } /** * Return whether this definition specifies a bean class. */ public boolean hasBeanClass() { return (this.beanClass instanceof Class); } /** * Determine the class of the wrapped bean, resolving it from a * specified class name if necessary. Will also reload a specified * Class from its name when called with the bean class already resolved. * @param classLoader the ClassLoader to use for resolving a (potential) class name * @return the resolved bean class * @throws ClassNotFoundException if the class name could be resolved */ public Class<?> resolveBeanClass(ClassLoader classLoader) throws ClassNotFoundException { String className = getBeanClassName(); if (className == null) { return null; } Class<?> resolvedClass = ClassUtils.forName(className, classLoader); this.beanClass = resolvedClass; return resolvedClass; } /** * Set the name of the target scope for the bean. * <p>The default is singleton status, although this is only applied once * a bean definition becomes active in the containing factory. A bean * definition may eventually inherit its scope from a parent bean definition. * For this reason, the default scope name is an empty string (i.e., {@code ""}), * with singleton status being assumed until a resolved scope is set. * @see #SCOPE_SINGLETON * @see #SCOPE_PROTOTYPE */ @Override public void setScope(String scope) { this.scope = scope; } /** * Return the name of the target scope for the bean. */ @Override public String getScope() { return this.scope; } /** * Return whether this a <b>Singleton</b>, with a single shared instance * returned from all calls. * @see #SCOPE_SINGLETON */ @Override public boolean isSingleton() { return SCOPE_SINGLETON.equals(scope) || SCOPE_DEFAULT.equals(scope); } /** * Return whether this a <b>Prototype</b>, with an independent instance * returned for each call. * @see #SCOPE_PROTOTYPE */ @Override public boolean isPrototype() { return SCOPE_PROTOTYPE.equals(scope); } /** * Set if this bean is "abstract", i.e. not meant to be instantiated itself but * rather just serving as parent for concrete child bean definitions. * <p>Default is "false". Specify true to tell the bean factory to not try to * instantiate that particular bean in any case. */ public void setAbstract(boolean abstractFlag) { this.abstractFlag = abstractFlag; } /** * Return whether this bean is "abstract", i.e. not meant to be instantiated * itself but rather just serving as parent for concrete child bean definitions. */ @Override public boolean isAbstract() { return this.abstractFlag; } /** * Set whether this bean should be lazily initialized. * <p>If {@code false}, the bean will get instantiated on startup by bean * factories that perform eager initialization of singletons. */ @Override public void setLazyInit(boolean lazyInit) { this.lazyInit = lazyInit; } /** * Return whether this bean should be lazily initialized, i.e. not * eagerly instantiated on startup. Only applicable to a singleton bean. */ @Override public boolean isLazyInit() { return this.lazyInit; } /** * Set the autowire mode. This determines whether any automagical detection * and setting of bean references will happen. Default is AUTOWIRE_NO, * which means there's no autowire. * @param autowireMode the autowire mode to set. * Must be one of the constants defined in this class. * @see #AUTOWIRE_NO * @see #AUTOWIRE_BY_NAME * @see #AUTOWIRE_BY_TYPE * @see #AUTOWIRE_CONSTRUCTOR * @see #AUTOWIRE_AUTODETECT */ public void setAutowireMode(int autowireMode) { this.autowireMode = autowireMode; } /** * Return the autowire mode as specified in the bean definition. */ public int getAutowireMode() { return this.autowireMode; } /** * Return the resolved autowire code, * (resolving AUTOWIRE_AUTODETECT to AUTOWIRE_CONSTRUCTOR or AUTOWIRE_BY_TYPE). * @see #AUTOWIRE_AUTODETECT * @see #AUTOWIRE_CONSTRUCTOR * @see #AUTOWIRE_BY_TYPE */ public int getResolvedAutowireMode() { if (this.autowireMode == AUTOWIRE_AUTODETECT) { // Work out whether to apply setter autowiring or constructor autowiring. // If it has a no-arg constructor it's deemed to be setter autowiring, // otherwise we'll try constructor autowiring. Constructor<?>[] constructors = getBeanClass().getConstructors(); for (Constructor<?> constructor : constructors) { if (constructor.getParameterTypes().length == 0) { return AUTOWIRE_BY_TYPE; } } return AUTOWIRE_CONSTRUCTOR; } else { return this.autowireMode; } } /** * Set the dependency check code. * @param dependencyCheck the code to set. * Must be one of the four constants defined in this class. * @see #DEPENDENCY_CHECK_NONE * @see #DEPENDENCY_CHECK_OBJECTS * @see #DEPENDENCY_CHECK_SIMPLE * @see #DEPENDENCY_CHECK_ALL */ public void setDependencyCheck(int dependencyCheck) { this.dependencyCheck = dependencyCheck; } /** * Return the dependency check code. */ public int getDependencyCheck() { return this.dependencyCheck; } /** * Set the names of the beans that this bean depends on being initialized. * The bean factory will guarantee that these beans get initialized first. * <p>Note that dependencies are normally expressed through bean properties or * constructor arguments. This property should just be necessary for other kinds * of dependencies like statics (*ugh*) or database preparation on startup. */ @Override public void setDependsOn(String... dependsOn) { this.dependsOn = dependsOn; } /** * Return the bean names that this bean depends on. */ @Override public String[] getDependsOn() { return this.dependsOn; } /** * Set whether this bean is a candidate for getting autowired into some other bean. * <p>Note that this flag is designed to only affect type-based autowiring. * It does not affect explicit references by name, which will get resolved even * if the specified bean is not marked as an autowire candidate. As a consequence, * autowiring by name will nevertheless inject a bean if the name matches. * @see #AUTOWIRE_BY_TYPE * @see #AUTOWIRE_BY_NAME */ @Override public void setAutowireCandidate(boolean autowireCandidate) { this.autowireCandidate = autowireCandidate; } /** * Return whether this bean is a candidate for getting autowired into some other bean. */ @Override public boolean isAutowireCandidate() { return this.autowireCandidate; } /** * Set whether this bean is a primary autowire candidate. * <p>If this value is {@code true} for exactly one bean among multiple * matching candidates, it will serve as a tie-breaker. */ @Override public void setPrimary(boolean primary) { this.primary = primary; } /** * Return whether this bean is a primary autowire candidate. */ @Override public boolean isPrimary() { return this.primary; } /** * Register a qualifier to be used for autowire candidate resolution, * keyed by the qualifier's type name. * @see AutowireCandidateQualifier#getTypeName() */ public void addQualifier(AutowireCandidateQualifier qualifier) { this.qualifiers.put(qualifier.getTypeName(), qualifier); } /** * Return whether this bean has the specified qualifier. */ public boolean hasQualifier(String typeName) { return this.qualifiers.keySet().contains(typeName); } /** * Return the qualifier mapped to the provided type name. */ public AutowireCandidateQualifier getQualifier(String typeName) { return this.qualifiers.get(typeName); } /** * Return all registered qualifiers. * @return the Set of {@link AutowireCandidateQualifier} objects. */ public Set<AutowireCandidateQualifier> getQualifiers() { return new LinkedHashSet<AutowireCandidateQualifier>(this.qualifiers.values()); } /** * Copy the qualifiers from the supplied AbstractBeanDefinition to this bean definition. * @param source the AbstractBeanDefinition to copy from */ public void copyQualifiersFrom(AbstractBeanDefinition source) { Assert.notNull(source, "Source must not be null"); this.qualifiers.putAll(source.qualifiers); } /** * Specify whether to allow access to non-public constructors and methods, * for the case of externalized metadata pointing to those. The default is * {@code true}; switch this to {@code false} for public access only. * <p>This applies to constructor resolution, factory method resolution, * and also init/destroy methods. Bean property accessors have to be public * in any case and are not affected by this setting. * <p>Note that annotation-driven configuration will still access non-public * members as far as they have been annotated. This setting applies to * externalized metadata in this bean definition only. */ public void setNonPublicAccessAllowed(boolean nonPublicAccessAllowed) { this.nonPublicAccessAllowed = nonPublicAccessAllowed; } /** * Return whether to allow access to non-public constructors and methods. */ public boolean isNonPublicAccessAllowed() { return this.nonPublicAccessAllowed; } /** * Specify whether to resolve constructors in lenient mode ({@code true}, * which is the default) or to switch to strict resolution (throwing an exception * in case of ambiguous constructors that all match when converting the arguments, * whereas lenient mode would use the one with the 'closest' type matches). */ public void setLenientConstructorResolution(boolean lenientConstructorResolution) { this.lenientConstructorResolution = lenientConstructorResolution; } /** * Return whether to resolve constructors in lenient mode or in strict mode. */ public boolean isLenientConstructorResolution() { return this.lenientConstructorResolution; } /** * Specify the factory bean to use, if any. * This the name of the bean to call the specified factory method on. * @see #setFactoryMethodName */ @Override public void setFactoryBeanName(String factoryBeanName) { this.factoryBeanName = factoryBeanName; } /** * Return the factory bean name, if any. */ @Override public String getFactoryBeanName() { return this.factoryBeanName; } /** * Specify a factory method, if any. This method will be invoked with * constructor arguments, or with no arguments if none are specified. * The method will be invoked on the specified factory bean, if any, * or otherwise as a static method on the local bean class. * @see #setFactoryBeanName * @see #setBeanClassName */ @Override public void setFactoryMethodName(String factoryMethodName) { this.factoryMethodName = factoryMethodName; } /** * Return a factory method, if any. */ @Override public String getFactoryMethodName() { return this.factoryMethodName; } /** * Specify constructor argument values for this bean. */ public void setConstructorArgumentValues(ConstructorArgumentValues constructorArgumentValues) { this.constructorArgumentValues = (constructorArgumentValues != null ? constructorArgumentValues : new ConstructorArgumentValues()); } /** * Return constructor argument values for this bean (never {@code null}). */ @Override public ConstructorArgumentValues getConstructorArgumentValues() { return this.constructorArgumentValues; } /** * Return if there are constructor argument values defined for this bean. */ public boolean hasConstructorArgumentValues() { return !this.constructorArgumentValues.isEmpty(); } /** * Specify property values for this bean, if any. */ public void setPropertyValues(MutablePropertyValues propertyValues) { this.propertyValues = (propertyValues != null ? propertyValues : new MutablePropertyValues()); } /** * Return property values for this bean (never {@code null}). */ @Override public MutablePropertyValues getPropertyValues() { return this.propertyValues; } /** * Specify method overrides for the bean, if any. */ public void setMethodOverrides(MethodOverrides methodOverrides) { this.methodOverrides = (methodOverrides != null ? methodOverrides : new MethodOverrides()); } /** * Return information about methods to be overridden by the IoC * container. This will be empty if there are no method overrides. * Never returns {@code null}. */ public MethodOverrides getMethodOverrides() { return this.methodOverrides; } /** * Set the name of the initializer method. The default is {@code null} * in which case there is no initializer method. */ public void setInitMethodName(String initMethodName) { this.initMethodName = initMethodName; } /** * Return the name of the initializer method. */ public String getInitMethodName() { return this.initMethodName; } /** * Specify whether or not the configured init method is the default. * Default value is {@code false}. * @see #setInitMethodName */ public void setEnforceInitMethod(boolean enforceInitMethod) { this.enforceInitMethod = enforceInitMethod; } /** * Indicate whether the configured init method is the default. * @see #getInitMethodName() */ public boolean isEnforceInitMethod() { return this.enforceInitMethod; } /** * Set the name of the destroy method. The default is {@code null} * in which case there is no destroy method. */ public void setDestroyMethodName(String destroyMethodName) { this.destroyMethodName = destroyMethodName; } /** * Return the name of the destroy method. */ public String getDestroyMethodName() { return this.destroyMethodName; } /** * Specify whether or not the configured destroy method is the default. * Default value is {@code false}. * @see #setDestroyMethodName */ public void setEnforceDestroyMethod(boolean enforceDestroyMethod) { this.enforceDestroyMethod = enforceDestroyMethod; } /** * Indicate whether the configured destroy method is the default. * @see #getDestroyMethodName */ public boolean isEnforceDestroyMethod() { return this.enforceDestroyMethod; } /** * Set whether this bean definition is 'synthetic', that is, not defined * by the application itself (for example, an infrastructure bean such * as a helper for auto-proxying, created through {@code <aop:config>}). */ public void setSynthetic(boolean synthetic) { this.synthetic = synthetic; } /** * Return whether this bean definition is 'synthetic', that is, * not defined by the application itself. */ public boolean isSynthetic() { return this.synthetic; } /** * Set the role hint for this {@code BeanDefinition}. */ public void setRole(int role) { this.role = role; } /** * Return the role hint for this {@code BeanDefinition}. */ @Override public int getRole() { return this.role; } /** * Set a human-readable description of this bean definition. */ public void setDescription(String description) { this.description = description; } /** * Return a human-readable description of this bean definition. */ @Override public String getDescription() { return this.description; } /** * Set the resource that this bean definition came from * (for the purpose of showing context in case of errors). */ public void setResource(Resource resource) { this.resource = resource; } /** * Return the resource that this bean definition came from. */ public Resource getResource() { return this.resource; } /** * Set a description of the resource that this bean definition * came from (for the purpose of showing context in case of errors). */ public void setResourceDescription(String resourceDescription) { this.resource = new DescriptiveResource(resourceDescription); } /** * Return a description of the resource that this bean definition * came from (for the purpose of showing context in case of errors). */ @Override public String getResourceDescription() { return (this.resource != null ? this.resource.getDescription() : null); } /** * Set the originating (e.g. decorated) BeanDefinition, if any. */ public void setOriginatingBeanDefinition(BeanDefinition originatingBd) { this.resource = new BeanDefinitionResource(originatingBd); } /** * Return the originating BeanDefinition, or {@code null} if none. * Allows for retrieving the decorated bean definition, if any. * <p>Note that this method returns the immediate originator. Iterate through the * originator chain to find the original BeanDefinition as defined by the user. */ @Override public BeanDefinition getOriginatingBeanDefinition() { return (this.resource instanceof BeanDefinitionResource ? ((BeanDefinitionResource) this.resource).getBeanDefinition() : null); } /** * Validate this bean definition. * @throws BeanDefinitionValidationException in case of validation failure */ public void validate() throws BeanDefinitionValidationException { if (!getMethodOverrides().isEmpty() && getFactoryMethodName() != null) { throw new BeanDefinitionValidationException( "Cannot combine static factory method with method overrides: " + "the static factory method must create the instance"); } if (hasBeanClass()) { prepareMethodOverrides(); } } /** * Validate and prepare the method overrides defined for this bean. * Checks for existence of a method with the specified name. * @throws BeanDefinitionValidationException in case of validation failure */ public void prepareMethodOverrides() throws BeanDefinitionValidationException { // Check that lookup methods exists. MethodOverrides methodOverrides = getMethodOverrides(); if (!methodOverrides.isEmpty()) { Set<MethodOverride> overrides = methodOverrides.getOverrides(); synchronized (overrides) { for (MethodOverride mo : overrides) { prepareMethodOverride(mo); } } } } /** * Validate and prepare the given method override. * Checks for existence of a method with the specified name, * marking it as not overloaded if none found. * @param mo the MethodOverride object to validate * @throws BeanDefinitionValidationException in case of validation failure */ protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException { int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName()); if (count == 0) { throw new BeanDefinitionValidationException( "Invalid method override: no method with name '" + mo.getMethodName() + "' on class [" + getBeanClassName() + "]"); } else if (count == 1) { // Mark override as not overloaded, to avoid the overhead of arg type checking. mo.setOverloaded(false); } } /** * Public declaration of Object's {@code clone()} method. * Delegates to {@link #cloneBeanDefinition()}. * @see Object#clone() */ @Override public Object clone() { return cloneBeanDefinition(); } /** * Clone this bean definition. * To be implemented by concrete subclasses. * @return the cloned bean definition object */ public abstract AbstractBeanDefinition cloneBeanDefinition(); @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof AbstractBeanDefinition)) { return false; } AbstractBeanDefinition that = (AbstractBeanDefinition) other; if (!ObjectUtils.nullSafeEquals(getBeanClassName(), that.getBeanClassName())) return false; if (!ObjectUtils.nullSafeEquals(this.scope, that.scope)) return false; if (this.abstractFlag != that.abstractFlag) return false; if (this.lazyInit != that.lazyInit) return false; if (this.autowireMode != that.autowireMode) return false; if (this.dependencyCheck != that.dependencyCheck) return false; if (!Arrays.equals(this.dependsOn, that.dependsOn)) return false; if (this.autowireCandidate != that.autowireCandidate) return false; if (!ObjectUtils.nullSafeEquals(this.qualifiers, that.qualifiers)) return false; if (this.primary != that.primary) return false; if (this.nonPublicAccessAllowed != that.nonPublicAccessAllowed) return false; if (this.lenientConstructorResolution != that.lenientConstructorResolution) return false; if (!ObjectUtils.nullSafeEquals(this.constructorArgumentValues, that.constructorArgumentValues)) return false; if (!ObjectUtils.nullSafeEquals(this.propertyValues, that.propertyValues)) return false; if (!ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides)) return false; if (!ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName)) return false; if (!ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName)) return false; if (!ObjectUtils.nullSafeEquals(this.initMethodName, that.initMethodName)) return false; if (this.enforceInitMethod != that.enforceInitMethod) return false; if (!ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName)) return false; if (this.enforceDestroyMethod != that.enforceDestroyMethod) return false; if (this.synthetic != that.synthetic) return false; if (this.role != that.role) return false; return super.equals(other); } @Override public int hashCode() { int hashCode = ObjectUtils.nullSafeHashCode(getBeanClassName()); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.scope); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.constructorArgumentValues); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.propertyValues); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryBeanName); hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryMethodName); hashCode = 29 * hashCode + super.hashCode(); return hashCode; } @Override public String toString() { StringBuilder sb = new StringBuilder("class ["); sb.append(getBeanClassName()).append("]"); sb.append("; scope=").append(this.scope); sb.append("; abstract=").append(this.abstractFlag); sb.append("; lazyInit=").append(this.lazyInit); sb.append("; autowireMode=").append(this.autowireMode); sb.append("; dependencyCheck=").append(this.dependencyCheck); sb.append("; autowireCandidate=").append(this.autowireCandidate); sb.append("; primary=").append(this.primary); sb.append("; factoryBeanName=").append(this.factoryBeanName); sb.append("; factoryMethodName=").append(this.factoryMethodName); sb.append("; initMethodName=").append(this.initMethodName); sb.append("; destroyMethodName=").append(this.destroyMethodName); if (this.resource != null) { sb.append("; defined in ").append(this.resource.getDescription()); } return sb.toString(); } }
四:注册解析的BeanDefinition
(1)BeanDefinitionReaderUtils 类
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.support; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** * Utility methods that are useful for bean definition reader implementations. * Mainly intended for internal use. * * @author Juergen Hoeller * @author Rob Harrop * @since 1.1 * @see PropertiesBeanDefinitionReader * @see org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader */ public class BeanDefinitionReaderUtils { /** * Separator for generated bean names. If a class name or parent name is not * unique, "#1", "#2" etc will be appended, until the name becomes unique. */ public static final String GENERATED_BEAN_NAME_SEPARATOR = BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR; /** * Create a new GenericBeanDefinition for the given parent name and class name, * eagerly loading the bean class if a ClassLoader has been specified. * @param parentName the name of the parent bean, if any * @param className the name of the bean class, if any * @param classLoader the ClassLoader to use for loading bean classes * (can be {@code null} to just register bean classes by name) * @return the bean definition * @throws ClassNotFoundException if the bean class could not be loaded */ public static AbstractBeanDefinition createBeanDefinition( String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setParentName(parentName); if (className != null) { if (classLoader != null) { bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else { bd.setBeanClassName(className); } } return bd; } /** * Generate a bean name for the given top-level bean definition, * unique within the given bean factory. * @param beanDefinition the bean definition to generate a bean name for * @param registry the bean factory that the definition is going to be * registered with (to check for existing bean names) * @return the generated bean name * @throws BeanDefinitionStoreException if no unique name can be generated * for the given bean definition * @see #generateBeanName(BeanDefinition, BeanDefinitionRegistry, boolean) */ public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { return generateBeanName(beanDefinition, registry, false); } /** * Generate a bean name for the given bean definition, unique within the * given bean factory. * @param definition the bean definition to generate a bean name for * @param registry the bean factory that the definition is going to be * registered with (to check for existing bean names) * @param isInnerBean whether the given bean definition will be registered * as inner bean or as top-level bean (allowing for special name generation * for inner beans versus top-level beans) * @return the generated bean name * @throws BeanDefinitionStoreException if no unique name can be generated * for the given bean definition */ public static String generateBeanName( BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) throws BeanDefinitionStoreException { String generatedBeanName = definition.getBeanClassName(); if (generatedBeanName == null) { if (definition.getParentName() != null) { generatedBeanName = definition.getParentName() + "$child"; } else if (definition.getFactoryBeanName() != null) { generatedBeanName = definition.getFactoryBeanName() + "$created"; } } if (!StringUtils.hasText(generatedBeanName)) { throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " + "'class' nor 'parent' nor 'factory-bean' - can't generate bean name"); } String id = generatedBeanName; if (isInnerBean) { // Inner bean: generate identity hashcode suffix. id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition); } else { // Top-level bean: use plain class name. // Increase counter until the id is unique. int counter = -1; while (counter == -1 || registry.containsBeanDefinition(id)) { counter++; id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter; } } return id; } /** * Register the given bean definition with the given bean factory. * @param definitionHolder the bean definition including name and aliases * @param registry the bean factory to register with * @throws BeanDefinitionStoreException if registration failed */ public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } } /** * Register the given bean definition with a generated name, * unique within the given bean factory. * @param definition the bean definition to generate a bean name for * @param registry the bean factory to register with * @return the generated bean name * @throws BeanDefinitionStoreException if no unique name can be generated * for the given bean definition or the definition cannot be registered */ public static String registerWithGeneratedName( AbstractBeanDefinition definition, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String generatedName = generateBeanName(definition, registry, false); registry.registerBeanDefinition(generatedName, definition); return generatedName; } }
(2)DefaultListableBeanFactory 类
复制代码
1
复制代码
1public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry interface //--------------------------------------------------------------------- @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition oldBeanDefinition; oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(oldBeanDefinition)) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
}
转载于:https://www.cnblogs.com/fdzfd/p/8437018.html
最后
以上就是潇洒百合最近收集整理的关于Spring 源码分析(三)--默认标签的解析的全部内容,更多相关Spring内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复