step.html 156.1 KB
Newer Older
茶陵後's avatar
茶陵後 已提交
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
<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Configuring a Step | Spring Docs</title>
    <meta name="generator" content="VuePress 1.9.7">
    <link rel="icon" type="image/png" sizes="16x16" href="/images/icons/favicon.ico">
    <link rel="icon" type="image/png" sizes="48x48" href="/images/icons/icon-48x48.png">
    <link rel="icon" type="image/png" sizes="72x72" href="/images/icons/icon-72x72.png">
    <link rel="manifest" href="/manifest.webmanifest">
    <link rel="apple-touch-icon" href="/images/icons/icon_48x48.png">
    <link rel="mask-icon" href="/images/icons/favicon.ico" color="#5dac38">
    <script>
    var _hmt = _hmt || [];
    (function () {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?8eefd6b163dcb3f5762af6b0825e2dd1";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
    </script>
    <meta name="description" content="XMLJavaBoth">
    <meta name="image" content="https://docs.spring.io/spring-batch/docs/current/reference/html/images/step.png">
    <meta name="twitter:title" content="Configuring a Step">
    <meta name="twitter:description" content="XMLJavaBoth">
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:image" content="https://docs.spring.io/spring-batch/docs/current/reference/html/images/step.png">
    <meta name="twitter:url" content="https://spring.gitcode.net/en/spring-batch/step.html">
    <meta property="og:type" content="article">
    <meta property="og:title" content="Configuring a Step">
    <meta property="og:description" content="XMLJavaBoth">
    <meta property="og:image" content="https://docs.spring.io/spring-batch/docs/current/reference/html/images/step.png">
    <meta property="og:url" content="https://spring.gitcode.net/en/spring-batch/step.html">
    <meta property="og:site_name" content="Spring 中文文档社区">
    <meta itemprop="name" content="Configuring a Step">
    <meta itemprop="description" content="XMLJavaBoth">
    <meta itemprop="image" content="https://docs.spring.io/spring-batch/docs/current/reference/html/images/step.png">
    <meta name="application-name" content="Spring 中文文档社区">
    <meta name="apple-mobile-web-app-title" content="Spring 中文社区">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="msapplication-TileColor" content="#5dac38">
    <meta name="theme-color" content="#5dac38">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="baidu-site-verification" content="code-tApgxyb9G8">
    
    <link rel="preload" href="/assets/css/0.styles.af3770e9.css" as="style"><link rel="preload" href="/assets/js/app.cf11b18e.js" as="script"><link rel="preload" href="/assets/js/3.50918073.js" as="script"><link rel="preload" href="/assets/js/4.cd4c3ff4.js" as="script"><link rel="preload" href="/assets/js/38.23e83578.js" as="script"><link rel="prefetch" href="/assets/js/10.675f4d7e.js"><link rel="prefetch" href="/assets/js/100.89ddf0f9.js"><link rel="prefetch" href="/assets/js/101.a2584c55.js"><link rel="prefetch" href="/assets/js/102.53225958.js"><link rel="prefetch" href="/assets/js/103.be06048d.js"><link rel="prefetch" href="/assets/js/104.a2328e06.js"><link rel="prefetch" href="/assets/js/105.78529341.js"><link rel="prefetch" href="/assets/js/106.fc779386.js"><link rel="prefetch" href="/assets/js/107.375c8dec.js"><link rel="prefetch" href="/assets/js/108.cf4ca7e2.js"><link rel="prefetch" href="/assets/js/109.f4d3964d.js"><link rel="prefetch" href="/assets/js/11.b58e279a.js"><link rel="prefetch" href="/assets/js/110.4ae56c4d.js"><link rel="prefetch" href="/assets/js/111.baf7121d.js"><link rel="prefetch" href="/assets/js/112.a963ade8.js"><link rel="prefetch" href="/assets/js/113.edbb458c.js"><link rel="prefetch" href="/assets/js/114.7e2b354f.js"><link rel="prefetch" href="/assets/js/115.4e41285c.js"><link rel="prefetch" href="/assets/js/116.1ee84ed6.js"><link rel="prefetch" href="/assets/js/117.4952cce2.js"><link rel="prefetch" href="/assets/js/118.306eabfa.js"><link rel="prefetch" href="/assets/js/119.5a4712e9.js"><link rel="prefetch" href="/assets/js/12.c41ab7bc.js"><link rel="prefetch" href="/assets/js/120.496c9660.js"><link rel="prefetch" href="/assets/js/121.e4a22135.js"><link rel="prefetch" href="/assets/js/122.02f82a94.js"><link rel="prefetch" href="/assets/js/123.53c5a24e.js"><link rel="prefetch" href="/assets/js/124.11d8be3e.js"><link rel="prefetch" href="/assets/js/125.c0740874.js"><link rel="prefetch" href="/assets/js/126.9cb2911c.js"><link rel="prefetch" href="/assets/js/127.6f87a638.js"><link rel="prefetch" href="/assets/js/128.456206df.js"><link rel="prefetch" href="/assets/js/129.ce51dc7d.js"><link rel="prefetch" href="/assets/js/13.1147a447.js"><link rel="prefetch" href="/assets/js/130.66718f4c.js"><link rel="prefetch" href="/assets/js/131.713226b7.js"><link rel="prefetch" href="/assets/js/132.6e2b68e3.js"><link rel="prefetch" href="/assets/js/133.11148e38.js"><link rel="prefetch" href="/assets/js/134.8de25763.js"><link rel="prefetch" href="/assets/js/135.961f6693.js"><link rel="prefetch" href="/assets/js/136.8abc4532.js"><link rel="prefetch" href="/assets/js/137.331bfb6b.js"><link rel="prefetch" href="/assets/js/138.f76ee7b9.js"><link rel="prefetch" href="/assets/js/139.578aa70e.js"><link rel="prefetch" href="/assets/js/14.1c437f54.js"><link rel="prefetch" href="/assets/js/140.9f1f28a0.js"><link rel="prefetch" href="/assets/js/141.b08ac1ec.js"><link rel="prefetch" href="/assets/js/142.e5c934cf.js"><link rel="prefetch" href="/assets/js/143.2a9d47c6.js"><link rel="prefetch" href="/assets/js/144.76090f65.js"><link rel="prefetch" href="/assets/js/145.41a54d41.js"><link rel="prefetch" href="/assets/js/146.979b34c1.js"><link rel="prefetch" href="/assets/js/147.46e366af.js"><link rel="prefetch" href="/assets/js/148.efcd2b17.js"><link rel="prefetch" href="/assets/js/149.04135c0b.js"><link rel="prefetch" href="/assets/js/15.cbd21f6a.js"><link rel="prefetch" href="/assets/js/150.679d76bf.js"><link rel="prefetch" href="/assets/js/151.2b0748da.js"><link rel="prefetch" href="/assets/js/152.cee5bbcd.js"><link rel="prefetch" href="/assets/js/153.680b4156.js"><link rel="prefetch" href="/assets/js/154.0c6972fe.js"><link rel="prefetch" href="/assets/js/155.35a3e5ab.js"><link rel="prefetch" href="/assets/js/156.6782d874.js"><link rel="prefetch" href="/assets/js/157.b9fe2583.js"><link rel="prefetch" href="/assets/js/158.96656194.js"><link rel="prefetch" href="/assets/js/159.2a0f7744.js"><link rel="prefetch" href="/assets/js/16.0cc4679e.js"><link rel="prefetch" href="/assets/js/160.c26bf909.js"><link rel="prefetch" href="/assets/js/161.45a3950a.js"><link rel="prefetch" href="/assets/js/162.4a08c069.js"><link rel="prefetch" href="/assets/js/163.a540d00c.js"><link rel="prefetch" href="/assets/js/164.117eb7b8.js"><link rel="prefetch" href="/assets/js/165.4fabe2ea.js"><link rel="prefetch" href="/assets/js/166.27d3bfe9.js"><link rel="prefetch" href="/assets/js/167.c8a74627.js"><link rel="prefetch" href="/assets/js/168.e16111b9.js"><link rel="prefetch" href="/assets/js/169.458ea1d8.js"><link rel="prefetch" href="/assets/js/17.d3f5977b.js"><link rel="prefetch" href="/assets/js/170.4b38adcf.js"><link rel="prefetch" href="/assets/js/171.98cb45b7.js"><link rel="prefetch" href="/assets/js/172.9ca2eb1a.js"><link rel="prefetch" href="/assets/js/173.14074c7f.js"><link rel="prefetch" href="/assets/js/174.8e1f9887.js"><link rel="prefetch" href="/assets/js/175.5989a4ca.js"><link rel="prefetch" href="/assets/js/176.89b35f24.js"><link rel="prefetch" href="/assets/js/177.8ca04666.js"><link rel="prefetch" href="/assets/js/178.f1f78ad5.js"><link rel="prefetch" href="/assets/js/179.a1faadfe.js"><link rel="prefetch" href="/assets/js/18.1a2bbade.js"><link rel="prefetch" href="/assets/js/180.33be0a0d.js"><link rel="prefetch" href="/assets/js/181.074198fc.js"><link rel="prefetch" href="/assets/js/182.2ea92f58.js"><link rel="prefetch" href="/assets/js/183.316f0529.js"><link rel="prefetch" href="/assets/js/184.f6dd5f36.js"><link rel="prefetch" href="/assets/js/185.134f1457.js"><link rel="prefetch" href="/assets/js/186.2aa74077.js"><link rel="prefetch" href="/assets/js/187.3a956aba.js"><link rel="prefetch" href="/assets/js/188.01a6573f.js"><link rel="prefetch" href="/assets/js/189.a8d65b4d.js"><link rel="prefetch" href="/assets/js/19.e062ea88.js"><link rel="prefetch" href="/assets/js/190.c753d8e3.js"><link rel="prefetch" href="/assets/js/191.280fe1e2.js"><link rel="prefetch" href="/assets/js/192.bbc94e32.js"><link rel="prefetch" href="/assets/js/193.41421d14.js"><link rel="prefetch" href="/assets/js/194.15f508e4.js"><link rel="prefetch" href="/assets/js/195.a17f3877.js"><link rel="prefetch" href="/assets/js/196.d17bfcdf.js"><link rel="prefetch" href="/assets/js/197.65791a5a.js"><link rel="prefetch" href="/assets/js/198.0441041e.js"><link rel="prefetch" href="/assets/js/199.538f2285.js"><link rel="prefetch" href="/assets/js/20.6c49f026.js"><link rel="prefetch" href="/assets/js/200.4ff8dbc4.js"><link rel="prefetch" href="/assets/js/201.088ccf86.js"><link rel="prefetch" href="/assets/js/202.8bdad311.js"><link rel="prefetch" href="/assets/js/203.45d3ecc5.js"><link rel="prefetch" href="/assets/js/204.c403aa39.js"><link rel="prefetch" href="/assets/js/205.e992b689.js"><link rel="prefetch" href="/assets/js/206.eed8bd42.js"><link rel="prefetch" href="/assets/js/207.3db1fc87.js"><link rel="prefetch" href="/assets/js/208.27399a7b.js"><link rel="prefetch" href="/assets/js/209.829f007c.js"><link rel="prefetch" href="/assets/js/21.0ed0e55b.js"><link rel="prefetch" href="/assets/js/210.35079683.js"><link rel="prefetch" href="/assets/js/211.94056191.js"><link rel="prefetch" href="/assets/js/212.431059ab.js"><link rel="prefetch" href="/assets/js/213.4d25e21f.js"><link rel="prefetch" href="/assets/js/214.e62f8fc5.js"><link rel="prefetch" href="/assets/js/215.433d7113.js"><link rel="prefetch" href="/assets/js/216.6de56c4d.js"><link rel="prefetch" href="/assets/js/217.ad3e1cd0.js"><link rel="prefetch" href="/assets/js/218.c225521d.js"><link rel="prefetch" href="/assets/js/219.f4241738.js"><link rel="prefetch" href="/assets/js/22.3563c6e0.js"><link rel="prefetch" href="/assets/js/220.ac9c6899.js"><link rel="prefetch" href="/assets/js/221.ff4ee0d2.js"><link rel="prefetch" href="/assets/js/222.20629300.js"><link rel="prefetch" href="/assets/js/223.a5fa0166.js"><link rel="prefetch" href="/assets/js/224.65290c4f.js"><link rel="prefetch" href="/assets/js/225.e698f717.js"><link rel="prefetch" href="/assets/js/226.4b28f10d.js"><link rel="prefetch" href="/assets/js/227.f44065ae.js"><link rel="prefetch" href="/assets/js/228.0b254d68.js"><link rel="prefetch" href="/assets/js/229.560ccb5c.js"><link rel="prefetch" href="/assets/js/23.2bc6a9e3.js"><link rel="prefetch" href="/assets/js/230.2e09449c.js"><link rel="prefetch" href="/assets/js/231.b09e3f00.js"><link rel="prefetch" href="/assets/js/232.eaa54385.js"><link rel="prefetch" href="/assets/js/233.36843a48.js"><link rel="prefetch" href="/assets/js/234.1e3e41c7.js"><link rel="prefetch" href="/assets/js/235.2dff4846.js"><link rel="prefetch" href="/assets/js/236.bb6fd980.js"><link rel="prefetch" href="/assets/js/237.e97364da.js"><link rel="prefetch" href="/assets/js/238.d8ce22f3.js"><link rel="prefetch" href="/assets/js/239.be791e5e.js"><link rel="prefetch" href="/assets/js/24.4b60795e.js"><link rel="prefetch" href="/assets/js/240.3927116f.js"><link rel="prefetch" href="/assets/js/241.6539a7f9.js"><link rel="prefetch" href="/assets/js/242.1241e424.js"><link rel="prefetch" href="/assets/js/243.a07d3be3.js"><link rel="prefetch" href="/assets/js/244.f98f98a1.js"><link rel="prefetch" href="/assets/js/245.ecb7c922.js"><link rel="prefetch" href="/assets/js/246.95ed23ce.js"><link rel="prefetch" href="/assets/js/247.fb5d42c6.js"><link rel="prefetch" href="/assets/js/248.f7b4f364.js"><link rel="prefetch" href="/assets/js/249.ac22d922.js"><link rel="prefetch" href="/assets/js/25.ef18cc01.js"><link rel="prefetch" href="/assets/js/250.01fbf76b.js"><link rel="prefetch" href="/assets/js/251.08f19bbd.js"><link rel="prefetch" href="/assets/js/252.9f11061d.js"><link rel="prefetch" href="/assets/js/253.cd7f85b9.js"><link rel="prefetch" href="/assets/js/254.2493e550.js"><link rel="prefetch" href="/assets/js/255.ac6d41ee.js"><link rel="prefetch" href="/assets/js/256.068eb5a6.js"><link rel="prefetch" href="/assets/js/257.b108c715.js"><link rel="prefetch" href="/assets/js/258.d614b5d4.js"><link rel="prefetch" href="/assets/js/259.87ba5ef3.js"><link rel="prefetch" href="/assets/js/26.5baa4d2c.js"><link rel="prefetch" href="/assets/js/260.c771e39d.js"><link rel="prefetch" href="/assets/js/261.0dbaf460.js"><link rel="prefetch" href="/assets/js/262.35e64a26.js"><link rel="prefetch" href="/assets/js/263.c16fca32.js"><link rel="prefetch" href="/assets/js/264.ea414912.js"><link rel="prefetch" href="/assets/js/265.f2e0d5bb.js"><link rel="prefetch" href="/assets/js/266.629a2d15.js"><link rel="prefetch" href="/assets/js/267.c7332e80.js"><link rel="prefetch" href="/assets/js/268.8be99f76.js"><link rel="prefetch" href="/assets/js/269.452ff2d4.js"><link rel="prefetch" href="/assets/js/27.2a2950d8.js"><link rel="prefetch" href="/assets/js/270.a5c429cb.js"><link rel="prefetch" href="/assets/js/271.1ad3cd83.js"><link rel="prefetch" href="/assets/js/272.354cef59.js"><link rel="prefetch" href="/assets/js/273.681156b7.js"><link rel="prefetch" href="/assets/js/274.6c51e7ae.js"><link rel="prefetch" href="/assets/js/275.24ef01b4.js"><link rel="prefetch" href="/assets/js/276.afeb2acd.js"><link rel="prefetch" href="/assets/js/277.6472c22d.js"><link rel="prefetch" href="/assets/js/278.416d9788.js"><link rel="prefetch" href="/assets/js/279.c190fbc9.js"><link rel="prefetch" href="/assets/js/28.6320d8c1.js"><link rel="prefetch" href="/assets/js/280.28b1b955.js"><link rel="prefetch" href="/assets/js/281.77afd7c5.js"><link rel="prefetch" href="/assets/js/282.eee0e9c0.js"><link rel="prefetch" href="/assets/js/283.e59fb0e5.js"><link rel="prefetch" href="/assets/js/284.9c6ff275.js"><link rel="prefetch" href="/assets/js/285.3e2d030a.js"><link rel="prefetch" href="/assets/js/286.d7562f9b.js"><link rel="prefetch" href="/assets/js/287.9e228e80.js"><link rel="prefetch" href="/assets/js/288.f9448d7d.js"><link rel="prefetch" href="/assets/js/289.30726f95.js"><link rel="prefetch" href="/assets/js/29.a420635f.js"><link rel="prefetch" href="/assets/js/290.f79765e2.js"><link rel="prefetch" href="/assets/js/291.0943618c.js"><link rel="prefetch" href="/assets/js/292.bd04f6db.js"><link rel="prefetch" href="/assets/js/293.776f4c0d.js"><link rel="prefetch" href="/assets/js/294.54e52863.js"><link rel="prefetch" href="/assets/js/295.bd033d69.js"><link rel="prefetch" href="/assets/js/296.1090c539.js"><link rel="prefetch" href="/assets/js/297.ec37f6e8.js"><link rel="prefetch" href="/assets/js/298.fa434214.js"><link rel="prefetch" href="/assets/js/299.50bd7c87.js"><link rel="prefetch" href="/assets/js/30.6c81ca7b.js"><link rel="prefetch" href="/assets/js/300.7a2c6632.js"><link rel="prefetch" href="/assets/js/301.4ae4e645.js"><link rel="prefetch" href="/assets/js/302.e1ef7459.js"><link rel="prefetch" href="/assets/js/303.3894068b.js"><link rel="prefetch" href="/assets/js/304.840b09e3.js"><link rel="prefetch" href="/assets/js/305.40ec0bf6.js"><link rel="prefetch" href="/assets/js/306.9fa4d8aa.js"><link rel="prefetch" href="/assets/js/307.33656e76.js"><link rel="prefetch" href="/assets/js/308.19398f71.js"><link rel="prefetch" href="/assets/js/309.bde6f12f.js"><link rel="prefetch" href="/assets/js/31.2b4f2752.js"><link rel="prefetch" href="/assets/js/310.69ced632.js"><link rel="prefetch" href="/assets/js/311.c8e57d0e.js"><link rel="prefetch" href="/assets/js/312.80c4d6a7.js"><link rel="prefetch" href="/assets/js/313.14060a06.js"><link rel="prefetch" href="/assets/js/314.29165d83.js"><link rel="prefetch" href="/assets/js/315.901aabf1.js"><link rel="prefetch" href="/assets/js/316.7f0d18e3.js"><link rel="prefetch" href="/assets/js/317.112de6ec.js"><link rel="prefetch" href="/assets/js/318.091ea533.js"><link rel="prefetch" href="/assets/js/319.25ca175e.js"><link rel="prefetch" href="/assets/js/32.ab03e16f.js"><link rel="prefetch" href="/assets/js/320.b89e85c9.js"><link rel="prefetch" href="/assets/js/321.69316136.js"><link rel="prefetch" href="/assets/js/322.567512f0.js"><link rel="prefetch" href="/assets/js/323.2d67bb75.js"><link rel="prefetch" href="/assets/js/324.c41411db.js"><link rel="prefetch" href="/assets/js/325.a412ca77.js"><link rel="prefetch" href="/assets/js/326.22408ce6.js"><link rel="prefetch" href="/assets/js/327.33524443.js"><link rel="prefetch" href="/assets/js/328.561ebeb1.js"><link rel="prefetch" href="/assets/js/329.d7a280e4.js"><link rel="prefetch" href="/assets/js/33.199f45ed.js"><link rel="prefetch" href="/assets/js/330.d01a7e1b.js"><link rel="prefetch" href="/assets/js/331.a3ad2556.js"><link rel="prefetch" href="/assets/js/332.36ad912a.js"><link rel="prefetch" href="/assets/js/333.2fb229c4.js"><link rel="prefetch" href="/assets/js/334.d170f507.js"><link rel="prefetch" href="/assets/js/335.90ca0539.js"><link rel="prefetch" href="/assets/js/336.454d4374.js"><link rel="prefetch" href="/assets/js/337.dba45eb4.js"><link rel="prefetch" href="/assets/js/338.c8e4ba66.js"><link rel="prefetch" href="/assets/js/339.ae85118e.js"><link rel="prefetch" href="/assets/js/34.d0c7a02e.js"><link rel="prefetch" href="/assets/js/340.7033b85b.js"><link rel="prefetch" href="/assets/js/341.13cfe1aa.js"><link rel="prefetch" href="/assets/js/342.b33302b5.js"><link rel="prefetch" href="/assets/js/343.946f30dc.js"><link rel="prefetch" href="/assets/js/344.b2add405.js"><link rel="prefetch" href="/assets/js/345.12433fa3.js"><link rel="prefetch" href="/assets/js/346.b1bdfeba.js"><link rel="prefetch" href="/assets/js/347.53530bff.js"><link rel="prefetch" href="/assets/js/348.48aa580e.js"><link rel="prefetch" href="/assets/js/349.53c4baca.js"><link rel="prefetch" href="/assets/js/35.5512348f.js"><link rel="prefetch" href="/assets/js/350.e4b2d6e6.js"><link rel="prefetch" href="/assets/js/351.d41b01c1.js"><link rel="prefetch" href="/assets/js/352.1c4d1250.js"><link rel="prefetch" href="/assets/js/353.7fd27c0f.js"><link rel="prefetch" href="/assets/js/354.47199c90.js"><link rel="prefetch" href="/assets/js/355.68bccab4.js"><link rel="prefetch" href="/assets/js/356.e3602eb5.js"><link rel="prefetch" href="/assets/js/357.cd5ce764.js"><link rel="prefetch" href="/assets/js/358.bee621d4.js"><link rel="prefetch" href="/assets/js/359.648aa4f0.js"><link rel="prefetch" href="/assets/js/36.bdebdf29.js"><link rel="prefetch" href="/assets/js/360.439f5fae.js"><link rel="prefetch" href="/assets/js/361.39f782b4.js"><link rel="prefetch" href="/assets/js/362.106acf4c.js"><link rel="prefetch" href="/assets/js/363.562a4e1e.js"><link rel="prefetch" href="/assets/js/364.5940b069.js"><link rel="prefetch" href="/assets/js/365.e429c365.js"><link rel="prefetch" href="/assets/js/366.cc650df8.js"><link rel="prefetch" href="/assets/js/367.347592c9.js"><link rel="prefetch" href="/assets/js/368.d68ce88d.js"><link rel="prefetch" href="/assets/js/369.034e7f1e.js"><link rel="prefetch" href="/assets/js/37.9d026956.js"><link rel="prefetch" href="/assets/js/370.ac6fc7a5.js"><link rel="prefetch" href="/assets/js/371.e70219a6.js"><link rel="prefetch" href="/assets/js/372.c449fc49.js"><link rel="prefetch" href="/assets/js/373.f07bea72.js"><link rel="prefetch" href="/assets/js/374.8152408f.js"><link rel="prefetch" href="/assets/js/375.63c70dab.js"><link rel="prefetch" href="/assets/js/376.06de19db.js"><link rel="prefetch" href="/assets/js/377.2319ddb1.js"><link rel="prefetch" href="/assets/js/378.4821e23c.js"><link rel="prefetch" href="/assets/js/379.54a13769.js"><link rel="prefetch" href="/assets/js/380.dac4cd46.js"><link rel="prefetch" href="/assets/js/381.8f83d1d7.js"><link rel="prefetch" href="/assets/js/382.e76e7d88.js"><link rel="prefetch" href="/assets/js/383.df731ee4.js"><link rel="prefetch" href="/assets/js/384.5093369e.js"><link rel="prefetch" href="/assets/js/385.ee576341.js"><link rel="prefetch" href="/assets/js/386.087a29a9.js"><link rel="prefetch" href="/assets/js/387.9f44d03b.js"><link rel="prefetch" href="/assets/js/388.a3f70992.js"><link rel="prefetch" href="/assets/js/389.df6e2ced.js"><link rel="prefetch" href="/assets/js/39.e9699d7f.js"><link rel="prefetch" href="/assets/js/390.c377efca.js"><link rel="prefetch" href="/assets/js/391.d7747385.js"><link rel="prefetch" href="/assets/js/392.bf8e8c1a.js"><link rel="prefetch" href="/assets/js/393.b4ed3be0.js"><link rel="prefetch" href="/assets/js/394.48eb505a.js"><link rel="prefetch" href="/assets/js/395.d9cd4812.js"><link rel="prefetch" href="/assets/js/396.b386a6b5.js"><link rel="prefetch" href="/assets/js/397.d19960fa.js"><link rel="prefetch" href="/assets/js/398.15f66e2a.js"><link rel="prefetch" href="/assets/js/399.cc4af83b.js"><link rel="prefetch" href="/assets/js/40.3a541653.js"><link rel="prefetch" href="/assets/js/400.d99e4b93.js"><link rel="prefetch" href="/assets/js/401.13fa06dd.js"><link rel="prefetch" href="/assets/js/402.3629b866.js"><link rel="prefetch" href="/assets/js/403.5826b040.js"><link rel="prefetch" href="/assets/js/404.d4b35549.js"><link rel="prefetch" href="/assets/js/405.9142a002.js"><link rel="prefetch" href="/assets/js/406.ba50e04d.js"><link rel="prefetch" href="/assets/js/407.b5271c6f.js"><link rel="prefetch" href="/assets/js/408.18baa241.js"><link rel="prefetch" href="/assets/js/409.6151d46b.js"><link rel="prefetch" href="/assets/js/41.b10ef41f.js"><link rel="prefetch" href="/assets/js/410.bb1fd058.js"><link rel="prefetch" href="/assets/js/411.9273fd47.js"><link rel="prefetch" href="/assets/js/412.d6b790c1.js"><link rel="prefetch" href="/assets/js/413.4c5a30bb.js"><link rel="prefetch" href="/assets/js/414.01aa0e0a.js"><link rel="prefetch" href="/assets/js/415.2633ad61.js"><link rel="prefetch" href="/assets/js/416.7a2263a9.js"><link rel="prefetch" href="/assets/js/417.98368241.js"><link rel="prefetch" href="/assets/js/418.ffeb9c9c.js"><link rel="prefetch" href="/assets/js/419.633f9efe.js"><link rel="prefetch" href="/assets/js/42.aa8b7c99.js"><link rel="prefetch" href="/assets/js/420.69868f4a.js"><link rel="prefetch" href="/assets/js/421.937d87cc.js"><link rel="prefetch" href="/assets/js/422.375fe09b.js"><link rel="prefetch" href="/assets/js/423.8d335fd6.js"><link rel="prefetch" href="/assets/js/424.d5b181d7.js"><link rel="prefetch" href="/assets/js/425.e06749ea.js"><link rel="prefetch" href="/assets/js/426.d7a23361.js"><link rel="prefetch" href="/assets/js/427.c26079c3.js"><link rel="prefetch" href="/assets/js/428.788e60b3.js"><link rel="prefetch" href="/assets/js/429.212c3091.js"><link rel="prefetch" href="/assets/js/43.bbf1f09a.js"><link rel="prefetch" href="/assets/js/430.e156b1fa.js"><link rel="prefetch" href="/assets/js/431.b41e44c6.js"><link rel="prefetch" href="/assets/js/432.7534e280.js"><link rel="prefetch" href="/assets/js/433.3d203e2b.js"><link rel="prefetch" href="/assets/js/434.41bb5350.js"><link rel="prefetch" href="/assets/js/435.a5c93fd3.js"><link rel="prefetch" href="/assets/js/436.60910866.js"><link rel="prefetch" href="/assets/js/437.7ae74f40.js"><link rel="prefetch" href="/assets/js/438.dc802af3.js"><link rel="prefetch" href="/assets/js/439.0de7c2a4.js"><link rel="prefetch" href="/assets/js/44.c0079627.js"><link rel="prefetch" href="/assets/js/440.43bc725f.js"><link rel="prefetch" href="/assets/js/441.1402dd2a.js"><link rel="prefetch" href="/assets/js/442.6106e1be.js"><link rel="prefetch" href="/assets/js/443.40909ac7.js"><link rel="prefetch" href="/assets/js/444.e506898d.js"><link rel="prefetch" href="/assets/js/445.8636f7a3.js"><link rel="prefetch" href="/assets/js/446.de915ed4.js"><link rel="prefetch" href="/assets/js/447.c7ac8e6e.js"><link rel="prefetch" href="/assets/js/448.9797a750.js"><link rel="prefetch" href="/assets/js/449.5d1f4748.js"><link rel="prefetch" href="/assets/js/45.2a09d581.js"><link rel="prefetch" href="/assets/js/450.42babefe.js"><link rel="prefetch" href="/assets/js/451.ee1b8ff8.js"><link rel="prefetch" href="/assets/js/452.7536e7c2.js"><link rel="prefetch" href="/assets/js/453.39a21d52.js"><link rel="prefetch" href="/assets/js/454.6511d1e1.js"><link rel="prefetch" href="/assets/js/455.2abb8ea0.js"><link rel="prefetch" href="/assets/js/456.5724d799.js"><link rel="prefetch" href="/assets/js/457.c32c0755.js"><link rel="prefetch" href="/assets/js/458.f67c539b.js"><link rel="prefetch" href="/assets/js/459.1634e8da.js"><link rel="prefetch" href="/assets/js/46.58b302e4.js"><link rel="prefetch" href="/assets/js/460.a22ac002.js"><link rel="prefetch" href="/assets/js/461.2c152148.js"><link rel="prefetch" href="/assets/js/462.14b038cf.js"><link rel="prefetch" href="/assets/js/463.dd0a3a00.js"><link rel="prefetch" href="/assets/js/464.f22ba288.js"><link rel="prefetch" href="/assets/js/465.9c187041.js"><link rel="prefetch" href="/assets/js/466.9957dd67.js"><link rel="prefetch" href="/assets/js/467.047041e8.js"><link rel="prefetch" href="/assets/js/468.425b6f20.js"><link rel="prefetch" href="/assets/js/469.2f70ecf7.js"><link rel="prefetch" href="/assets/js/47.987d79be.js"><link rel="prefetch" href="/assets/js/470.602b7d98.js"><link rel="prefetch" href="/assets/js/471.ddabe1b6.js"><link rel="prefetch" href="/assets/js/472.3a1ad521.js"><link rel="prefetch" href="/assets/js/473.2be352ab.js"><link rel="prefetch" href="/assets/js/474.e9c805de.js"><link rel="prefetch" href="/assets/js/475.93cab6cb.js"><link rel="prefetch" href="/assets/js/476.89384fa4.js"><link rel="prefetch" href="/assets/js/477.2b282ee8.js"><link rel="prefetch" href="/assets/js/478.27790491.js"><link rel="prefetch" href="/assets/js/479.2b728ba6.js"><link rel="prefetch" href="/assets/js/48.0e76d761.js"><link rel="prefetch" href="/assets/js/480.bd0beea9.js"><link rel="prefetch" href="/assets/js/481.004a0005.js"><link rel="prefetch" href="/assets/js/482.d9c6dc45.js"><link rel="prefetch" href="/assets/js/483.e7842361.js"><link rel="prefetch" href="/assets/js/484.702ac9a3.js"><link rel="prefetch" href="/assets/js/485.d38ba4c2.js"><link rel="prefetch" href="/assets/js/486.8a0cd211.js"><link rel="prefetch" href="/assets/js/487.18e243bb.js"><link rel="prefetch" href="/assets/js/488.cb0ad1bf.js"><link rel="prefetch" href="/assets/js/489.7c7adc5c.js"><link rel="prefetch" href="/assets/js/49.83e0619b.js"><link rel="prefetch" href="/assets/js/490.3f86a6a4.js"><link rel="prefetch" href="/assets/js/491.c1c90b4f.js"><link rel="prefetch" href="/assets/js/492.5658313d.js"><link rel="prefetch" href="/assets/js/493.9b953b18.js"><link rel="prefetch" href="/assets/js/494.80e3d4f4.js"><link rel="prefetch" href="/assets/js/495.66650a67.js"><link rel="prefetch" href="/assets/js/496.4e0d753b.js"><link rel="prefetch" href="/assets/js/497.1837b7c2.js"><link rel="prefetch" href="/assets/js/498.e2dcd450.js"><link rel="prefetch" href="/assets/js/499.4d5022f2.js"><link rel="prefetch" href="/assets/js/5.f343fd5d.js"><link rel="prefetch" href="/assets/js/50.6716fe91.js"><link rel="prefetch" href="/assets/js/500.10c0ee69.js"><link rel="prefetch" href="/assets/js/501.be3f9599.js"><link rel="prefetch" href="/assets/js/502.27844894.js"><link rel="prefetch" href="/assets/js/503.15f84a9b.js"><link rel="prefetch" href="/assets/js/504.60780a8e.js"><link rel="prefetch" href="/assets/js/505.6f9bed41.js"><link rel="prefetch" href="/assets/js/506.3e19b413.js"><link rel="prefetch" href="/assets/js/507.a12a02cb.js"><link rel="prefetch" href="/assets/js/508.b1384524.js"><link rel="prefetch" href="/assets/js/509.c74ef6c0.js"><link rel="prefetch" href="/assets/js/51.bc8d5aaf.js"><link rel="prefetch" href="/assets/js/510.266a6048.js"><link rel="prefetch" href="/assets/js/511.be98a2ef.js"><link rel="prefetch" href="/assets/js/512.e033e89e.js"><link rel="prefetch" href="/assets/js/513.837b9052.js"><link rel="prefetch" href="/assets/js/514.38271d19.js"><link rel="prefetch" href="/assets/js/515.c08327b5.js"><link rel="prefetch" href="/assets/js/516.3d573fdf.js"><link rel="prefetch" href="/assets/js/517.5406a8bd.js"><link rel="prefetch" href="/assets/js/518.543bea6f.js"><link rel="prefetch" href="/assets/js/519.e4967ce6.js"><link rel="prefetch" href="/assets/js/52.20603f07.js"><link rel="prefetch" href="/assets/js/520.0a863135.js"><link rel="prefetch" href="/assets/js/521.80c26149.js"><link rel="prefetch" href="/assets/js/522.5d0549ee.js"><link rel="prefetch" href="/assets/js/523.4b5d705c.js"><link rel="prefetch" href="/assets/js/524.24354cd8.js"><link rel="prefetch" href="/assets/js/525.d201b688.js"><link rel="prefetch" href="/assets/js/526.f405c35a.js"><link rel="prefetch" href="/assets/js/527.921d252f.js"><link rel="prefetch" href="/assets/js/528.cb45a5dd.js"><link rel="prefetch" href="/assets/js/529.aeec69e2.js"><link rel="prefetch" href="/assets/js/53.9604c447.js"><link rel="prefetch" href="/assets/js/530.7d5514c0.js"><link rel="prefetch" href="/assets/js/531.de381ab2.js"><link rel="prefetch" href="/assets/js/532.31b6e993.js"><link rel="prefetch" href="/assets/js/533.23335bff.js"><link rel="prefetch" href="/assets/js/534.131d260d.js"><link rel="prefetch" href="/assets/js/535.3057e7f2.js"><link rel="prefetch" href="/assets/js/536.1df4cc6e.js"><link rel="prefetch" href="/assets/js/537.c23a3391.js"><link rel="prefetch" href="/assets/js/538.ac3546d3.js"><link rel="prefetch" href="/assets/js/539.36137525.js"><link rel="prefetch" href="/assets/js/54.841e8e8f.js"><link rel="prefetch" href="/assets/js/540.f9171241.js"><link rel="prefetch" href="/assets/js/541.00a9732f.js"><link rel="prefetch" href="/assets/js/542.d981dcf7.js"><link rel="prefetch" href="/assets/js/543.0016cdef.js"><link rel="prefetch" href="/assets/js/544.b24fa17d.js"><link rel="prefetch" href="/assets/js/545.8adcd15c.js"><link rel="prefetch" href="/assets/js/546.189f10ef.js"><link rel="prefetch" href="/assets/js/547.d47175ac.js"><link rel="prefetch" href="/assets/js/548.67ed7a21.js"><link rel="prefetch" href="/assets/js/549.a72c957e.js"><link rel="prefetch" href="/assets/js/55.eccc64f8.js"><link rel="prefetch" href="/assets/js/550.c127415f.js"><link rel="prefetch" href="/assets/js/551.288648b2.js"><link rel="prefetch" href="/assets/js/552.5191109c.js"><link rel="prefetch" href="/assets/js/553.a0417c79.js"><link rel="prefetch" href="/assets/js/554.05224c83.js"><link rel="prefetch" href="/assets/js/555.d95f24bd.js"><link rel="prefetch" href="/assets/js/556.42a17364.js"><link rel="prefetch" href="/assets/js/557.a066d457.js"><link rel="prefetch" href="/assets/js/558.1f4641c3.js"><link rel="prefetch" href="/assets/js/559.f85fd85a.js"><link rel="prefetch" href="/assets/js/56.9ede6cf7.js"><link rel="prefetch" href="/assets/js/560.c486ead6.js"><link rel="prefetch" href="/assets/js/561.5654ef71.js"><link rel="prefetch" href="/assets/js/562.8ac06965.js"><link rel="prefetch" href="/assets/js/563.209407dd.js"><link rel="prefetch" href="/assets/js/564.4da5848b.js"><link rel="prefetch" href="/assets/js/565.0ea0c2cb.js"><link rel="prefetch" href="/assets/js/566.fbb62b05.js"><link rel="prefetch" href="/assets/js/567.0454bee2.js"><link rel="prefetch" href="/assets/js/568.5aad57f8.js"><link rel="prefetch" href="/assets/js/569.b4b199ad.js"><link rel="prefetch" href="/assets/js/57.2e9b38e9.js"><link rel="prefetch" href="/assets/js/570.890f1d05.js"><link rel="prefetch" href="/assets/js/571.56e5f721.js"><link rel="prefetch" href="/assets/js/572.fa3418f1.js"><link rel="prefetch" href="/assets/js/573.224ada77.js"><link rel="prefetch" href="/assets/js/574.4cc85330.js"><link rel="prefetch" href="/assets/js/575.61a17f5e.js"><link rel="prefetch" href="/assets/js/576.0ec5efb8.js"><link rel="prefetch" href="/assets/js/577.6bc915dd.js"><link rel="prefetch" href="/assets/js/578.fd4e39e7.js"><link rel="prefetch" href="/assets/js/579.0238c950.js"><link rel="prefetch" href="/assets/js/58.f28ad3cc.js"><link rel="prefetch" href="/assets/js/580.a08c6c02.js"><link rel="prefetch" href="/assets/js/581.392f9c6f.js"><link rel="prefetch" href="/assets/js/582.2f59e9f2.js"><link rel="prefetch" href="/assets/js/583.2097fe85.js"><link rel="prefetch" href="/assets/js/584.f0d8c622.js"><link rel="prefetch" href="/assets/js/585.85fab1f2.js"><link rel="prefetch" href="/assets/js/586.c359098c.js"><link rel="prefetch" href="/assets/js/587.1dff90c3.js"><link rel="prefetch" href="/assets/js/588.6afc16eb.js"><link rel="prefetch" href="/assets/js/589.4337cfee.js"><link rel="prefetch" href="/assets/js/59.9079a4f5.js"><link rel="prefetch" href="/assets/js/590.f969cc18.js"><link rel="prefetch" href="/assets/js/591.dfceaca2.js"><link rel="prefetch" href="/assets/js/592.b670f7b8.js"><link rel="prefetch" href="/assets/js/593.85ff3e7e.js"><link rel="prefetch" href="/assets/js/594.87d3c73b.js"><link rel="prefetch" href="/assets/js/595.18f2a1df.js"><link rel="prefetch" href="/assets/js/596.adb07b39.js"><link rel="prefetch" href="/assets/js/597.4bfdae44.js"><link rel="prefetch" href="/assets/js/598.a4f73bf5.js"><link rel="prefetch" href="/assets/js/599.5b85b7f2.js"><link rel="prefetch" href="/assets/js/6.6f5ae702.js"><link rel="prefetch" href="/assets/js/60.3095e21a.js"><link rel="prefetch" href="/assets/js/600.98cef029.js"><link rel="prefetch" href="/assets/js/601.34cfecd2.js"><link rel="prefetch" href="/assets/js/602.afaf2e1f.js"><link rel="prefetch" href="/assets/js/603.5f081041.js"><link rel="prefetch" href="/assets/js/604.a55dc3e4.js"><link rel="prefetch" href="/assets/js/605.cc600bca.js"><link rel="prefetch" href="/assets/js/606.9e0874e1.js"><link rel="prefetch" href="/assets/js/607.bd0a2835.js"><link rel="prefetch" href="/assets/js/608.e3c0bb6d.js"><link rel="prefetch" href="/assets/js/609.968adfbe.js"><link rel="prefetch" href="/assets/js/61.cd58c0e2.js"><link rel="prefetch" href="/assets/js/610.6ddb82e2.js"><link rel="prefetch" href="/assets/js/611.f6573e33.js"><link rel="prefetch" href="/assets/js/612.cd703232.js"><link rel="prefetch" href="/assets/js/613.5ae48097.js"><link rel="prefetch" href="/assets/js/614.c9fc5628.js"><link rel="prefetch" href="/assets/js/615.5f3c1162.js"><link rel="prefetch" href="/assets/js/616.3efeed17.js"><link rel="prefetch" href="/assets/js/617.25dec672.js"><link rel="prefetch" href="/assets/js/618.b53f21b6.js"><link rel="prefetch" href="/assets/js/619.e0c2de74.js"><link rel="prefetch" href="/assets/js/62.aa4d202d.js"><link rel="prefetch" href="/assets/js/620.88136c6a.js"><link rel="prefetch" href="/assets/js/621.494122df.js"><link rel="prefetch" href="/assets/js/622.e2a6e4bd.js"><link rel="prefetch" href="/assets/js/623.20a56d61.js"><link rel="prefetch" href="/assets/js/624.602dd933.js"><link rel="prefetch" href="/assets/js/625.70f44f60.js"><link rel="prefetch" href="/assets/js/626.11524978.js"><link rel="prefetch" href="/assets/js/627.b3badb72.js"><link rel="prefetch" href="/assets/js/628.e613665e.js"><link rel="prefetch" href="/assets/js/629.20e73b43.js"><link rel="prefetch" href="/assets/js/63.f7cd40f4.js"><link rel="prefetch" href="/assets/js/630.6099312f.js"><link rel="prefetch" href="/assets/js/631.669bcda0.js"><link rel="prefetch" href="/assets/js/632.d33f5ec9.js"><link rel="prefetch" href="/assets/js/633.211456ee.js"><link rel="prefetch" href="/assets/js/634.ea9d07ae.js"><link rel="prefetch" href="/assets/js/635.f22368f1.js"><link rel="prefetch" href="/assets/js/636.ebe249f7.js"><link rel="prefetch" href="/assets/js/637.7b645ab3.js"><link rel="prefetch" href="/assets/js/638.4565c395.js"><link rel="prefetch" href="/assets/js/639.c5144f9c.js"><link rel="prefetch" href="/assets/js/64.8cd3aa43.js"><link rel="prefetch" href="/assets/js/640.2dc2eba9.js"><link rel="prefetch" href="/assets/js/641.70155ce7.js"><link rel="prefetch" href="/assets/js/642.c55f5ca8.js"><link rel="prefetch" href="/assets/js/643.69a5b8e5.js"><link rel="prefetch" href="/assets/js/644.84431935.js"><link rel="prefetch" href="/assets/js/645.5119ebc2.js"><link rel="prefetch" href="/assets/js/646.506fc745.js"><link rel="prefetch" href="/assets/js/647.e5f03652.js"><link rel="prefetch" href="/assets/js/648.47ae0cc5.js"><link rel="prefetch" href="/assets/js/649.b3a67529.js"><link rel="prefetch" href="/assets/js/65.14b3da5d.js"><link rel="prefetch" href="/assets/js/650.89765bb0.js"><link rel="prefetch" href="/assets/js/651.19b73cf8.js"><link rel="prefetch" href="/assets/js/652.4436725f.js"><link rel="prefetch" href="/assets/js/653.391168ff.js"><link rel="prefetch" href="/assets/js/654.8b449d07.js"><link rel="prefetch" href="/assets/js/655.27051c8c.js"><link rel="prefetch" href="/assets/js/656.7adaae31.js"><link rel="prefetch" href="/assets/js/657.4fee46d2.js"><link rel="prefetch" href="/assets/js/658.0243a6e8.js"><link rel="prefetch" href="/assets/js/659.f69398bc.js"><link rel="prefetch" href="/assets/js/66.899fc260.js"><link rel="prefetch" href="/assets/js/660.5e51ab7c.js"><link rel="prefetch" href="/assets/js/661.980d3d5a.js"><link rel="prefetch" href="/assets/js/662.79643730.js"><link rel="prefetch" href="/assets/js/663.d030bd1d.js"><link rel="prefetch" href="/assets/js/664.32b3c0e8.js"><link rel="prefetch" href="/assets/js/665.384c456b.js"><link rel="prefetch" href="/assets/js/666.2672eb36.js"><link rel="prefetch" href="/assets/js/667.2ca85ff9.js"><link rel="prefetch" href="/assets/js/668.b80ef3b4.js"><link rel="prefetch" href="/assets/js/669.41f08cb1.js"><link rel="prefetch" href="/assets/js/67.c0e799e4.js"><link rel="prefetch" href="/assets/js/670.48512f45.js"><link rel="prefetch" href="/assets/js/671.93e1cdd9.js"><link rel="prefetch" href="/assets/js/672.aa2a7e31.js"><link rel="prefetch" href="/assets/js/673.b19ed80d.js"><link rel="prefetch" href="/assets/js/674.0337bf32.js"><link rel="prefetch" href="/assets/js/675.88a9d569.js"><link rel="prefetch" href="/assets/js/676.7fd2de1c.js"><link rel="prefetch" href="/assets/js/677.1356b477.js"><link rel="prefetch" href="/assets/js/678.d99fd658.js"><link rel="prefetch" href="/assets/js/679.a2e40bc7.js"><link rel="prefetch" href="/assets/js/68.2e72dacb.js"><link rel="prefetch" href="/assets/js/680.58e5d76e.js"><link rel="prefetch" href="/assets/js/681.2e66d773.js"><link rel="prefetch" href="/assets/js/682.42526013.js"><link rel="prefetch" href="/assets/js/683.447d4972.js"><link rel="prefetch" href="/assets/js/684.19beb22a.js"><link rel="prefetch" href="/assets/js/685.cd3fd615.js"><link rel="prefetch" href="/assets/js/686.c6200f3f.js"><link rel="prefetch" href="/assets/js/687.3d6cf8bb.js"><link rel="prefetch" href="/assets/js/688.e9ddd041.js"><link rel="prefetch" href="/assets/js/689.74bb6414.js"><link rel="prefetch" href="/assets/js/69.d29a7787.js"><link rel="prefetch" href="/assets/js/690.82b51acd.js"><link rel="prefetch" href="/assets/js/691.a6edc5c3.js"><link rel="prefetch" href="/assets/js/692.c5fd2fa7.js"><link rel="prefetch" href="/assets/js/693.0c0b8126.js"><link rel="prefetch" href="/assets/js/694.551ae4d1.js"><link rel="prefetch" href="/assets/js/695.2801a2f2.js"><link rel="prefetch" href="/assets/js/696.8723006b.js"><link rel="prefetch" href="/assets/js/697.275e71c7.js"><link rel="prefetch" href="/assets/js/698.431e2bfb.js"><link rel="prefetch" href="/assets/js/699.c82907d3.js"><link rel="prefetch" href="/assets/js/7.c8b0ee6b.js"><link rel="prefetch" href="/assets/js/70.53b18677.js"><link rel="prefetch" href="/assets/js/700.9faf8917.js"><link rel="prefetch" href="/assets/js/701.5ce77f04.js"><link rel="prefetch" href="/assets/js/702.488262eb.js"><link rel="prefetch" href="/assets/js/703.8f79363d.js"><link rel="prefetch" href="/assets/js/704.a4cfe8cb.js"><link rel="prefetch" href="/assets/js/705.4f1759eb.js"><link rel="prefetch" href="/assets/js/706.baf03b10.js"><link rel="prefetch" href="/assets/js/707.48c01840.js"><link rel="prefetch" href="/assets/js/708.b3cda177.js"><link rel="prefetch" href="/assets/js/709.260cc3a8.js"><link rel="prefetch" href="/assets/js/71.b44506bc.js"><link rel="prefetch" href="/assets/js/710.e4fa6646.js"><link rel="prefetch" href="/assets/js/711.7816aba5.js"><link rel="prefetch" href="/assets/js/712.14939ffd.js"><link rel="prefetch" href="/assets/js/72.9793c1ce.js"><link rel="prefetch" href="/assets/js/73.b4d37c7e.js"><link rel="prefetch" href="/assets/js/74.b816cbc7.js"><link rel="prefetch" href="/assets/js/75.9f45a274.js"><link rel="prefetch" href="/assets/js/76.4921e235.js"><link rel="prefetch" href="/assets/js/77.f9258c97.js"><link rel="prefetch" href="/assets/js/78.55656c0f.js"><link rel="prefetch" href="/assets/js/79.b5784c72.js"><link rel="prefetch" href="/assets/js/8.44118d7c.js"><link rel="prefetch" href="/assets/js/80.98240933.js"><link rel="prefetch" href="/assets/js/81.5421fa90.js"><link rel="prefetch" href="/assets/js/82.72a10ccf.js"><link rel="prefetch" href="/assets/js/83.abdca93e.js"><link rel="prefetch" href="/assets/js/84.5d0190e3.js"><link rel="prefetch" href="/assets/js/85.5d2a1647.js"><link rel="prefetch" href="/assets/js/86.5aea5730.js"><link rel="prefetch" href="/assets/js/87.bfe2bb57.js"><link rel="prefetch" href="/assets/js/88.4097611c.js"><link rel="prefetch" href="/assets/js/89.e5a98da0.js"><link rel="prefetch" href="/assets/js/9.612b54fd.js"><link rel="prefetch" href="/assets/js/90.5564a69b.js"><link rel="prefetch" href="/assets/js/91.ff219511.js"><link rel="prefetch" href="/assets/js/92.8191f073.js"><link rel="prefetch" href="/assets/js/93.4b6ecb16.js"><link rel="prefetch" href="/assets/js/94.fd999a73.js"><link rel="prefetch" href="/assets/js/95.c96c310d.js"><link rel="prefetch" href="/assets/js/96.2eb0ab2f.js"><link rel="prefetch" href="/assets/js/97.4c8c6fba.js"><link rel="prefetch" href="/assets/js/98.f9ef7bdb.js"><link rel="prefetch" href="/assets/js/99.513483d0.js"><link rel="prefetch" href="/assets/js/vendors~docsearch.49ad9c45.js">
    <link rel="stylesheet" href="/assets/css/0.styles.af3770e9.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/en/" class="home-link router-link-active"><img src="/images/icons/spring-logo.svg" alt="Spring Docs" class="logo"> <span class="site-name can-hide">Spring Docs</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/en/spring/why-spring.html" class="nav-link">
  Spring
</a></div><div class="nav-item"><a href="/en/spring-boot/getting-help.html" class="nav-link">
  Spring Boot
</a></div><div class="nav-item"><a href="/en/spring-cloud/documentation-overview.html" class="nav-link">
  Spring Cloud
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Others" class="dropdown-title"><span class="title">more</span> <span class="arrow down"></span></button> <button type="button" aria-label="Others" class="mobile-dropdown-title"><span class="title">more</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/en/spring-framework/overview.html" class="nav-link">
  Spring Framework
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-data/spring-data.html" class="nav-link">
  Spring Data
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-cloud-data-flow/spring-cloud-dataflow.html" class="nav-link">
  Spring Cloud Data Flow
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-security/overview.html" class="nav-link">
  Spring Security
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-for-graphql/spring-graphql.html" class="nav-link">
  Spring for GraphQL
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-session/_index.html" class="nav-link">
  Spring Session
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-integration/preface.html" class="nav-link">
  Spring Integration
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-hateoas/spring-hateoas.html" class="nav-link">
  Spring HATEOAS
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-rest-docs/spring-restdocs.html" class="nav-link">
  Spring REST Docs
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-batch/spring-batch-intro.html" class="nav-link">
  Spring Batch
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-amqp/spring-amqp.html" class="nav-link">
  Spring AMQP
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-credhub/spring-credhub.html" class="nav-link">
  Spring CredHub
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-flo/spring-flo.html" class="nav-link">
  Spring Flo
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-for-apache-kafka/spring-kafka.html" class="nav-link">
  Spring for Apache Kafka
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-ldap/spring-ldap.html" class="nav-link">
  Spring LDAP
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-shell/spring-shell.html" class="nav-link">
  Spring Shell
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-statemachine/spring-statemachine.html" class="nav-link">
  Spring Statemachine
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-vault/spring-vault.html" class="nav-link">
  Spring Vault
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-web-flow/preface.html" class="nav-link">
  Spring Web Flow
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-web-services/spring-web-service.html" class="nav-link">
  Spring Web Services
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Select language" class="dropdown-title"><span class="title">Language</span> <span class="arrow down"></span></button> <button type="button" aria-label="Select language" class="mobile-dropdown-title"><span class="title">Language</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/en/spring-batch/step.html" aria-current="page" class="nav-link router-link-exact-active router-link-active">
  English
</a></li><li class="dropdown-item"><!----> <a href="/spring-batch/step.html" class="nav-link">
  简体中文
</a></li></ul></div></div> <a href="https://gitcode.net/dev-cloud/spring-docs" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitCode
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/en/spring/why-spring.html" class="nav-link">
  Spring
</a></div><div class="nav-item"><a href="/en/spring-boot/getting-help.html" class="nav-link">
  Spring Boot
</a></div><div class="nav-item"><a href="/en/spring-cloud/documentation-overview.html" class="nav-link">
  Spring Cloud
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Others" class="dropdown-title"><span class="title">more</span> <span class="arrow down"></span></button> <button type="button" aria-label="Others" class="mobile-dropdown-title"><span class="title">more</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/en/spring-framework/overview.html" class="nav-link">
  Spring Framework
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-data/spring-data.html" class="nav-link">
  Spring Data
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-cloud-data-flow/spring-cloud-dataflow.html" class="nav-link">
  Spring Cloud Data Flow
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-security/overview.html" class="nav-link">
  Spring Security
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-for-graphql/spring-graphql.html" class="nav-link">
  Spring for GraphQL
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-session/_index.html" class="nav-link">
  Spring Session
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-integration/preface.html" class="nav-link">
  Spring Integration
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-hateoas/spring-hateoas.html" class="nav-link">
  Spring HATEOAS
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-rest-docs/spring-restdocs.html" class="nav-link">
  Spring REST Docs
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-batch/spring-batch-intro.html" class="nav-link">
  Spring Batch
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-amqp/spring-amqp.html" class="nav-link">
  Spring AMQP
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-credhub/spring-credhub.html" class="nav-link">
  Spring CredHub
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-flo/spring-flo.html" class="nav-link">
  Spring Flo
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-for-apache-kafka/spring-kafka.html" class="nav-link">
  Spring for Apache Kafka
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-ldap/spring-ldap.html" class="nav-link">
  Spring LDAP
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-shell/spring-shell.html" class="nav-link">
  Spring Shell
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-statemachine/spring-statemachine.html" class="nav-link">
  Spring Statemachine
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-vault/spring-vault.html" class="nav-link">
  Spring Vault
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-web-flow/preface.html" class="nav-link">
  Spring Web Flow
</a></li><li class="dropdown-item"><!----> <a href="/en/spring-web-services/spring-web-service.html" class="nav-link">
  Spring Web Services
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Select language" class="dropdown-title"><span class="title">Language</span> <span class="arrow down"></span></button> <button type="button" aria-label="Select language" class="mobile-dropdown-title"><span class="title">Language</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/en/spring-batch/step.html" aria-current="page" class="nav-link router-link-exact-active router-link-active">
  English
</a></li><li class="dropdown-item"><!----> <a href="/spring-batch/step.html" class="nav-link">
  简体中文
</a></li></ul></div></div> <a href="https://gitcode.net/dev-cloud/spring-docs" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitCode
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Spring Batch 文档</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/en/spring-batch/spring-batch-intro.html" class="sidebar-link">Spring Batch Introduction</a></li><li><a href="/en/spring-batch/whatsnew.html" class="sidebar-link">What’s New in Spring Batch 4.3</a></li><li><a href="/en/spring-batch/domain.html" class="sidebar-link">The Domain Language of Batch</a></li><li><a href="/en/spring-batch/job.html" class="sidebar-link">Configuring and Running a Job</a></li><li><a href="/en/spring-batch/step.html" aria-current="page" class="active sidebar-link">Configuring a Step</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/en/spring-batch/step.html#configuring-a-step-2" class="sidebar-link">Configuring a Step</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/en/spring-batch/step.html#chunk-oriented-processing" class="sidebar-link">Chunk-oriented Processing</a></li><li class="sidebar-sub-header"><a href="/en/spring-batch/step.html#taskletstep" class="sidebar-link">TaskletStep</a></li><li class="sidebar-sub-header"><a href="/en/spring-batch/step.html#controlling-step-flow" class="sidebar-link">Controlling Step Flow</a></li><li class="sidebar-sub-header"><a href="/en/spring-batch/step.html#late-binding-of-job-and-step-attributes" class="sidebar-link">Late Binding of Job and Step Attributes</a></li></ul></li></ul></li><li><a href="/en/spring-batch/readersAndWriters.html" class="sidebar-link">ItemReaders and ItemWriters</a></li><li><a href="/en/spring-batch/processor.html" class="sidebar-link">Item processing</a></li><li><a href="/en/spring-batch/scalability.html" class="sidebar-link">Scaling and Parallel Processing</a></li><li><a href="/en/spring-batch/repeat.html" class="sidebar-link">Repeat</a></li><li><a href="/en/spring-batch/retry.html" class="sidebar-link">Retry</a></li><li><a href="/en/spring-batch/testing.html" class="sidebar-link">Unit Testing</a></li><li><a href="/en/spring-batch/common-patterns.html" class="sidebar-link">Common Batch Patterns</a></li><li><a href="/en/spring-batch/jsr-352.html" class="sidebar-link">JSR-352 Support</a></li><li><a href="/en/spring-batch/spring-batch-integration.html" class="sidebar-link">Spring Batch Integration</a></li><li><a href="/en/spring-batch/monitoring-and-metrics.html" class="sidebar-link">Monitoring and metrics</a></li><li><a href="/en/spring-batch/appendix.html" class="sidebar-link">Appendix A: List of ItemReaders and ItemWriters</a></li><li><a href="/en/spring-batch/schema-appendix.html" class="sidebar-link">Meta-Data Schema</a></li><li><a href="/en/spring-batch/transaction-appendix.html" class="sidebar-link">Batch Processing and Transactions</a></li><li><a href="/en/spring-batch/glossary.html" class="sidebar-link">Glossary</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="configuring-a-step"><a href="#configuring-a-step" class="header-anchor">#</a> Configuring a Step</h1> <h2 id="configuring-a-step-2"><a href="#configuring-a-step-2" class="header-anchor">#</a> Configuring a <code>Step</code></h2> <p>XMLJavaBoth</p> <p>As discussed in <a href="/en/spring-batch/domain.html#domainLanguageOfBatch">the domain chapter</a>, a <code>Step</code> is a
domain object that encapsulates an independent, sequential phase of a batch job and
contains all of the information necessary to define and control the actual batch
processing. This is a necessarily vague description because the contents of any given<code>Step</code> are at the discretion of the developer writing a <code>Job</code>. A <code>Step</code> can be as simple
or complex as the developer desires. A simple <code>Step</code> might load data from a file into the
database, requiring little or no code (depending upon the implementations used). A more
complex <code>Step</code> might have complicated business rules that are applied as part of the
processing, as shown in the following image:</p> <p><img src="https://docs.spring.io/spring-batch/docs/current/reference/html/images/step.png" alt="Step"></p> <p>Figure 1. Step</p> <h3 id="chunk-oriented-processing"><a href="#chunk-oriented-processing" class="header-anchor">#</a> Chunk-oriented Processing</h3> <p>Spring Batch uses a 'Chunk-oriented' processing style within its most common
implementation. Chunk oriented processing refers to reading the data one at a time and
creating 'chunks' that are written out within a transaction boundary. Once the number of
items read equals the commit interval, the entire chunk is written out by the<code>ItemWriter</code>, and then the transaction is committed. The following image shows the
process:</p> <p><img src="https://docs.spring.io/spring-batch/docs/current/reference/html/images/chunk-oriented-processing.png" alt="Chunk Oriented Processing"></p> <p>Figure 2. Chunk-oriented Processing</p> <p>The following pseudo code shows the same concepts in a simplified form:</p> <div class="language- extra-class"><pre class="language-text"><code>List items = new Arraylist();
for(int i = 0; i &lt; commitInterval; i++){
    Object item = itemReader.read();
    if (item != null) {
        items.add(item);
    }
}
itemWriter.write(items);
</code></pre></div><p>A chunk-oriented step can also be configured with an optional <code>ItemProcessor</code>to process items before passing them to the <code>ItemWriter</code>. The following image
shows the process when an <code>ItemProcessor</code> is registered in the step:</p> <p><img src="https://docs.spring.io/spring-batch/docs/current/reference/html/images/chunk-oriented-processing-with-item-processor.png" alt="Chunk Oriented Processing With Item Processor"></p> <p>Figure 3. Chunk-oriented Processing with Item Processor</p> <p>The following pseudo code shows how this is implemented in a simplified form:</p> <div class="language- extra-class"><pre class="language-text"><code>List items = new Arraylist();
for(int i = 0; i &lt; commitInterval; i++){
    Object item = itemReader.read();
    if (item != null) {
        items.add(item);
    }
}

List processedItems = new Arraylist();
for(Object item: items){
    Object processedItem = itemProcessor.process(item);
    if (processedItem != null) {
        processedItems.add(processedItem);
    }
}

itemWriter.write(processedItems);
</code></pre></div><p>For more details about item processors and their use cases, please refer to the<a href="/en/spring-batch/processor.html#itemProcessor">Item processing</a> section.</p> <h4 id="configuring-a-step-3"><a href="#configuring-a-step-3" class="header-anchor">#</a> Configuring a <code>Step</code></h4> <p>Despite the relatively short list of required dependencies for a <code>Step</code>, it is an
extremely complex class that can potentially contain many collaborators.</p> <p>In order to ease configuration, the Spring Batch XML namespace can be used, as shown in
the following example:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;job id=&quot;sampleJob&quot; job-repository=&quot;jobRepository&quot;&gt;
    &lt;step id=&quot;step1&quot;&gt;
        &lt;tasklet transaction-manager=&quot;transactionManager&quot;&gt;
            &lt;chunk reader=&quot;itemReader&quot; writer=&quot;itemWriter&quot; commit-interval=&quot;10&quot;/&gt;
        &lt;/tasklet&gt;
    &lt;/step&gt;
&lt;/job&gt;
</code></pre></div><p>When using Java configuration, the Spring Batch builders can be used, as shown in the
following example:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>/**
 * Note the JobRepository is typically autowired in and not needed to be explicitly
 * configured
 */
@Bean
public Job sampleJob(JobRepository jobRepository, Step sampleStep) {
    return this.jobBuilderFactory.get(&quot;sampleJob&quot;)
    			.repository(jobRepository)
                .start(sampleStep)
                .build();
}

/**
 * Note the TransactionManager is typically autowired in and not needed to be explicitly
 * configured
 */
@Bean
public Step sampleStep(PlatformTransactionManager transactionManager) {
	return this.stepBuilderFactory.get(&quot;sampleStep&quot;)
				.transactionManager(transactionManager)
				.&lt;String, String&gt;chunk(10)
				.reader(itemReader())
				.writer(itemWriter())
				.build();
}
</code></pre></div><p>The configuration above includes the only required dependencies to create a item-oriented
step:</p> <ul><li><p><code>reader</code>: The <code>ItemReader</code> that provides items for processing.</p></li> <li><p><code>writer</code>: The <code>ItemWriter</code> that processes the items provided by the <code>ItemReader</code>.</p></li> <li><p><code>transaction-manager</code>: Spring’s <code>PlatformTransactionManager</code> that begins and commits
transactions during processing.</p></li> <li><p><code>transactionManager</code>: Spring’s <code>PlatformTransactionManager</code> that begins and commits
transactions during processing.</p></li> <li><p><code>job-repository</code>: The XML-specific name of the <code>JobRepository</code> that periodically stores
the <code>StepExecution</code> and <code>ExecutionContext</code> during processing (just before committing). For
an in-line <code>&lt;step/&gt;</code> (one defined within a <code>&lt;job/&gt;</code>), it is an attribute on the <code>&lt;job/&gt;</code>element. For a standalone <code>&lt;step/&gt;</code>, it is defined as an attribute of the &lt;tasklet/&gt;.</p></li> <li><p><code>repository</code>: The Java-specific name of the <code>JobRepository</code> that periodically stores
the <code>StepExecution</code> and <code>ExecutionContext</code> during processing (just before committing).</p></li> <li><p><code>commit-interval</code>: The XML-specific name of the number of items to be processed
before the transaction is committed.</p></li> <li><p><code>chunk</code>: The Java-specific name of the dependency that indicates that this is an
item-based step and the number of items to be processed before the transaction is
committed.</p></li></ul> <p>It should be noted that <code>job-repository</code> defaults to <code>jobRepository</code> and<code>transaction-manager</code> defaults to <code>transactionManager</code>. Also, the <code>ItemProcessor</code> is
optional, since the item could be directly passed from the reader to the writer.</p> <p>It should be noted that <code>repository</code> defaults to <code>jobRepository</code> and <code>transactionManager</code>defaults to <code>transactionManager</code> (all provided through the infrastructure from<code>@EnableBatchProcessing</code>). Also, the <code>ItemProcessor</code> is optional, since the item could be
directly passed from the reader to the writer.</p> <h4 id="inheriting-from-a-parent-step"><a href="#inheriting-from-a-parent-step" class="header-anchor">#</a> Inheriting from a Parent <code>Step</code></h4> <p>If a group of <code>Steps</code> share similar configurations, then it may be helpful to define a
&quot;parent&quot; <code>Step</code> from which the concrete <code>Steps</code> may inherit properties. Similar to class
inheritance in Java, the &quot;child&quot; <code>Step</code> combines its elements and attributes with the
parent’s. The child also overrides any of the parent’s <code>Steps</code>.</p> <p>In the following example, the <code>Step</code>, &quot;concreteStep1&quot;, inherits from &quot;parentStep&quot;. It is
instantiated with 'itemReader', 'itemProcessor', 'itemWriter', <code>startLimit=5</code>, and<code>allowStartIfComplete=true</code>. Additionally, the <code>commitInterval</code> is '5', since it is
overridden by the &quot;concreteStep1&quot; <code>Step</code>, as shown in the following example:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;parentStep&quot;&gt;
    &lt;tasklet allow-start-if-complete=&quot;true&quot;&gt;
        &lt;chunk reader=&quot;itemReader&quot; writer=&quot;itemWriter&quot; commit-interval=&quot;10&quot;/&gt;
    &lt;/tasklet&gt;
&lt;/step&gt;

&lt;step id=&quot;concreteStep1&quot; parent=&quot;parentStep&quot;&gt;
    &lt;tasklet start-limit=&quot;5&quot;&gt;
        &lt;chunk processor=&quot;itemProcessor&quot; commit-interval=&quot;5&quot;/&gt;
    &lt;/tasklet&gt;
&lt;/step&gt;
</code></pre></div><p>The <code>id</code> attribute is still required on the step within the job element. This is for two
reasons:</p> <ul><li><p>The <code>id</code> is used as the step name when persisting the <code>StepExecution</code>. If the same
standalone step is referenced in more than one step in the job, an error occurs.</p></li> <li><p>When creating job flows, as described later in this chapter, the <code>next</code> attribute
should be referring to the step in the flow, not the standalone step.</p></li></ul> <h5 id="abstract-step"><a href="#abstract-step" class="header-anchor">#</a> Abstract <code>Step</code></h5> <p>Sometimes, it may be necessary to define a parent <code>Step</code> that is not a complete <code>Step</code>configuration. If, for instance, the <code>reader</code>, <code>writer</code>, and <code>tasklet</code> attributes are
left off of a <code>Step</code> configuration, then initialization fails. If a parent must be
defined without these properties, then the <code>abstract</code> attribute should be used. An<code>abstract</code> <code>Step</code> is only extended, never instantiated.</p> <p>In the following example, the <code>Step</code> <code>abstractParentStep</code> would not be instantiated if it
were not declared to be abstract. The <code>Step</code>, &quot;concreteStep2&quot;, has 'itemReader',
'itemWriter', and commit-interval=10.</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;abstractParentStep&quot; abstract=&quot;true&quot;&gt;
    &lt;tasklet&gt;
        &lt;chunk commit-interval=&quot;10&quot;/&gt;
    &lt;/tasklet&gt;
&lt;/step&gt;

&lt;step id=&quot;concreteStep2&quot; parent=&quot;abstractParentStep&quot;&gt;
    &lt;tasklet&gt;
        &lt;chunk reader=&quot;itemReader&quot; writer=&quot;itemWriter&quot;/&gt;
    &lt;/tasklet&gt;
&lt;/step&gt;
</code></pre></div><h5 id="merging-lists"><a href="#merging-lists" class="header-anchor">#</a> Merging Lists</h5> <p>Some of the configurable elements on <code>Steps</code> are lists, such as the <code>&lt;listeners/&gt;</code> element.
If both the parent and child <code>Steps</code> declare a <code>&lt;listeners/&gt;</code> element, then the
child’s list overrides the parent’s. In order to allow a child to add additional
listeners to the list defined by the parent, every list element has a <code>merge</code> attribute.
If the element specifies that <code>merge=&quot;true&quot;</code>, then the child’s list is combined with the
parent’s instead of overriding it.</p> <p>In the following example, the <code>Step</code> &quot;concreteStep3&quot;, is created with two listeners:<code>listenerOne</code> and <code>listenerTwo</code>:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;listenersParentStep&quot; abstract=&quot;true&quot;&gt;
    &lt;listeners&gt;
        &lt;listener ref=&quot;listenerOne&quot;/&gt;
    &lt;listeners&gt;
&lt;/step&gt;

&lt;step id=&quot;concreteStep3&quot; parent=&quot;listenersParentStep&quot;&gt;
    &lt;tasklet&gt;
        &lt;chunk reader=&quot;itemReader&quot; writer=&quot;itemWriter&quot; commit-interval=&quot;5&quot;/&gt;
    &lt;/tasklet&gt;
    &lt;listeners merge=&quot;true&quot;&gt;
        &lt;listener ref=&quot;listenerTwo&quot;/&gt;
    &lt;listeners&gt;
&lt;/step&gt;
</code></pre></div><h4 id="the-commit-interval"><a href="#the-commit-interval" class="header-anchor">#</a> The Commit Interval</h4> <p>As mentioned previously, a step reads in and writes out items, periodically committing
using the supplied <code>PlatformTransactionManager</code>. With a <code>commit-interval</code> of 1, it
commits after writing each individual item. This is less than ideal in many situations,
since beginning and committing a transaction is expensive. Ideally, it is preferable to
process as many items as possible in each transaction, which is completely dependent upon
the type of data being processed and the resources with which the step is interacting.
For this reason, the number of items that are processed within a commit can be
configured.</p> <p>The following example shows a <code>step</code> whose <code>tasklet</code> has a <code>commit-interval</code>value of 10 as it would be defined in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;job id=&quot;sampleJob&quot;&gt;
    &lt;step id=&quot;step1&quot;&gt;
        &lt;tasklet&gt;
            &lt;chunk reader=&quot;itemReader&quot; writer=&quot;itemWriter&quot; commit-interval=&quot;10&quot;/&gt;
        &lt;/tasklet&gt;
    &lt;/step&gt;
&lt;/job&gt;
</code></pre></div><p>The following example shows a <code>step</code> whose <code>tasklet</code> has a <code>commit-interval</code>value of 10 as it would be defined in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job sampleJob() {
    return this.jobBuilderFactory.get(&quot;sampleJob&quot;)
                     .start(step1())
                     .build();
}

@Bean
public Step step1() {
	return this.stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;String, String&gt;chunk(10)
				.reader(itemReader())
				.writer(itemWriter())
				.build();
}
</code></pre></div><p>In the preceding example, 10 items are processed within each transaction. At the
beginning of processing, a transaction is begun. Also, each time <code>read</code> is called on the<code>ItemReader</code>, a counter is incremented. When it reaches 10, the list of aggregated items
is passed to the <code>ItemWriter</code>, and the transaction is committed.</p> <h4 id="configuring-a-step-for-restart"><a href="#configuring-a-step-for-restart" class="header-anchor">#</a> Configuring a <code>Step</code> for Restart</h4> <p>In the &quot;<a href="/en/spring-batch/job.html#configureJob">Configuring and Running a Job</a>&quot; section , restarting a<code>Job</code> was discussed. Restart has numerous impacts on steps, and, consequently, may
require some specific configuration.</p> <h5 id="setting-a-start-limit"><a href="#setting-a-start-limit" class="header-anchor">#</a> Setting a Start Limit</h5> <p>There are many scenarios where you may want to control the number of times a <code>Step</code> may
be started. For example, a particular <code>Step</code> might need to be configured so that it only
runs once because it invalidates some resource that must be fixed manually before it can
be run again. This is configurable on the step level, since different steps may have
different requirements. A <code>Step</code> that may only be executed once can exist as part of the
same <code>Job</code> as a <code>Step</code> that can be run infinitely.</p> <p>The following code fragment shows an example of a start limit configuration in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot;&gt;
    &lt;tasklet start-limit=&quot;1&quot;&gt;
        &lt;chunk reader=&quot;itemReader&quot; writer=&quot;itemWriter&quot; commit-interval=&quot;10&quot;/&gt;
    &lt;/tasklet&gt;
&lt;/step&gt;
</code></pre></div><p>The following code fragment shows an example of a start limit configuration in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Step step1() {
	return this.stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;String, String&gt;chunk(10)
				.reader(itemReader())
				.writer(itemWriter())
				.startLimit(1)
				.build();
}
</code></pre></div><p>The step shown in the preceding example can be run only once. Attempting to run it again
causes a <code>StartLimitExceededException</code> to be thrown. Note that the default value for the
start-limit is <code>Integer.MAX_VALUE</code>.</p> <h5 id="restarting-a-completed-step"><a href="#restarting-a-completed-step" class="header-anchor">#</a> Restarting a Completed <code>Step</code></h5> <p>In the case of a restartable job, there may be one or more steps that should always be
run, regardless of whether or not they were successful the first time. An example might
be a validation step or a <code>Step</code> that cleans up resources before processing. During
normal processing of a restarted job, any step with a status of 'COMPLETED', meaning it
has already been completed successfully, is skipped. Setting <code>allow-start-if-complete</code> to
&quot;true&quot; overrides this so that the step always runs.</p> <p>The following code fragment shows how to define a restartable job in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot;&gt;
    &lt;tasklet allow-start-if-complete=&quot;true&quot;&gt;
        &lt;chunk reader=&quot;itemReader&quot; writer=&quot;itemWriter&quot; commit-interval=&quot;10&quot;/&gt;
    &lt;/tasklet&gt;
&lt;/step&gt;
</code></pre></div><p>The following code fragment shows how to define a restartable job in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Step step1() {
	return this.stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;String, String&gt;chunk(10)
				.reader(itemReader())
				.writer(itemWriter())
				.allowStartIfComplete(true)
				.build();
}
</code></pre></div><h5 id="step-restart-configuration-example"><a href="#step-restart-configuration-example" class="header-anchor">#</a> <code>Step</code> Restart Configuration Example</h5> <p>The following XML example shows how to configure a job to have steps that can be
restarted:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;job id=&quot;footballJob&quot; restartable=&quot;true&quot;&gt;
    &lt;step id=&quot;playerload&quot; next=&quot;gameLoad&quot;&gt;
        &lt;tasklet&gt;
            &lt;chunk reader=&quot;playerFileItemReader&quot; writer=&quot;playerWriter&quot;
                   commit-interval=&quot;10&quot; /&gt;
        &lt;/tasklet&gt;
    &lt;/step&gt;
    &lt;step id=&quot;gameLoad&quot; next=&quot;playerSummarization&quot;&gt;
        &lt;tasklet allow-start-if-complete=&quot;true&quot;&gt;
            &lt;chunk reader=&quot;gameFileItemReader&quot; writer=&quot;gameWriter&quot;
                   commit-interval=&quot;10&quot;/&gt;
        &lt;/tasklet&gt;
    &lt;/step&gt;
    &lt;step id=&quot;playerSummarization&quot;&gt;
        &lt;tasklet start-limit=&quot;2&quot;&gt;
            &lt;chunk reader=&quot;playerSummarizationSource&quot; writer=&quot;summaryWriter&quot;
                   commit-interval=&quot;10&quot;/&gt;
        &lt;/tasklet&gt;
    &lt;/step&gt;
&lt;/job&gt;
</code></pre></div><p>The following Java example shows how to configure a job to have steps that can be
restarted:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job footballJob() {
	return this.jobBuilderFactory.get(&quot;footballJob&quot;)
				.start(playerLoad())
				.next(gameLoad())
				.next(playerSummarization())
				.build();
}

@Bean
public Step playerLoad() {
	return this.stepBuilderFactory.get(&quot;playerLoad&quot;)
			.&lt;String, String&gt;chunk(10)
			.reader(playerFileItemReader())
			.writer(playerWriter())
			.build();
}

@Bean
public Step gameLoad() {
	return this.stepBuilderFactory.get(&quot;gameLoad&quot;)
			.allowStartIfComplete(true)
			.&lt;String, String&gt;chunk(10)
			.reader(gameFileItemReader())
			.writer(gameWriter())
			.build();
}

@Bean
public Step playerSummarization() {
	return this.stepBuilderFactory.get(&quot;playerSummarization&quot;)
			.startLimit(2)
			.&lt;String, String&gt;chunk(10)
			.reader(playerSummarizationSource())
			.writer(summaryWriter())
			.build();
}
</code></pre></div><p>The preceding example configuration is for a job that loads in information about football
games and summarizes them. It contains three steps: <code>playerLoad</code>, <code>gameLoad</code>, and<code>playerSummarization</code>. The <code>playerLoad</code> step loads player information from a flat file,
while the <code>gameLoad</code> step does the same for games. The final step,<code>playerSummarization</code>, then summarizes the statistics for each player, based upon the
provided games. It is assumed that the file loaded by <code>playerLoad</code> must be loaded only
once, but that <code>gameLoad</code> can load any games found within a particular directory,
deleting them after they have been successfully loaded into the database. As a result,
the <code>playerLoad</code> step contains no additional configuration. It can be started any number
of times, and, if complete, is skipped. The <code>gameLoad</code> step, however, needs to be run
every time in case extra files have been added since it last ran. It has
'allow-start-if-complete' set to 'true' in order to always be started. (It is assumed
that the database table games are loaded into has a process indicator on it, to ensure
new games can be properly found by the summarization step). The summarization step,
which is the most important in the job, is configured to have a start limit of 2. This
is useful because if the step continually fails, a new exit code is returned to the
operators that control job execution, and it can not start again until manual
intervention has taken place.</p> <table><thead><tr><th></th> <th>This job provides an example for this document and is not the same as the <code>footballJob</code>found in the samples project.</th></tr></thead> <tbody></tbody></table> <p>The remainder of this section describes what happens for each of the three runs of the<code>footballJob</code> example.</p> <p>Run 1:</p> <ol><li><p><code>playerLoad</code> runs and completes successfully, adding 400 players to the 'PLAYERS'
table.</p></li> <li><p><code>gameLoad</code> runs and processes 11 files worth of game data, loading their contents
into the 'GAMES' table.</p></li> <li><p><code>playerSummarization</code> begins processing and fails after 5 minutes.</p></li></ol> <p>Run 2:</p> <ol><li><p><code>playerLoad</code> does not run, since it has already completed successfully, and<code>allow-start-if-complete</code> is 'false' (the default).</p></li> <li><p><code>gameLoad</code> runs again and processes another 2 files, loading their contents into the
'GAMES' table as well (with a process indicator indicating they have yet to be
processed).</p></li> <li><p><code>playerSummarization</code> begins processing of all remaining game data (filtering using the
process indicator) and fails again after 30 minutes.</p></li></ol> <p>Run 3:</p> <ol><li><p><code>playerLoad</code> does not run, since it has already completed successfully, and<code>allow-start-if-complete</code> is 'false' (the default).</p></li> <li><p><code>gameLoad</code> runs again and processes another 2 files, loading their contents into the
'GAMES' table as well (with a process indicator indicating they have yet to be
processed).</p></li> <li><p><code>playerSummarization</code> is not started and the job is immediately killed, since this is
the third execution of <code>playerSummarization</code>, and its limit is only 2. Either the limit
must be raised or the <code>Job</code> must be executed as a new <code>JobInstance</code>.</p></li></ol> <h4 id="configuring-skip-logic"><a href="#configuring-skip-logic" class="header-anchor">#</a> Configuring Skip Logic</h4> <p>There are many scenarios where errors encountered while processing should not result in<code>Step</code> failure, but should be skipped instead. This is usually a decision that must be
made by someone who understands the data itself and what meaning it has. Financial data,
for example, may not be skippable because it results in money being transferred, which
needs to be completely accurate. Loading a list of vendors, on the other hand, might
allow for skips. If a vendor is not loaded because it was formatted incorrectly or was
missing necessary information, then there probably are not issues. Usually, these bad
records are logged as well, which is covered later when discussing listeners.</p> <p>The following XML example shows an example of using a skip limit:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot;&gt;
   &lt;tasklet&gt;
      &lt;chunk reader=&quot;flatFileItemReader&quot; writer=&quot;itemWriter&quot;
             commit-interval=&quot;10&quot; skip-limit=&quot;10&quot;&gt;
         &lt;skippable-exception-classes&gt;
            &lt;include class=&quot;org.springframework.batch.item.file.FlatFileParseException&quot;/&gt;
         &lt;/skippable-exception-classes&gt;
      &lt;/chunk&gt;
   &lt;/tasklet&gt;
&lt;/step&gt;
</code></pre></div><p>The following Java example shows an example of using a skip limit:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Step step1() {
	return this.stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;String, String&gt;chunk(10)
				.reader(flatFileItemReader())
				.writer(itemWriter())
				.faultTolerant()
				.skipLimit(10)
				.skip(FlatFileParseException.class)
				.build();
}
</code></pre></div><p>In the preceding example, a <code>FlatFileItemReader</code> is used. If, at any point, a<code>FlatFileParseException</code> is thrown, the item is skipped and counted against the total
skip limit of 10. Exceptions (and their subclasses) that are declared might be thrown
during any phase of the chunk processing (read, process, write) but separate counts
are made of skips on read, process, and write inside
the step execution, but the limit applies across all skips. Once the skip limit is
reached, the next exception found causes the step to fail. In other words, the eleventh
skip triggers the exception, not the tenth.</p> <p>One problem with the preceding example is that any other exception besides a<code>FlatFileParseException</code> causes the <code>Job</code> to fail. In certain scenarios, this may be the
correct behavior. However, in other scenarios, it may be easier to identify which
exceptions should cause failure and skip everything else.</p> <p>The following XML example shows an example excluding a particular exception:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot;&gt;
    &lt;tasklet&gt;
        &lt;chunk reader=&quot;flatFileItemReader&quot; writer=&quot;itemWriter&quot;
               commit-interval=&quot;10&quot; skip-limit=&quot;10&quot;&gt;
            &lt;skippable-exception-classes&gt;
                &lt;include class=&quot;java.lang.Exception&quot;/&gt;
                &lt;exclude class=&quot;java.io.FileNotFoundException&quot;/&gt;
            &lt;/skippable-exception-classes&gt;
        &lt;/chunk&gt;
    &lt;/tasklet&gt;
&lt;/step&gt;
</code></pre></div><p>The following Java example shows an example excluding a particular exception:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Step step1() {
	return this.stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;String, String&gt;chunk(10)
				.reader(flatFileItemReader())
				.writer(itemWriter())
				.faultTolerant()
				.skipLimit(10)
				.skip(Exception.class)
				.noSkip(FileNotFoundException.class)
				.build();
}
</code></pre></div><p>By identifying <code>java.lang.Exception</code> as a skippable exception class, the configuration
indicates that all <code>Exceptions</code> are skippable. However, by 'excluding'<code>java.io.FileNotFoundException</code>, the configuration refines the list of skippable
exception classes to be all <code>Exceptions</code> <em>except</em> <code>FileNotFoundException</code>. Any excluded
exception classes is fatal if encountered (that is, they are not skipped).</p> <p>For any exception encountered, the skippability is determined by the nearest superclass
in the class hierarchy. Any unclassified exception is treated as 'fatal'.</p> <p>The order of the <code>&lt;include/&gt;</code> and <code>&lt;exclude/&gt;</code> elements does not matter.</p> <p>The order of the <code>skip</code> and <code>noSkip</code> method calls does not matter.</p> <h4 id="configuring-retry-logic"><a href="#configuring-retry-logic" class="header-anchor">#</a> Configuring Retry Logic</h4> <p>In most cases, you want an exception to cause either a skip or a <code>Step</code> failure. However,
not all exceptions are deterministic. If a <code>FlatFileParseException</code> is encountered while
reading, it is always thrown for that record. Resetting the <code>ItemReader</code> does not help.
However, for other exceptions, such as a <code>DeadlockLoserDataAccessException</code>, which
indicates that the current process has attempted to update a record that another process
holds a lock on. Waiting and trying again might result in success.</p> <p>In XML, retry should be configured as follows:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot;&gt;
   &lt;tasklet&gt;
      &lt;chunk reader=&quot;itemReader&quot; writer=&quot;itemWriter&quot;
             commit-interval=&quot;2&quot; retry-limit=&quot;3&quot;&gt;
         &lt;retryable-exception-classes&gt;
            &lt;include class=&quot;org.springframework.dao.DeadlockLoserDataAccessException&quot;/&gt;
         &lt;/retryable-exception-classes&gt;
      &lt;/chunk&gt;
   &lt;/tasklet&gt;
&lt;/step&gt;
</code></pre></div><p>In Java, retry should be configured as follows:</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Step step1() {
	return this.stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;String, String&gt;chunk(2)
				.reader(itemReader())
				.writer(itemWriter())
				.faultTolerant()
				.retryLimit(3)
				.retry(DeadlockLoserDataAccessException.class)
				.build();
}
</code></pre></div><p>The <code>Step</code> allows a limit for the number of times an individual item can be retried and a
list of exceptions that are 'retryable'. More details on how retry works can be found in<a href="/en/spring-batch/retry.html#retry">retry</a>.</p> <h4 id="controlling-rollback"><a href="#controlling-rollback" class="header-anchor">#</a> Controlling Rollback</h4> <p>By default, regardless of retry or skip, any exceptions thrown from the <code>ItemWriter</code>cause the transaction controlled by the <code>Step</code> to rollback. If skip is configured as
described earlier, exceptions thrown from the <code>ItemReader</code> do not cause a rollback.
However, there are many scenarios in which exceptions thrown from the <code>ItemWriter</code> should
not cause a rollback, because no action has taken place to invalidate the transaction.
For this reason, the <code>Step</code> can be configured with a list of exceptions that should not
cause rollback.</p> <p>In XML, you can control rollback as follows:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot;&gt;
   &lt;tasklet&gt;
      &lt;chunk reader=&quot;itemReader&quot; writer=&quot;itemWriter&quot; commit-interval=&quot;2&quot;/&gt;
      &lt;no-rollback-exception-classes&gt;
         &lt;include class=&quot;org.springframework.batch.item.validator.ValidationException&quot;/&gt;
      &lt;/no-rollback-exception-classes&gt;
   &lt;/tasklet&gt;
&lt;/step&gt;
</code></pre></div><p>In Java, you can control rollback as follows:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Step step1() {
	return this.stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;String, String&gt;chunk(2)
				.reader(itemReader())
				.writer(itemWriter())
				.faultTolerant()
				.noRollback(ValidationException.class)
				.build();
}
</code></pre></div><h5 id="transactional-readers"><a href="#transactional-readers" class="header-anchor">#</a> Transactional Readers</h5> <p>The basic contract of the <code>ItemReader</code> is that it is forward only. The step buffers
reader input, so that in the case of a rollback, the items do not need to be re-read
from the reader. However, there are certain scenarios in which the reader is built on
top of a transactional resource, such as a JMS queue. In this case, since the queue is
tied to the transaction that is rolled back, the messages that have been pulled from the
queue are put back on. For this reason, the step can be configured to not buffer the
items.</p> <p>The following example shows how to create reader that does not buffer items in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot;&gt;
    &lt;tasklet&gt;
        &lt;chunk reader=&quot;itemReader&quot; writer=&quot;itemWriter&quot; commit-interval=&quot;2&quot;
               is-reader-transactional-queue=&quot;true&quot;/&gt;
    &lt;/tasklet&gt;
&lt;/step&gt;
</code></pre></div><p>The following example shows how to create reader that does not buffer items in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Step step1() {
	return this.stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;String, String&gt;chunk(2)
				.reader(itemReader())
				.writer(itemWriter())
				.readerIsTransactionalQueue()
				.build();
}
</code></pre></div><h4 id="transaction-attributes"><a href="#transaction-attributes" class="header-anchor">#</a> Transaction Attributes</h4> <p>Transaction attributes can be used to control the <code>isolation</code>, <code>propagation</code>, and<code>timeout</code> settings. More information on setting transaction attributes can be found in
the<a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction" target="_blank" rel="noopener noreferrer">Spring
core documentation<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>.</p> <p>The following example sets the <code>isolation</code>, <code>propagation</code>, and <code>timeout</code> transaction
attributes in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot;&gt;
    &lt;tasklet&gt;
        &lt;chunk reader=&quot;itemReader&quot; writer=&quot;itemWriter&quot; commit-interval=&quot;2&quot;/&gt;
        &lt;transaction-attributes isolation=&quot;DEFAULT&quot;
                                propagation=&quot;REQUIRED&quot;
                                timeout=&quot;30&quot;/&gt;
    &lt;/tasklet&gt;
&lt;/step&gt;
</code></pre></div><p>The following example sets the <code>isolation</code>, <code>propagation</code>, and <code>timeout</code> transaction
attributes in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Step step1() {
	DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
	attribute.setPropagationBehavior(Propagation.REQUIRED.value());
	attribute.setIsolationLevel(Isolation.DEFAULT.value());
	attribute.setTimeout(30);

	return this.stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;String, String&gt;chunk(2)
				.reader(itemReader())
				.writer(itemWriter())
				.transactionAttribute(attribute)
				.build();
}
</code></pre></div><h4 id="registering-itemstream-with-a-step"><a href="#registering-itemstream-with-a-step" class="header-anchor">#</a> Registering <code>ItemStream</code> with a <code>Step</code></h4> <p>The step has to take care of <code>ItemStream</code> callbacks at the necessary points in its
lifecycle (For more information on the <code>ItemStream</code> interface, see<a href="/en/spring-batch/readersAndWriters.html#itemStream">ItemStream</a>). This is vital if a step fails and might
need to be restarted, because the <code>ItemStream</code> interface is where the step gets the
information it needs about persistent state between executions.</p> <p>If the <code>ItemReader</code>, <code>ItemProcessor</code>, or <code>ItemWriter</code> itself implements the <code>ItemStream</code>interface, then these are registered automatically. Any other streams need to be
registered separately. This is often the case where indirect dependencies, such as
delegates, are injected into the reader and writer. A stream can be registered on the<code>step</code> through the 'stream' element.</p> <p>The following example shows how to register a <code>stream</code> on a <code>step</code> in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot;&gt;
    &lt;tasklet&gt;
        &lt;chunk reader=&quot;itemReader&quot; writer=&quot;compositeWriter&quot; commit-interval=&quot;2&quot;&gt;
            &lt;streams&gt;
                &lt;stream ref=&quot;fileItemWriter1&quot;/&gt;
                &lt;stream ref=&quot;fileItemWriter2&quot;/&gt;
            &lt;/streams&gt;
        &lt;/chunk&gt;
    &lt;/tasklet&gt;
&lt;/step&gt;

&lt;beans:bean id=&quot;compositeWriter&quot;
            class=&quot;org.springframework.batch.item.support.CompositeItemWriter&quot;&gt;
    &lt;beans:property name=&quot;delegates&quot;&gt;
        &lt;beans:list&gt;
            &lt;beans:ref bean=&quot;fileItemWriter1&quot; /&gt;
            &lt;beans:ref bean=&quot;fileItemWriter2&quot; /&gt;
        &lt;/beans:list&gt;
    &lt;/beans:property&gt;
&lt;/beans:bean&gt;
</code></pre></div><p>The following example shows how to register a <code>stream</code> on a <code>step</code> in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Step step1() {
	return this.stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;String, String&gt;chunk(2)
				.reader(itemReader())
				.writer(compositeItemWriter())
				.stream(fileItemWriter1())
				.stream(fileItemWriter2())
				.build();
}

/**
 * In Spring Batch 4, the CompositeItemWriter implements ItemStream so this isn't
 * necessary, but used for an example.
 */
@Bean
public CompositeItemWriter compositeItemWriter() {
	List&lt;ItemWriter&gt; writers = new ArrayList&lt;&gt;(2);
	writers.add(fileItemWriter1());
	writers.add(fileItemWriter2());

	CompositeItemWriter itemWriter = new CompositeItemWriter();

	itemWriter.setDelegates(writers);

	return itemWriter;
}
</code></pre></div><p>In the example above, the <code>CompositeItemWriter</code> is not an <code>ItemStream</code>, but both of its
delegates are. Therefore, both delegate writers must be explicitly registered as streams
in order for the framework to handle them correctly. The <code>ItemReader</code> does not need to be
explicitly registered as a stream because it is a direct property of the <code>Step</code>. The step
is now restartable, and the state of the reader and writer is correctly persisted in the
event of a failure.</p> <h4 id="intercepting-step-execution"><a href="#intercepting-step-execution" class="header-anchor">#</a> Intercepting <code>Step</code> Execution</h4> <p>Just as with the <code>Job</code>, there are many events during the execution of a <code>Step</code> where a
user may need to perform some functionality. For example, in order to write out to a flat
file that requires a footer, the <code>ItemWriter</code> needs to be notified when the <code>Step</code> has
been completed, so that the footer can be written. This can be accomplished with one of many<code>Step</code> scoped listeners.</p> <p>Any class that implements one of the extensions of <code>StepListener</code> (but not that interface
itself since it is empty) can be applied to a step through the <code>listeners</code> element.
The <code>listeners</code> element is valid inside a step, tasklet, or chunk declaration. It is
recommended that you declare the listeners at the level at which its function applies,
or, if it is multi-featured (such as <code>StepExecutionListener</code> and <code>ItemReadListener</code>),
then declare it at the most granular level where it applies.</p> <p>The following example shows a listener applied at the chunk level in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot;&gt;
    &lt;tasklet&gt;
        &lt;chunk reader=&quot;reader&quot; writer=&quot;writer&quot; commit-interval=&quot;10&quot;/&gt;
        &lt;listeners&gt;
            &lt;listener ref=&quot;chunkListener&quot;/&gt;
        &lt;/listeners&gt;
    &lt;/tasklet&gt;
&lt;/step&gt;
</code></pre></div><p>The following example shows a listener applied at the chunk level in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Step step1() {
	return this.stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;String, String&gt;chunk(10)
				.reader(reader())
				.writer(writer())
				.listener(chunkListener())
				.build();
}
</code></pre></div><p>An <code>ItemReader</code>, <code>ItemWriter</code> or <code>ItemProcessor</code> that itself implements one of the<code>StepListener</code> interfaces is registered automatically with the <code>Step</code> if using the
namespace <code>&lt;step&gt;</code> element or one of the <code>*StepFactoryBean</code> factories. This only
applies to components directly injected into the <code>Step</code>. If the listener is nested inside
another component, it needs to be explicitly registered (as described previously under<a href="#registeringItemStreams">Registering <code>ItemStream</code> with a <code>Step</code></a>).</p> <p>In addition to the <code>StepListener</code> interfaces, annotations are provided to address the
same concerns. Plain old Java objects can have methods with these annotations that are
then converted into the corresponding <code>StepListener</code> type. It is also common to annotate
custom implementations of chunk components such as <code>ItemReader</code> or <code>ItemWriter</code> or<code>Tasklet</code>. The annotations are analyzed by the XML parser for the <code>&lt;listener/&gt;</code> elements
as well as registered with the <code>listener</code> methods in the builders, so all you need to do
is use the XML namespace or builders to register the listeners with a step.</p> <h5 id="stepexecutionlistener"><a href="#stepexecutionlistener" class="header-anchor">#</a> <code>StepExecutionListener</code></h5> <p><code>StepExecutionListener</code> represents the most generic listener for <code>Step</code> execution. It
allows for notification before a <code>Step</code> is started and after it ends, whether it ended
normally or failed, as shown in the following example:</p> <div class="language- extra-class"><pre class="language-text"><code>public interface StepExecutionListener extends StepListener {

    void beforeStep(StepExecution stepExecution);

    ExitStatus afterStep(StepExecution stepExecution);

}
</code></pre></div><p><code>ExitStatus</code> is the return type of <code>afterStep</code> in order to allow listeners the chance to
modify the exit code that is returned upon completion of a <code>Step</code>.</p> <p>The annotations corresponding to this interface are:</p> <ul><li><p><code>@BeforeStep</code></p></li> <li><p><code>@AfterStep</code></p></li></ul> <h5 id="chunklistener"><a href="#chunklistener" class="header-anchor">#</a> <code>ChunkListener</code></h5> <p>A chunk is defined as the items processed within the scope of a transaction. Committing a
transaction, at each commit interval, commits a 'chunk'. A <code>ChunkListener</code> can be used to
perform logic before a chunk begins processing or after a chunk has completed
successfully, as shown in the following interface definition:</p> <div class="language- extra-class"><pre class="language-text"><code>public interface ChunkListener extends StepListener {

    void beforeChunk(ChunkContext context);
    void afterChunk(ChunkContext context);
    void afterChunkError(ChunkContext context);

}
</code></pre></div><p>The beforeChunk method is called after the transaction is started but before read is
called on the <code>ItemReader</code>. Conversely, <code>afterChunk</code> is called after the chunk has been
committed (and not at all if there is a rollback).</p> <p>The annotations corresponding to this interface are:</p> <ul><li><p><code>@BeforeChunk</code></p></li> <li><p><code>@AfterChunk</code></p></li> <li><p><code>@AfterChunkError</code></p></li></ul> <p>A <code>ChunkListener</code> can be applied when there is no chunk declaration. The <code>TaskletStep</code> is
responsible for calling the <code>ChunkListener</code>, so it applies to a non-item-oriented tasklet
as well (it is called before and after the tasklet).</p> <h5 id="itemreadlistener"><a href="#itemreadlistener" class="header-anchor">#</a> <code>ItemReadListener</code></h5> <p>When discussing skip logic previously, it was mentioned that it may be beneficial to log
the skipped records, so that they can be dealt with later. In the case of read errors,
this can be done with an <code>ItemReaderListener</code>, as shown in the following interface
definition:</p> <div class="language- extra-class"><pre class="language-text"><code>public interface ItemReadListener&lt;T&gt; extends StepListener {

    void beforeRead();
    void afterRead(T item);
    void onReadError(Exception ex);

}
</code></pre></div><p>The <code>beforeRead</code> method is called before each call to read on the <code>ItemReader</code>. The<code>afterRead</code> method is called after each successful call to read and is passed the item
that was read. If there was an error while reading, the <code>onReadError</code> method is called.
The exception encountered is provided so that it can be logged.</p> <p>The annotations corresponding to this interface are:</p> <ul><li><p><code>@BeforeRead</code></p></li> <li><p><code>@AfterRead</code></p></li> <li><p><code>@OnReadError</code></p></li></ul> <h5 id="itemprocesslistener"><a href="#itemprocesslistener" class="header-anchor">#</a> <code>ItemProcessListener</code></h5> <p>Just as with the <code>ItemReadListener</code>, the processing of an item can be 'listened' to, as
shown in the following interface definition:</p> <div class="language- extra-class"><pre class="language-text"><code>public interface ItemProcessListener&lt;T, S&gt; extends StepListener {

    void beforeProcess(T item);
    void afterProcess(T item, S result);
    void onProcessError(T item, Exception e);

}
</code></pre></div><p>The <code>beforeProcess</code> method is called before <code>process</code> on the <code>ItemProcessor</code> and is
handed the item that is to be processed. The <code>afterProcess</code> method is called after the
item has been successfully processed. If there was an error while processing, the<code>onProcessError</code> method is called. The exception encountered and the item that was
attempted to be processed are provided, so that they can be logged.</p> <p>The annotations corresponding to this interface are:</p> <ul><li><p><code>@BeforeProcess</code></p></li> <li><p><code>@AfterProcess</code></p></li> <li><p><code>@OnProcessError</code></p></li></ul> <h5 id="itemwritelistener"><a href="#itemwritelistener" class="header-anchor">#</a> <code>ItemWriteListener</code></h5> <p>The writing of an item can be 'listened' to with the <code>ItemWriteListener</code>, as shown in the
following interface definition:</p> <div class="language- extra-class"><pre class="language-text"><code>public interface ItemWriteListener&lt;S&gt; extends StepListener {

    void beforeWrite(List&lt;? extends S&gt; items);
    void afterWrite(List&lt;? extends S&gt; items);
    void onWriteError(Exception exception, List&lt;? extends S&gt; items);

}
</code></pre></div><p>The <code>beforeWrite</code> method is called before <code>write</code> on the <code>ItemWriter</code> and is handed the
list of items that is written. The <code>afterWrite</code> method is called after the item has been
successfully written. If there was an error while writing, the <code>onWriteError</code> method is
called. The exception encountered and the item that was attempted to be written are
provided, so that they can be logged.</p> <p>The annotations corresponding to this interface are:</p> <ul><li><p><code>@BeforeWrite</code></p></li> <li><p><code>@AfterWrite</code></p></li> <li><p><code>@OnWriteError</code></p></li></ul> <h5 id="skiplistener"><a href="#skiplistener" class="header-anchor">#</a> <code>SkipListener</code></h5> <p><code>ItemReadListener</code>, <code>ItemProcessListener</code>, and <code>ItemWriteListener</code> all provide mechanisms
for being notified of errors, but none informs you that a record has actually been
skipped. <code>onWriteError</code>, for example, is called even if an item is retried and
successful. For this reason, there is a separate interface for tracking skipped items, as
shown in the following interface definition:</p> <div class="language- extra-class"><pre class="language-text"><code>public interface SkipListener&lt;T,S&gt; extends StepListener {

    void onSkipInRead(Throwable t);
    void onSkipInProcess(T item, Throwable t);
    void onSkipInWrite(S item, Throwable t);

}
</code></pre></div><p><code>onSkipInRead</code> is called whenever an item is skipped while reading. It should be noted
that rollbacks may cause the same item to be registered as skipped more than once.<code>onSkipInWrite</code> is called when an item is skipped while writing. Because the item has
been read successfully (and not skipped), it is also provided the item itself as an
argument.</p> <p>The annotations corresponding to this interface are:</p> <ul><li><p><code>@OnSkipInRead</code></p></li> <li><p><code>@OnSkipInWrite</code></p></li> <li><p><code>@OnSkipInProcess</code></p></li></ul> <h6 id="skiplisteners-and-transactions"><a href="#skiplisteners-and-transactions" class="header-anchor">#</a> SkipListeners and Transactions</h6> <p>One of the most common use cases for a <code>SkipListener</code> is to log out a skipped item, so
that another batch process or even human process can be used to evaluate and fix the
issue leading to the skip. Because there are many cases in which the original transaction
may be rolled back, Spring Batch makes two guarantees:</p> <ol><li><p>The appropriate skip method (depending on when the error happened) is called only once
per item.</p></li> <li><p>The <code>SkipListener</code> is always called just before the transaction is committed. This is
to ensure that any transactional resources call by the listener are not rolled back by a
failure within the <code>ItemWriter</code>.</p></li></ol> <h3 id="taskletstep"><a href="#taskletstep" class="header-anchor">#</a> <code>TaskletStep</code></h3> <p><a href="#chunkOrientedProcessing">Chunk-oriented processing</a> is not the only way to process in a<code>Step</code>. What if a <code>Step</code> must consist of a simple stored procedure call? You could
implement the call as an <code>ItemReader</code> and return null after the procedure finishes.
However, doing so is a bit unnatural, since there would need to be a no-op <code>ItemWriter</code>.
Spring Batch provides the <code>TaskletStep</code> for this scenario.</p> <p><code>Tasklet</code> is a simple interface that has one method, <code>execute</code>, which is called
repeatedly by the <code>TaskletStep</code> until it either returns <code>RepeatStatus.FINISHED</code> or throws
an exception to signal a failure. Each call to a <code>Tasklet</code> is wrapped in a transaction.<code>Tasklet</code> implementors might call a stored procedure, a script, or a simple SQL update
statement.</p> <p>To create a <code>TaskletStep</code> in XML, the 'ref' attribute of the <code>&lt;tasklet/&gt;</code> element should
reference a bean that defines a <code>Tasklet</code> object. No <code>&lt;chunk/&gt;</code> element should be used
within the <code>&lt;tasklet/&gt;</code>. The following example shows a simple tasklet:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot;&gt;
    &lt;tasklet ref=&quot;myTasklet&quot;/&gt;
&lt;/step&gt;
</code></pre></div><p>To create a <code>TaskletStep</code> in Java, the bean passed to the <code>tasklet</code> method of the builder
should implement the <code>Tasklet</code> interface. No call to <code>chunk</code> should be called when
building a <code>TaskletStep</code>. The following example shows a simple tasklet:</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Step step1() {
    return this.stepBuilderFactory.get(&quot;step1&quot;)
    			.tasklet(myTasklet())
    			.build();
}
</code></pre></div><table><thead><tr><th></th> <th><code>TaskletStep</code> automatically registers the<br>tasklet as a <code>StepListener</code> if it implements the <code>StepListener</code>interface.</th></tr></thead> <tbody></tbody></table> <h4 id="taskletadapter"><a href="#taskletadapter" class="header-anchor">#</a> <code>TaskletAdapter</code></h4> <p>As with other adapters for the <code>ItemReader</code> and <code>ItemWriter</code> interfaces, the <code>Tasklet</code>interface contains an implementation that allows for adapting itself to any pre-existing
class: <code>TaskletAdapter</code>. An example where this may be useful is an existing DAO that is
used to update a flag on a set of records. The <code>TaskletAdapter</code> can be used to call this
class without having to write an adapter for the <code>Tasklet</code> interface.</p> <p>The following example shows how to define a <code>TaskletAdapter</code> in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;bean id=&quot;myTasklet&quot; class=&quot;o.s.b.core.step.tasklet.MethodInvokingTaskletAdapter&quot;&gt;
    &lt;property name=&quot;targetObject&quot;&gt;
        &lt;bean class=&quot;org.mycompany.FooDao&quot;/&gt;
    &lt;/property&gt;
    &lt;property name=&quot;targetMethod&quot; value=&quot;updateFoo&quot; /&gt;
&lt;/bean&gt;
</code></pre></div><p>The following example shows how to define a <code>TaskletAdapter</code> in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public MethodInvokingTaskletAdapter myTasklet() {
	MethodInvokingTaskletAdapter adapter = new MethodInvokingTaskletAdapter();

	adapter.setTargetObject(fooDao());
	adapter.setTargetMethod(&quot;updateFoo&quot;);

	return adapter;
}
</code></pre></div><h4 id="example-tasklet-implementation"><a href="#example-tasklet-implementation" class="header-anchor">#</a> Example <code>Tasklet</code> Implementation</h4> <p>Many batch jobs contain steps that must be done before the main processing begins in
order to set up various resources or after processing has completed to cleanup those
resources. In the case of a job that works heavily with files, it is often necessary to
delete certain files locally after they have been uploaded successfully to another
location. The following example (taken from the<a href="https://github.com/spring-projects/spring-batch/tree/master/spring-batch-samples" target="_blank" rel="noopener noreferrer">Spring
Batch samples project<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>) is a <code>Tasklet</code> implementation with just such a responsibility:</p> <div class="language- extra-class"><pre class="language-text"><code>public class FileDeletingTasklet implements Tasklet, InitializingBean {

    private Resource directory;

    public RepeatStatus execute(StepContribution contribution,
                                ChunkContext chunkContext) throws Exception {
        File dir = directory.getFile();
        Assert.state(dir.isDirectory());

        File[] files = dir.listFiles();
        for (int i = 0; i &lt; files.length; i++) {
            boolean deleted = files[i].delete();
            if (!deleted) {
                throw new UnexpectedJobExecutionException(&quot;Could not delete file &quot; +
                                                          files[i].getPath());
            }
        }
        return RepeatStatus.FINISHED;
    }

    public void setDirectoryResource(Resource directory) {
        this.directory = directory;
    }

    public void afterPropertiesSet() throws Exception {
        Assert.notNull(directory, &quot;directory must be set&quot;);
    }
}
</code></pre></div><p>The preceding <code>tasklet</code> implementation deletes all files within a given directory. It
should be noted that the <code>execute</code> method is called only once. All that is left is to
reference the <code>tasklet</code> from the <code>step</code>.</p> <p>The following example shows how to reference the <code>tasklet</code> from the <code>step</code> in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;job id=&quot;taskletJob&quot;&gt;
    &lt;step id=&quot;deleteFilesInDir&quot;&gt;
       &lt;tasklet ref=&quot;fileDeletingTasklet&quot;/&gt;
    &lt;/step&gt;
&lt;/job&gt;

&lt;beans:bean id=&quot;fileDeletingTasklet&quot;
            class=&quot;org.springframework.batch.sample.tasklet.FileDeletingTasklet&quot;&gt;
    &lt;beans:property name=&quot;directoryResource&quot;&gt;
        &lt;beans:bean id=&quot;directory&quot;
                    class=&quot;org.springframework.core.io.FileSystemResource&quot;&gt;
            &lt;beans:constructor-arg value=&quot;target/test-outputs/test-dir&quot; /&gt;
        &lt;/beans:bean&gt;
    &lt;/beans:property&gt;
&lt;/beans:bean&gt;
</code></pre></div><p>The following example shows how to reference the <code>tasklet</code> from the <code>step</code> in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job taskletJob() {
	return this.jobBuilderFactory.get(&quot;taskletJob&quot;)
				.start(deleteFilesInDir())
				.build();
}

@Bean
public Step deleteFilesInDir() {
	return this.stepBuilderFactory.get(&quot;deleteFilesInDir&quot;)
				.tasklet(fileDeletingTasklet())
				.build();
}

@Bean
public FileDeletingTasklet fileDeletingTasklet() {
	FileDeletingTasklet tasklet = new FileDeletingTasklet();

	tasklet.setDirectoryResource(new FileSystemResource(&quot;target/test-outputs/test-dir&quot;));

	return tasklet;
}
</code></pre></div><h3 id="controlling-step-flow"><a href="#controlling-step-flow" class="header-anchor">#</a> Controlling Step Flow</h3> <p>With the ability to group steps together within an owning job comes the need to be able
to control how the job &quot;flows&quot; from one step to another. The failure of a <code>Step</code> does not
necessarily mean that the <code>Job</code> should fail. Furthermore, there may be more than one type
of 'success' that determines which <code>Step</code> should be executed next. Depending upon how a
group of <code>Steps</code> is configured, certain steps may not even be processed at all.</p> <h4 id="sequential-flow"><a href="#sequential-flow" class="header-anchor">#</a> Sequential Flow</h4> <p>The simplest flow scenario is a job where all of the steps execute sequentially, as shown
in the following image:</p> <p><img src="https://docs.spring.io/spring-batch/docs/current/reference/html/images/sequential-flow.png" alt="Sequential Flow"></p> <p>Figure 4. Sequential Flow</p> <p>This can be achieved by using the 'next' in a <code>step</code>.</p> <p>The following example shows how to use the <code>next</code> attribute in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;job id=&quot;job&quot;&gt;
    &lt;step id=&quot;stepA&quot; parent=&quot;s1&quot; next=&quot;stepB&quot; /&gt;
    &lt;step id=&quot;stepB&quot; parent=&quot;s2&quot; next=&quot;stepC&quot;/&gt;
    &lt;step id=&quot;stepC&quot; parent=&quot;s3&quot; /&gt;
&lt;/job&gt;
</code></pre></div><p>The following example shows how to use the <code>next()</code> method in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job job() {
	return this.jobBuilderFactory.get(&quot;job&quot;)
				.start(stepA())
				.next(stepB())
				.next(stepC())
				.build();
}
</code></pre></div><p>In the scenario above, 'step A' runs first because it is the first <code>Step</code> listed. If
'step A' completes normally, then 'step B' runs, and so on. However, if 'step A' fails,
then the entire <code>Job</code> fails and 'step B' does not execute.</p> <table><thead><tr><th></th> <th>With the Spring Batch XML namespace, the first step listed in the configuration is<em>always</em> the first step run by the <code>Job</code>. The order of the other step elements does not<br>matter, but the first step must always appear first in the xml.</th></tr></thead> <tbody></tbody></table> <h4 id="conditional-flow"><a href="#conditional-flow" class="header-anchor">#</a> Conditional Flow</h4> <p>In the example above, there are only two possibilities:</p> <ol><li><p>The <code>step</code> is successful and the next <code>step</code> should be executed.</p></li> <li><p>The <code>step</code> failed and, thus, the <code>job</code> should fail.</p></li></ol> <p>In many cases, this may be sufficient. However, what about a scenario in which the
failure of a <code>step</code> should trigger a different <code>step</code>, rather than causing failure? The
following image shows such a flow:</p> <p><img src="https://docs.spring.io/spring-batch/docs/current/reference/html/images/conditional-flow.png" alt="Conditional Flow"></p> <p>Figure 5. Conditional Flow</p> <p>In order to handle more complex scenarios, the Spring Batch XML namespace allows transitions
elements to be defined within the step element. One such transition is the <code>next</code>element. Like the <code>next</code> attribute, the <code>next</code> element tells the <code>Job</code> which <code>Step</code> to
execute next. However, unlike the attribute, any number of <code>next</code> elements are allowed on
a given <code>Step</code>, and there is no default behavior in the case of failure. This means that, if
transition elements are used, then all of the behavior for the <code>Step</code> transitions must be
defined explicitly. Note also that a single step cannot have both a <code>next</code> attribute and
a <code>transition</code> element.</p> <p>The <code>next</code> element specifies a pattern to match and the step to execute next, as shown in
the following example:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;job id=&quot;job&quot;&gt;
    &lt;step id=&quot;stepA&quot; parent=&quot;s1&quot;&gt;
        &lt;next on=&quot;*&quot; to=&quot;stepB&quot; /&gt;
        &lt;next on=&quot;FAILED&quot; to=&quot;stepC&quot; /&gt;
    &lt;/step&gt;
    &lt;step id=&quot;stepB&quot; parent=&quot;s2&quot; next=&quot;stepC&quot; /&gt;
    &lt;step id=&quot;stepC&quot; parent=&quot;s3&quot; /&gt;
&lt;/job&gt;
</code></pre></div><p>The Java API offers a fluent set of methods that let you specify the flow and what to do
when a step fails. The following example shows how to specify one step (<code>stepA</code>) and then
proceed to either of two different steps (<code>stepB</code> and <code>stepC</code>), depending on whether<code>stepA</code> succeeds:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job job() {
	return this.jobBuilderFactory.get(&quot;job&quot;)
				.start(stepA())
				.on(&quot;*&quot;).to(stepB())
				.from(stepA()).on(&quot;FAILED&quot;).to(stepC())
				.end()
				.build();
}
</code></pre></div><p>When using XML configuration, the <code>on</code> attribute of a transition element uses a simple
pattern-matching scheme to match the <code>ExitStatus</code> that results from the execution of the<code>Step</code>.</p> <p>When using java configuration, the <code>on()</code> method uses a simple pattern-matching scheme to
match the <code>ExitStatus</code> that results from the execution of the <code>Step</code>.</p> <p>Only two special characters are allowed in the pattern:</p> <ul><li><p>&quot;*&quot; matches zero or more characters</p></li> <li><p>&quot;?&quot; matches exactly one character</p></li></ul> <p>For example, &quot;c*t&quot; matches &quot;cat&quot; and &quot;count&quot;, while &quot;c?t&quot; matches &quot;cat&quot; but not &quot;count&quot;.</p> <p>While there is no limit to the number of transition elements on a <code>Step</code>, if the <code>Step</code>execution results in an <code>ExitStatus</code> that is not covered by an element, then the
framework throws an exception and the <code>Job</code> fails. The framework automatically orders
transitions from most specific to least specific. This means that, even if the ordering
were swapped for &quot;stepA&quot; in the example above, an <code>ExitStatus</code> of &quot;FAILED&quot; would still go
to &quot;stepC&quot;.</p> <h5 id="batch-status-versus-exit-status"><a href="#batch-status-versus-exit-status" class="header-anchor">#</a> Batch Status Versus Exit Status</h5> <p>When configuring a <code>Job</code> for conditional flow, it is important to understand the
difference between <code>BatchStatus</code> and <code>ExitStatus</code>. <code>BatchStatus</code> is an enumeration that
is a property of both <code>JobExecution</code> and <code>StepExecution</code> and is used by the framework to
record the status of a <code>Job</code> or <code>Step</code>. It can be one of the following values:<code>COMPLETED</code>, <code>STARTING</code>, <code>STARTED</code>, <code>STOPPING</code>, <code>STOPPED</code>, <code>FAILED</code>, <code>ABANDONED</code>, or<code>UNKNOWN</code>. Most of them are self explanatory: <code>COMPLETED</code> is the status set when a step
or job has completed successfully, <code>FAILED</code> is set when it fails, and so on.</p> <p>The following example contains the 'next' element when using XML configuration:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;next on=&quot;FAILED&quot; to=&quot;stepB&quot; /&gt;
</code></pre></div><p>The following example contains the 'on' element when using Java Configuration:</p> <div class="language- extra-class"><pre class="language-text"><code>...
.from(stepA()).on(&quot;FAILED&quot;).to(stepB())
...
</code></pre></div><p>At first glance, it would appear that 'on' references the <code>BatchStatus</code> of the <code>Step</code> to
which it belongs. However, it actually references the <code>ExitStatus</code> of the <code>Step</code>. As the
name implies, <code>ExitStatus</code> represents the status of a <code>Step</code> after it finishes execution.</p> <p>More specifically, when using XML configuration, the 'next' element shown in the
preceding XML configuration example references the exit code of <code>ExitStatus</code>.</p> <p>When using Java configuration, the 'on()' method shown in the preceding
Java configuration example references the exit code of <code>ExitStatus</code>.</p> <p>In English, it says: &quot;go to stepB if the exit code is <code>FAILED</code> &quot;. By default, the exit
code is always the same as the <code>BatchStatus</code> for the <code>Step</code>, which is why the entry above
works. However, what if the exit code needs to be different? A good example comes from
the skip sample job within the samples project:</p> <p>The following example shows how to work with a different exit code in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot; parent=&quot;s1&quot;&gt;
    &lt;end on=&quot;FAILED&quot; /&gt;
    &lt;next on=&quot;COMPLETED WITH SKIPS&quot; to=&quot;errorPrint1&quot; /&gt;
    &lt;next on=&quot;*&quot; to=&quot;step2&quot; /&gt;
&lt;/step&gt;
</code></pre></div><p>The following example shows how to work with a different exit code in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job job() {
	return this.jobBuilderFactory.get(&quot;job&quot;)
			.start(step1()).on(&quot;FAILED&quot;).end()
			.from(step1()).on(&quot;COMPLETED WITH SKIPS&quot;).to(errorPrint1())
			.from(step1()).on(&quot;*&quot;).to(step2())
			.end()
			.build();
}
</code></pre></div><p><code>step1</code> has three possibilities:</p> <ol><li><p>The <code>Step</code> failed, in which case the job should fail.</p></li> <li><p>The <code>Step</code> completed successfully.</p></li> <li><p>The <code>Step</code> completed successfully but with an exit code of 'COMPLETED WITH SKIPS'. In
this case, a different step should be run to handle the errors.</p></li></ol> <p>The preceding configuration works. However, something needs to change the exit code based on
the condition of the execution having skipped records, as shown in the following example:</p> <div class="language- extra-class"><pre class="language-text"><code>public class SkipCheckingListener extends StepExecutionListenerSupport {
    public ExitStatus afterStep(StepExecution stepExecution) {
        String exitCode = stepExecution.getExitStatus().getExitCode();
        if (!exitCode.equals(ExitStatus.FAILED.getExitCode()) &amp;&amp;
              stepExecution.getSkipCount() &gt; 0) {
            return new ExitStatus(&quot;COMPLETED WITH SKIPS&quot;);
        }
        else {
            return null;
        }
    }
}
</code></pre></div><p>The above code is a <code>StepExecutionListener</code> that first checks to make sure the <code>Step</code> was
successful and then checks to see if the skip count on the <code>StepExecution</code> is higher than
0. If both conditions are met, a new <code>ExitStatus</code> with an exit code of<code>COMPLETED WITH SKIPS</code> is returned.</p> <h4 id="configuring-for-stop"><a href="#configuring-for-stop" class="header-anchor">#</a> Configuring for Stop</h4> <p>After the discussion of <a href="#batchStatusVsExitStatus">BatchStatus and ExitStatus</a>,
one might wonder how the <code>BatchStatus</code> and <code>ExitStatus</code> are determined for the <code>Job</code>.
While these statuses are determined for the <code>Step</code> by the code that is executed, the
statuses for the <code>Job</code> are determined based on the configuration.</p> <p>So far, all of the job configurations discussed have had at least one final <code>Step</code> with
no transitions.</p> <p>In the following XML example, after the <code>step</code> executes, the <code>Job</code> ends:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;stepC&quot; parent=&quot;s3&quot;/&gt;
</code></pre></div><p>In the following Java example, after the <code>step</code> executes, the <code>Job</code> ends:</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job job() {
	return this.jobBuilderFactory.get(&quot;job&quot;)
				.start(step1())
				.build();
}
</code></pre></div><p>If no transitions are defined for a <code>Step</code>, then the status of the <code>Job</code> is defined as
follows:</p> <ul><li><p>If the <code>Step</code> ends with <code>ExitStatus</code> FAILED, then the <code>BatchStatus</code> and <code>ExitStatus</code> of
the <code>Job</code> are both <code>FAILED</code>.</p></li> <li><p>Otherwise, the <code>BatchStatus</code> and <code>ExitStatus</code> of the <code>Job</code> are both <code>COMPLETED</code>.</p></li></ul> <p>While this method of terminating a batch job is sufficient for some batch jobs, such as a
simple sequential step job, custom defined job-stopping scenarios may be required. For
this purpose, Spring Batch provides three transition elements to stop a <code>Job</code> (in
addition to the <a href="#nextElement"><code>next</code> element</a> that we discussed previously).
Each of these stopping elements stops a <code>Job</code> with a particular <code>BatchStatus</code>. It is
important to note that the stop transition elements have no effect on either the<code>BatchStatus</code> or <code>ExitStatus</code> of any <code>Steps</code> in the <code>Job</code>. These elements affect only the
final statuses of the <code>Job</code>. For example, it is possible for every step in a job to have
a status of <code>FAILED</code> but for the job to have a status of <code>COMPLETED</code>.</p> <h5 id="ending-at-a-step"><a href="#ending-at-a-step" class="header-anchor">#</a> Ending at a Step</h5> <p>Configuring a step end instructs a <code>Job</code> to stop with a <code>BatchStatus</code> of <code>COMPLETED</code>. A<code>Job</code> that has finished with status <code>COMPLETED</code> cannot be restarted (the framework throws
a <code>JobInstanceAlreadyCompleteException</code>).</p> <p>When using XML configuration, the 'end' element is used for this task. The <code>end</code> element
also allows for an optional 'exit-code' attribute that can be used to customize the<code>ExitStatus</code> of the <code>Job</code>. If no 'exit-code' attribute is given, then the <code>ExitStatus</code> is<code>COMPLETED</code> by default, to match the <code>BatchStatus</code>.</p> <p>When using Java configuration, the 'end' method is used for this task. The <code>end</code> method
also allows for an optional 'exitStatus' parameter that can be used to customize the<code>ExitStatus</code> of the <code>Job</code>. If no 'exitStatus' value is provided, then the <code>ExitStatus</code> is<code>COMPLETED</code> by default, to match the <code>BatchStatus</code>.</p> <p>Consider the following scenario: if <code>step2</code> fails, then the <code>Job</code> stops with a<code>BatchStatus</code> of <code>COMPLETED</code> and an <code>ExitStatus</code> of <code>COMPLETED</code> and <code>step3</code> does not run.
Otherwise, execution moves to <code>step3</code>. Note that if <code>step2</code> fails, the <code>Job</code> is not
restartable (because the status is <code>COMPLETED</code>).</p> <p>The following example shows the scenario in XML:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot; parent=&quot;s1&quot; next=&quot;step2&quot;&gt;

&lt;step id=&quot;step2&quot; parent=&quot;s2&quot;&gt;
    &lt;end on=&quot;FAILED&quot;/&gt;
    &lt;next on=&quot;*&quot; to=&quot;step3&quot;/&gt;
&lt;/step&gt;

&lt;step id=&quot;step3&quot; parent=&quot;s3&quot;&gt;
</code></pre></div><p>The following example shows the scenario in Java:</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job job() {
	return this.jobBuilderFactory.get(&quot;job&quot;)
				.start(step1())
				.next(step2())
				.on(&quot;FAILED&quot;).end()
				.from(step2()).on(&quot;*&quot;).to(step3())
				.end()
				.build();
}
</code></pre></div><h5 id="failing-a-step"><a href="#failing-a-step" class="header-anchor">#</a> Failing a Step</h5> <p>Configuring a step to fail at a given point instructs a <code>Job</code> to stop with a<code>BatchStatus</code> of <code>FAILED</code>. Unlike end, the failure of a <code>Job</code> does not prevent the <code>Job</code>from being restarted.</p> <p>When using XML configuration, the 'fail' element also allows for an optional 'exit-code'
attribute that can be used to customize the <code>ExitStatus</code> of the <code>Job</code>. If no 'exit-code'
attribute is given, then the <code>ExitStatus</code> is <code>FAILED</code> by default, to match the<code>BatchStatus</code>.</p> <p>Consider the following scenario if <code>step2</code> fails, then the <code>Job</code> stops with a<code>BatchStatus</code> of <code>FAILED</code> and an <code>ExitStatus</code> of <code>EARLY TERMINATION</code> and <code>step3</code> does not
execute. Otherwise, execution moves to <code>step3</code>. Additionally, if <code>step2</code> fails and the<code>Job</code> is restarted, then execution begins again on <code>step2</code>.</p> <p>The following example shows the scenario in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot; parent=&quot;s1&quot; next=&quot;step2&quot;&gt;

&lt;step id=&quot;step2&quot; parent=&quot;s2&quot;&gt;
    &lt;fail on=&quot;FAILED&quot; exit-code=&quot;EARLY TERMINATION&quot;/&gt;
    &lt;next on=&quot;*&quot; to=&quot;step3&quot;/&gt;
&lt;/step&gt;

&lt;step id=&quot;step3&quot; parent=&quot;s3&quot;&gt;
</code></pre></div><p>The following example shows the scenario in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job job() {
	return this.jobBuilderFactory.get(&quot;job&quot;)
			.start(step1())
			.next(step2()).on(&quot;FAILED&quot;).fail()
			.from(step2()).on(&quot;*&quot;).to(step3())
			.end()
			.build();
}
</code></pre></div><h5 id="stopping-a-job-at-a-given-step"><a href="#stopping-a-job-at-a-given-step" class="header-anchor">#</a> Stopping a Job at a Given Step</h5> <p>Configuring a job to stop at a particular step instructs a <code>Job</code> to stop with a<code>BatchStatus</code> of <code>STOPPED</code>. Stopping a <code>Job</code> can provide a temporary break in processing,
so that the operator can take some action before restarting the <code>Job</code>.</p> <p>When using XML configuration, a 'stop' element requires a 'restart' attribute that specifies
the step where execution should pick up when the Job is restarted.</p> <p>When using Java configuration, the <code>stopAndRestart</code> method requires a 'restart' attribute
that specifies the step where execution should pick up when the Job is restarted.</p> <p>Consider the following scenario: if <code>step1</code> finishes with <code>COMPLETE</code>, then the job then
stops. Once it is restarted, execution begins on <code>step2</code>.</p> <p>The following listing shows the scenario in XML:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;step id=&quot;step1&quot; parent=&quot;s1&quot;&gt;
    &lt;stop on=&quot;COMPLETED&quot; restart=&quot;step2&quot;/&gt;
&lt;/step&gt;

&lt;step id=&quot;step2&quot; parent=&quot;s2&quot;/&gt;
</code></pre></div><p>The following example shows the scenario in Java:</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job job() {
	return this.jobBuilderFactory.get(&quot;job&quot;)
			.start(step1()).on(&quot;COMPLETED&quot;).stopAndRestart(step2())
			.end()
			.build();
}
</code></pre></div><h4 id="programmatic-flow-decisions"><a href="#programmatic-flow-decisions" class="header-anchor">#</a> Programmatic Flow Decisions</h4> <p>In some situations, more information than the <code>ExitStatus</code> may be required to decide
which step to execute next. In this case, a <code>JobExecutionDecider</code> can be used to assist
in the decision, as shown in the following example:</p> <div class="language- extra-class"><pre class="language-text"><code>public class MyDecider implements JobExecutionDecider {
    public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
        String status;
        if (someCondition()) {
            status = &quot;FAILED&quot;;
        }
        else {
            status = &quot;COMPLETED&quot;;
        }
        return new FlowExecutionStatus(status);
    }
}
</code></pre></div><p>In the following sample job configuration, a <code>decision</code> specifies the decider to use as
well as all of the transitions:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;job id=&quot;job&quot;&gt;
    &lt;step id=&quot;step1&quot; parent=&quot;s1&quot; next=&quot;decision&quot; /&gt;

    &lt;decision id=&quot;decision&quot; decider=&quot;decider&quot;&gt;
        &lt;next on=&quot;FAILED&quot; to=&quot;step2&quot; /&gt;
        &lt;next on=&quot;COMPLETED&quot; to=&quot;step3&quot; /&gt;
    &lt;/decision&gt;

    &lt;step id=&quot;step2&quot; parent=&quot;s2&quot; next=&quot;step3&quot;/&gt;
    &lt;step id=&quot;step3&quot; parent=&quot;s3&quot; /&gt;
&lt;/job&gt;

&lt;beans:bean id=&quot;decider&quot; class=&quot;com.MyDecider&quot;/&gt;
</code></pre></div><p>In the following example, a bean implementing the <code>JobExecutionDecider</code> is passed
directly to the <code>next</code> call when using Java configuration.</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job job() {
	return this.jobBuilderFactory.get(&quot;job&quot;)
			.start(step1())
			.next(decider()).on(&quot;FAILED&quot;).to(step2())
			.from(decider()).on(&quot;COMPLETED&quot;).to(step3())
			.end()
			.build();
}
</code></pre></div><h4 id="split-flows"><a href="#split-flows" class="header-anchor">#</a> Split Flows</h4> <p>Every scenario described so far has involved a <code>Job</code> that executes its steps one at a
time in a linear fashion. In addition to this typical style, Spring Batch also allows
for a job to be configured with parallel flows.</p> <p>The XML namespace allows you to use the 'split' element. As the following example shows,
the 'split' element contains one or more 'flow' elements, where entire separate flows can
be defined. A 'split' element may also contain any of the previously discussed transition
elements, such as the 'next' attribute or the 'next', 'end' or 'fail' elements.</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;split id=&quot;split1&quot; next=&quot;step4&quot;&gt;
    &lt;flow&gt;
        &lt;step id=&quot;step1&quot; parent=&quot;s1&quot; next=&quot;step2&quot;/&gt;
        &lt;step id=&quot;step2&quot; parent=&quot;s2&quot;/&gt;
    &lt;/flow&gt;
    &lt;flow&gt;
        &lt;step id=&quot;step3&quot; parent=&quot;s3&quot;/&gt;
    &lt;/flow&gt;
&lt;/split&gt;
&lt;step id=&quot;step4&quot; parent=&quot;s4&quot;/&gt;
</code></pre></div><p>Java based configuration lets you configure splits through the provided builders. As the
following example shows, the 'split' element contains one or more 'flow' elements, where
entire separate flows can be defined. A 'split' element may also contain any of the
previously discussed transition elements, such as the 'next' attribute or the 'next',
'end' or 'fail' elements.</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Flow flow1() {
	return new FlowBuilder&lt;SimpleFlow&gt;(&quot;flow1&quot;)
			.start(step1())
			.next(step2())
			.build();
}

@Bean
public Flow flow2() {
	return new FlowBuilder&lt;SimpleFlow&gt;(&quot;flow2&quot;)
			.start(step3())
			.build();
}

@Bean
public Job job(Flow flow1, Flow flow2) {
	return this.jobBuilderFactory.get(&quot;job&quot;)
				.start(flow1)
				.split(new SimpleAsyncTaskExecutor())
				.add(flow2)
				.next(step4())
				.end()
				.build();
}
</code></pre></div><h4 id="externalizing-flow-definitions-and-dependencies-between-jobs"><a href="#externalizing-flow-definitions-and-dependencies-between-jobs" class="header-anchor">#</a> Externalizing Flow Definitions and Dependencies Between Jobs</h4> <p>Part of the flow in a job can be externalized as a separate bean definition and then
re-used. There are two ways to do so. The first is to simply declare the flow as a
reference to one defined elsewhere.</p> <p>The following example shows how to declare a flow as a reference to a flow defined
elsewhere in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;job id=&quot;job&quot;&gt;
    &lt;flow id=&quot;job1.flow1&quot; parent=&quot;flow1&quot; next=&quot;step3&quot;/&gt;
    &lt;step id=&quot;step3&quot; parent=&quot;s3&quot;/&gt;
&lt;/job&gt;

&lt;flow id=&quot;flow1&quot;&gt;
    &lt;step id=&quot;step1&quot; parent=&quot;s1&quot; next=&quot;step2&quot;/&gt;
    &lt;step id=&quot;step2&quot; parent=&quot;s2&quot;/&gt;
&lt;/flow&gt;
</code></pre></div><p>The following example shows how to declare a flow as a reference to a flow defined
elsewhere in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job job() {
	return this.jobBuilderFactory.get(&quot;job&quot;)
				.start(flow1())
				.next(step3())
				.end()
				.build();
}

@Bean
public Flow flow1() {
	return new FlowBuilder&lt;SimpleFlow&gt;(&quot;flow1&quot;)
			.start(step1())
			.next(step2())
			.build();
}
</code></pre></div><p>The effect of defining an external flow as shown in the preceding example is to insert
the steps from the external flow into the job as if they had been declared inline. In
this way, many jobs can refer to the same template flow and compose such templates into
different logical flows. This is also a good way to separate the integration testing of
the individual flows.</p> <p>The other form of an externalized flow is to use a <code>JobStep</code>. A <code>JobStep</code> is similar to a<code>FlowStep</code> but actually creates and launches a separate job execution for the steps in
the flow specified.</p> <p>The following example hows an example of a <code>JobStep</code> in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;job id=&quot;jobStepJob&quot; restartable=&quot;true&quot;&gt;
   &lt;step id=&quot;jobStepJob.step1&quot;&gt;
      &lt;job ref=&quot;job&quot; job-launcher=&quot;jobLauncher&quot;
          job-parameters-extractor=&quot;jobParametersExtractor&quot;/&gt;
   &lt;/step&gt;
&lt;/job&gt;

&lt;job id=&quot;job&quot; restartable=&quot;true&quot;&gt;...&lt;/job&gt;

&lt;bean id=&quot;jobParametersExtractor&quot; class=&quot;org.spr...DefaultJobParametersExtractor&quot;&gt;
   &lt;property name=&quot;keys&quot; value=&quot;input.file&quot;/&gt;
&lt;/bean&gt;
</code></pre></div><p>The following example shows an example of a <code>JobStep</code> in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public Job jobStepJob() {
	return this.jobBuilderFactory.get(&quot;jobStepJob&quot;)
				.start(jobStepJobStep1(null))
				.build();
}

@Bean
public Step jobStepJobStep1(JobLauncher jobLauncher) {
	return this.stepBuilderFactory.get(&quot;jobStepJobStep1&quot;)
				.job(job())
				.launcher(jobLauncher)
				.parametersExtractor(jobParametersExtractor())
				.build();
}

@Bean
public Job job() {
	return this.jobBuilderFactory.get(&quot;job&quot;)
				.start(step1())
				.build();
}

@Bean
public DefaultJobParametersExtractor jobParametersExtractor() {
	DefaultJobParametersExtractor extractor = new DefaultJobParametersExtractor();

	extractor.setKeys(new String[]{&quot;input.file&quot;});

	return extractor;
}
</code></pre></div><p>The job parameters extractor is a strategy that determines how the <code>ExecutionContext</code> for
the <code>Step</code> is converted into <code>JobParameters</code> for the <code>Job</code> that is run. The <code>JobStep</code> is
useful when you want to have some more granular options for monitoring and reporting on
jobs and steps. Using <code>JobStep</code> is also often a good answer to the question: &quot;How do I
create dependencies between jobs?&quot; It is a good way to break up a large system into
smaller modules and control the flow of jobs.</p> <h3 id="late-binding-of-job-and-step-attributes"><a href="#late-binding-of-job-and-step-attributes" class="header-anchor">#</a> Late Binding of <code>Job</code> and <code>Step</code> Attributes</h3> <p>Both the XML and flat file examples shown earlier use the Spring <code>Resource</code> abstraction
to obtain a file. This works because <code>Resource</code> has a <code>getFile</code> method, which returns a<code>java.io.File</code>. Both XML and flat file resources can be configured using standard Spring
constructs:</p> <p>The following example shows late binding in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;bean id=&quot;flatFileItemReader&quot;
      class=&quot;org.springframework.batch.item.file.FlatFileItemReader&quot;&gt;
    &lt;property name=&quot;resource&quot;
              value=&quot;file://outputs/file.txt&quot; /&gt;
&lt;/bean&gt;
</code></pre></div><p>The following example shows late binding in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public FlatFileItemReader flatFileItemReader() {
	FlatFileItemReader&lt;Foo&gt; reader = new FlatFileItemReaderBuilder&lt;Foo&gt;()
			.name(&quot;flatFileItemReader&quot;)
			.resource(new FileSystemResource(&quot;file://outputs/file.txt&quot;))
			...
}
</code></pre></div><p>The preceding <code>Resource</code> loads the file from the specified file system location. Note
that absolute locations have to start with a double slash (<code>//</code>). In most Spring
applications, this solution is good enough, because the names of these resources are
known at compile time. However, in batch scenarios, the file name may need to be
determined at runtime as a parameter to the job. This can be solved using '-D' parameters
to read a system property.</p> <p>The following example shows how to read a file name from a property in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;bean id=&quot;flatFileItemReader&quot;
      class=&quot;org.springframework.batch.item.file.FlatFileItemReader&quot;&gt;
    &lt;property name=&quot;resource&quot; value=&quot;${input.file.name}&quot; /&gt;
&lt;/bean&gt;
</code></pre></div><p>The following shows how to read a file name from a property in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@Bean
public FlatFileItemReader flatFileItemReader(@Value(&quot;${input.file.name}&quot;) String name) {
	return new FlatFileItemReaderBuilder&lt;Foo&gt;()
			.name(&quot;flatFileItemReader&quot;)
			.resource(new FileSystemResource(name))
			...
}
</code></pre></div><p>All that would be required for this solution to work would be a system argument (such as<code>-Dinput.file.name=&quot;file://outputs/file.txt&quot;</code>).</p> <table><thead><tr><th></th> <th>Although a <code>PropertyPlaceholderConfigurer</code> can be used here, it is not<br>necessary if the system property is always set because the <code>ResourceEditor</code> in Spring<br>already filters and does placeholder replacement on system properties.</th></tr></thead> <tbody></tbody></table> <p>Often, in a batch setting, it is preferable to parametrize the file name in the<code>JobParameters</code> of the job, instead of through system properties, and access them that
way. To accomplish this, Spring Batch allows for the late binding of various <code>Job</code> and<code>Step</code> attributes.</p> <p>The following example shows how to parameterize a file name in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;bean id=&quot;flatFileItemReader&quot; scope=&quot;step&quot;
      class=&quot;org.springframework.batch.item.file.FlatFileItemReader&quot;&gt;
    &lt;property name=&quot;resource&quot; value=&quot;#{jobParameters['input.file.name']}&quot; /&gt;
&lt;/bean&gt;
</code></pre></div><p>The following example shows how to parameterize a file name in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value(&quot;#{jobParameters['input.file.name']}&quot;) String name) {
	return new FlatFileItemReaderBuilder&lt;Foo&gt;()
			.name(&quot;flatFileItemReader&quot;)
			.resource(new FileSystemResource(name))
			...
}
</code></pre></div><p>Both the <code>JobExecution</code> and <code>StepExecution</code> level <code>ExecutionContext</code> can be accessed in
the same way.</p> <p>The following example shows how to access the <code>ExecutionContext</code> in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;bean id=&quot;flatFileItemReader&quot; scope=&quot;step&quot;
      class=&quot;org.springframework.batch.item.file.FlatFileItemReader&quot;&gt;
    &lt;property name=&quot;resource&quot; value=&quot;#{jobExecutionContext['input.file.name']}&quot; /&gt;
&lt;/bean&gt;
</code></pre></div><p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;bean id=&quot;flatFileItemReader&quot; scope=&quot;step&quot;
      class=&quot;org.springframework.batch.item.file.FlatFileItemReader&quot;&gt;
    &lt;property name=&quot;resource&quot; value=&quot;#{stepExecutionContext['input.file.name']}&quot; /&gt;
&lt;/bean&gt;
</code></pre></div><p>The following example shows how to access the <code>ExecutionContext</code> in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value(&quot;#{jobExecutionContext['input.file.name']}&quot;) String name) {
	return new FlatFileItemReaderBuilder&lt;Foo&gt;()
			.name(&quot;flatFileItemReader&quot;)
			.resource(new FileSystemResource(name))
			...
}
</code></pre></div><p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value(&quot;#{stepExecutionContext['input.file.name']}&quot;) String name) {
	return new FlatFileItemReaderBuilder&lt;Foo&gt;()
			.name(&quot;flatFileItemReader&quot;)
			.resource(new FileSystemResource(name))
			...
}
</code></pre></div><table><thead><tr><th></th> <th>Any bean that uses late-binding must be declared with scope=&quot;step&quot;. See<a href="#step-scope">Step Scope</a> for more information. It should be noted<br>that a <code>Step</code> bean should not be step-scoped. If late-binding is needed in a step<br>definition, the components of that step (ie tasklet, item reader/writer, etc)<br>are the ones that should be scoped instead.</th></tr></thead> <tbody></tbody></table> <table><thead><tr><th></th> <th>If you are using Spring 3.0 (or above), the expressions in step-scoped beans are in the<br>Spring Expression Language, a powerful general purpose language with many interesting<br>features. To provide backward compatibility, if Spring Batch detects the presence of<br>older versions of Spring, it uses a native expression language that is less powerful and<br>that has slightly different parsing rules. The main difference is that the map keys in<br>the example above do not need to be quoted with Spring 2.5, but the quotes are mandatory<br>in Spring 3.0.</th></tr></thead> <tbody></tbody></table> <h4 id="step-scope"><a href="#step-scope" class="header-anchor">#</a> Step Scope</h4> <p>All of the late binding examples shown earlier have a scope of “step” declared on the
bean definition.</p> <p>The following example shows an example of binding to step scope in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;bean id=&quot;flatFileItemReader&quot; scope=&quot;step&quot;
      class=&quot;org.springframework.batch.item.file.FlatFileItemReader&quot;&gt;
    &lt;property name=&quot;resource&quot; value=&quot;#{jobParameters[input.file.name]}&quot; /&gt;
&lt;/bean&gt;
</code></pre></div><p>The following example shows an example of binding to step scope in Java:</p> <p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value(&quot;#{jobParameters[input.file.name]}&quot;) String name) {
	return new FlatFileItemReaderBuilder&lt;Foo&gt;()
			.name(&quot;flatFileItemReader&quot;)
			.resource(new FileSystemResource(name))
			...
}
</code></pre></div><p>Using a scope of <code>Step</code> is required in order to use late binding, because the bean cannot
actually be instantiated until the <code>Step</code> starts, to allow the attributes to be found.
Because it is not part of the Spring container by default, the scope must be added
explicitly, by using the <code>batch</code> namespace or by including a bean definition explicitly
for the <code>StepScope</code>, or by using the <code>@EnableBatchProcessing</code> annotation. Use only one of
those methods. The following example uses the <code>batch</code> namespace:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:batch=&quot;http://www.springframework.org/schema/batch&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xsi:schemaLocation=&quot;...&quot;&gt;
&lt;batch:job .../&gt;
...
&lt;/beans&gt;
</code></pre></div><p>The following example includes the bean definition explicitly:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;bean class=&quot;org.springframework.batch.core.scope.StepScope&quot; /&gt;
</code></pre></div><h4 id="job-scope"><a href="#job-scope" class="header-anchor">#</a> Job Scope</h4> <p><code>Job</code> scope, introduced in Spring Batch 3.0, is similar to <code>Step</code> scope in configuration
but is a Scope for the <code>Job</code> context, so that there is only one instance of such a bean
per running job. Additionally, support is provided for late binding of references
accessible from the <code>JobContext</code> using <code>#{..}</code> placeholders. Using this feature, bean
properties can be pulled from the job or job execution context and the job parameters.</p> <p>The following example shows an example of binding to job scope in XML:</p> <p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;job&quot;&gt;
    &lt;property name=&quot;name&quot; value=&quot;#{jobParameters[input]}&quot; /&gt;
&lt;/bean&gt;
</code></pre></div><p>XML Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;job&quot;&gt;
    &lt;property name=&quot;name&quot; value=&quot;#{jobExecutionContext['input.name']}.txt&quot; /&gt;
&lt;/bean&gt;
</code></pre></div><p>The following example shows an example of binding to job scope in Java:</p> <p>Java Configurtation</p> <div class="language- extra-class"><pre class="language-text"><code>@JobScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value(&quot;#{jobParameters[input]}&quot;) String name) {
	return new FlatFileItemReaderBuilder&lt;Foo&gt;()
			.name(&quot;flatFileItemReader&quot;)
			.resource(new FileSystemResource(name))
			...
}
</code></pre></div><p>Java Configuration</p> <div class="language- extra-class"><pre class="language-text"><code>@JobScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value(&quot;#{jobExecutionContext['input.name']}&quot;) String name) {
	return new FlatFileItemReaderBuilder&lt;Foo&gt;()
			.name(&quot;flatFileItemReader&quot;)
			.resource(new FileSystemResource(name))
			...
}
</code></pre></div><p>Because it is not part of the Spring container by default, the scope must be added
explicitly, by using the <code>batch</code> namespace, by including a bean definition explicitly for
the JobScope, or using the <code>@EnableBatchProcessing</code> annotation (but not all of them).
The following example uses the <code>batch</code> namespace:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
		  xmlns:batch=&quot;http://www.springframework.org/schema/batch&quot;
		  xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
		  xsi:schemaLocation=&quot;...&quot;&gt;

&lt;batch:job .../&gt;
...
&lt;/beans&gt;
</code></pre></div><p>The following example includes a bean that explicitly defines the <code>JobScope</code>:</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;bean class=&quot;org.springframework.batch.core.scope.JobScope&quot; /&gt;
</code></pre></div><table><thead><tr><th></th> <th>There are some practical limitations of using job-scoped beans in multi-threaded<br>or partitioned steps. Spring Batch does not control the threads spawned in these<br>use cases, so it is not possible to set them up correctly to use such beans. Hence,<br>it is not recommended to use job-scoped beans in multi-threaded or partitioned steps.</th></tr></thead> <tbody></tbody></table></div> <footer class="page-edit"><div class="edit-link"><a href="https://gitcode.net/dev-cloud/spring-docs/-/blob/master/docs/en/spring-batch/step.md" target="_blank" rel="noopener noreferrer">Edit this page on GitCode</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <div class="last-updated"><span class="prefix">Last Updated:</span> <span class="time">Thu Mar 17 2022 18:19:53 GMT+0800</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">

      <a href="/en/spring-batch/job.html" class="prev">
        Configuring and Running a Job
      </a></span> <span class="next"><a href="/en/spring-batch/readersAndWriters.html">
        ItemReaders and ItemWriters
      </a>

    </span></p></div> </main></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.cf11b18e.js" defer></script><script src="/assets/js/3.50918073.js" defer></script><script src="/assets/js/4.cd4c3ff4.js" defer></script><script src="/assets/js/38.23e83578.js" defer></script>
  </body>
</html>