๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring/Spring Batch

Spring Batch (9) JobParametersValidator

by ์ฃผ๋ฐœ2 2022. 11. 13.
๋ฐ˜์‘ํ˜•

์ง€๋‚œ ์‹œ๊ฐ„์—๋Š” JobLauncher์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

JobLauncher๋Š” ์‹ค์ œ Spring Batch Job์„ ์‹คํ–‰ํ•˜๋Š” ์—ญํ• ์„ ํ•˜๋ฉฐ, Job & JobParameters๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ ๋ฐฐ์น˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ ํ›„ JobExecution์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. 

 

Spring Batch์—์„œ๋Š” BatchAutoConfiguration ํด๋ž˜์Šค ๋‚ด์˜ JobLauncherApplicationRunner ํด๋ž˜์Šค๊ฐ€ Job์„ ์‹คํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

 

 

๐Ÿ“Œ JobParametersValidator

๊ธฐ๋ณธ ๊ฐœ๋…

  • Job ์‹คํ–‰ ์‹œ ํ•„์ˆ˜์ ์ธ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ์—ญํ• ์ž…๋‹ˆ๋‹ค.
  • ๊ธฐ๋ณธ์ ์œผ๋กœ DefaultJobParametersValidator ๊ตฌํ˜„์ฒด๋ฅผ ์ง€์›ํ•˜๋ฉฐ, JobParametersValidator ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์—ฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฒ€์ฆํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

 

๐Ÿ“Œ ์˜ˆ์ œ ์ฝ”๋“œ 1. JobParametersValidator ์ธํ„ฐํŽ˜์ด์Šค ์ง์ ‘ ๊ตฌํ˜„

์ฒซ ๋ฒˆ์งธ๋กœ JobParametersValidator ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์—ฌ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.JobParametersValidator;

public class CustomJobParametersValidator implements JobParametersValidator {

    @Override
    public void validate(JobParameters jobParameters) throws JobParametersInvalidException {

        if (jobParameters.getString("name") == null) {
            throw new JobParametersInvalidException("name parameter is not found.");
        }
    }
}

์œ„ ์˜ˆ์ œ๋Š” JobParameters์— key๊ฐ€ name์ธ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

 

 

์‹ค์ œ ์ ์šฉ์€ ์•„๋ž˜์™€ ๊ฐ™์ด Job์—์„œ validator() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์œ„์—์„œ ์ƒ์„ฑํ•œ CustomJobParametersValidator ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

JobBuilderHelper

@RequiredArgsConstructor
@Configuration
public class ValidatorConfiguration {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job parametersValidatorJob() {
        return this.jobBuilderFactory.get("parametersValidatorJob")
                .validator(new CustomJobParametersValidator()) // Validator ์„ค์ •
                .start(parametersValidatorStep1())
                .next(parametersValidatorStep2())
                .next(parametersValidatorStep3())
                .build();
    }
    
    ... 
}

 

 

Spring Batch์—์„œ JobParameters์— ๋Œ€ํ•œ ๊ฒ€์ฆ์€ ์ด 2๋ฒˆ์ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

  1. JobLauncher ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด์ธ SimpleJobLauncher์—์„œ JobParameters ๊ฒ€์ฆ
  2. Job ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด์ธ AbstractJob ์ถ”์ƒ ํด๋ž˜์Šค์—์„œ JobParameters ๊ฒ€์ฆ

1. SimpleJobLauncher.run()

 

2. AbstractJob.execute()

 

 

 

AbstractJob

์ปค์Šคํ…€ Validator๋ฅผ ์„ค์ •ํ•˜๊ณ  ์‹คํ–‰ํ•ด๋ณด๋ฉด ์œ„์™€ ๊ฐ™์ด AbstractJob ์ถ”์ƒ ํด๋ž˜์Šค์—์„œ setter๋ฅผ ํ†ตํ•ด validator๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

 

SimpleJobLauncher

๊ทธ ํ›„ ์ฒซ ๋ฒˆ์งธ ๊ฒ€์ฆ์ธ SimpleJobLauncher ํด๋ž˜์Šค์—์„œ validate() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ AbstractJob ์ถ”์ƒ ํด๋ž˜์Šค์˜ validate() ๋ฉ”์„œ๋“œ์—์„œ๋„ ๊ฒ€์ฆ์ด ๋˜์–ด์•ผํ•˜๋‚˜, ์œ„ ์˜ˆ์‹œ๋Š” ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒํ•˜์—ฌ ์ดํ›„ ๋กœ์ง์€ ์ง„ํ–‰์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

 

์˜ˆ์ œ ์ฝ”๋“œ์—์„œ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์— requestDate๋ผ๋Š” key๋ฅผ ์„ค์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— name์— ํ•ด๋‹นํ•˜๋Š” key๋Š” ์กด์žฌํ•˜์ง€ ์•Š์•„ null๋กœ ๋‚˜์˜ค๊ณ , ์ปค์Šคํ…€ Validator ํด๋ž˜์Šค์—์„œ ์„ค์ •ํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๋ฉฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

 

 

 

๋งŒ์•ฝ ์œ„์ฒ˜๋Ÿผ JobParameters์— key๋ฅผ name์œผ๋กœ ์„ค์ •ํ•˜์—ฌ ๋‹ค์‹œ ์‹คํ–‰ํ•ด๋ณด๋ฉด ๊ฒ€์ฆ์— ํ†ต๊ณผํ•˜์—ฌ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰์ด ๋ฉ๋‹ˆ๋‹ค.

 

 

๋‘ ๋ฒˆ์งธ ๊ฒ€์ฆ์ธ AbstractJob ์ถ”์ƒ ํด๋ž˜์Šค์—์„œ๋„ ์ •์ƒ์ ์œผ๋กœ validate() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ต๊ณผํ•˜์—ฌ Batch Job์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

 

 

 

๐Ÿ“Œ ์˜ˆ์ œ ์ฝ”๋“œ 2. DefaultJobParametersValidator ๊ตฌํ˜„์ฒด ์‚ฌ์šฉ

๋‹ค์Œ์œผ๋กœ Spring Batch์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” JobParametersValidator ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ธฐ๋ณธ ๊ตฌํ˜„์ฒด์ธ DefaultJobParametersValidator ํด๋ž˜์Šค์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

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
/*
 * Copyright 2012-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.batch.core.job;
 
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
 
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.JobParametersValidator;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
 
/**
 * Default implementation of {@link JobParametersValidator}.
 *
 * @author Dave Syer
 * @author Mahmoud Ben Hassine
 *
 */
public class DefaultJobParametersValidator implements JobParametersValidator, InitializingBean {
 
    private Collection<String> requiredKeys;
 
    private Collection<String> optionalKeys;
 
    /**
     * Convenient default constructor for unconstrained validation.
     */
    public DefaultJobParametersValidator() {
        this(new String[0], new String[0]);
    }
 
    /**
     * Create a new validator with the required and optional job parameter keys
     * provided.
     *
     * @see DefaultJobParametersValidator#setOptionalKeys(String[])
     * @see DefaultJobParametersValidator#setRequiredKeys(String[])
     *
     * @param requiredKeys the required keys
     * @param optionalKeys the optional keys
     */
    public DefaultJobParametersValidator(String[] requiredKeys, String[] optionalKeys) {
        super();
        setRequiredKeys(requiredKeys);
        setOptionalKeys(optionalKeys);
    }
 
    /**
     * Check that there are no overlaps between required and optional keys.
     * @throws IllegalStateException if there is an overlap
     */
    @Override
    public void afterPropertiesSet() throws IllegalStateException {
        for (String key : requiredKeys) {
            Assert.state(!optionalKeys.contains(key), "Optional keys cannot be required: " + key);
        }
    }
 
    /**
     * Check the parameters meet the specification provided. If optional keys
     * are explicitly specified then all keys must be in that list, or in the
     * required list. Otherwise all keys that are specified as required must be
     * present.
     *
     * @see JobParametersValidator#validate(JobParameters)
     *
     * @throws JobParametersInvalidException if the parameters are not valid
     */
    @Override
    public void validate(@Nullable JobParameters parameters) throws JobParametersInvalidException {
 
        if (parameters == null) {
            throw new JobParametersInvalidException("The JobParameters can not be null");
        }
 
        Set<String> keys = parameters.getParameters().keySet();
 
        // If there are explicit optional keys then all keys must be in that
        // group, or in the required group.
        if (!optionalKeys.isEmpty()) {
 
            Collection<String> missingKeys = new HashSet<>();
            for (String key : keys) {
                if (!optionalKeys.contains(key) && !requiredKeys.contains(key)) {
                    missingKeys.add(key);
                }
            }
            if (!missingKeys.isEmpty()) {
                throw new JobParametersInvalidException(
                        "The JobParameters contains keys that are not explicitly optional or required: " + missingKeys);
            }
 
        }
 
        Collection<String> missingKeys = new HashSet<>();
        for (String key : requiredKeys) {
            if (!keys.contains(key)) {
                missingKeys.add(key);
            }
        }
        if (!missingKeys.isEmpty()) {
            throw new JobParametersInvalidException("The JobParameters do not contain required keys: " + missingKeys);
        }
 
    }
 
    /**
     * The keys that are required in the parameters. The default is empty,
     * meaning that all parameters are optional, unless optional keys are
     * explicitly specified.
     *
     * @param requiredKeys the required key values
     *
     * @see #setOptionalKeys(String[])
     */
    public final void setRequiredKeys(String[] requiredKeys) {
        this.requiredKeys = new HashSet<>(Arrays.asList(requiredKeys));
    }
 
    /**
     * The keys that are optional in the parameters. If any keys are explicitly
     * optional, then to be valid all other keys must be explicitly required.
     * The default is empty, meaning that all parameters that are not required
     * are optional.
     *
     * @param optionalKeys the optional key values
     *
     * @see #setRequiredKeys(String[])
     */
    public final void setOptionalKeys(String[] optionalKeys) {
        this.optionalKeys = new HashSet<>(Arrays.asList(optionalKeys));
    }
 
}
 
cs

 

DefaultJobParametersValidator ํด๋ž˜์Šค์—๋Š” requiredKeys, optionalKeys ๋‘ ๊ฐœ์˜ ์ปฌ๋ ‰์…˜ ํ•„๋“œ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

 

๋ณ€์ˆ˜๋ช…์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ๊ฐ๊ฐ ํ•„์ˆ˜ key, ์˜ต์…”๋„ key๋ฅผ ์˜๋ฏธํ•˜๋Š”๋ฐ์š” requiredKeys๋Š” ๋‹จ์–ด ๊ทธ๋Œ€๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋ฐ˜๋“œ์‹œ ์กด์žฌํ•ด์•ผ ํ•˜๋Š” key๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ optionalKeys๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์— ์กด์žฌํ•˜์ง€ ์•Š์•„๋„ ์ƒ๊ด€์ด ์—†์Šต๋‹ˆ๋‹ค.

 

@RequiredArgsConstructor
@Configuration
public class ValidatorConfiguration {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job parametersValidatorJob() {
        String[] requiredKeys = {"name", "date"};
        String[] optionalKeys = {"year"};

        return this.jobBuilderFactory.get("parametersValidatorJob")
                .validator(new DefaultJobParametersValidator(requiredKeys, optionalKeys))
                .start(parametersValidatorStep1())
                .next(parametersValidatorStep2())
                .next(parametersValidatorStep3())
                .build();
    }

์œ„ ์ฝ”๋“œ์—์„œ ํ•„์ˆ˜ ํ‚ค๋Š” name, date ์ด๋ฏ€๋กœ ๋‘ key๊ฐ€ JobParameters์— ๋ฐ˜๋“œ์‹œ ํฌํ•จ์ด ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • name, date = ํ•„์ˆ˜
  • year = ์„ ํƒ

 

๋งŒ์•ฝ ์œ„์ฒ˜๋Ÿผ ํŒŒ๋ผ๋ฏธํ„ฐ์— ํ•„์ˆ˜ ํ‚ค์ธ date๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, Job์ด ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜์ง€ ์•Š๊ณ  ์‹คํŒจํ•  ๊ฒƒ์ด๋ผ๊ณ  ์˜ˆ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

DefaultJobParametersValidator ํด๋ž˜์Šค์˜ validate() ๋ฉ”์„œ๋“œ์—์„œ ์ฒซ for๋ฌธ ๋‚ด์—์„œ์˜ ๊ฒ€์ฆ์€ ์ž…๋ ฅ๋ฐ›์€ JobParameters์— ๋Œ€ํ•ด ๊ฒ€์ฆํ•˜์—ฌ optionalKeys, requiredKeys ๋‘ ์ปฌ๋ ‰์…˜์— ๋ชจ๋‘ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

 

 

๊ทธ ํ›„ ๋‘ ๋ฒˆ์งธ for๋ฌธ์—์„œ requiredKeys์— ํ•ด๋‹นํ•˜๋Š” date ํ‚ค๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— misskingKeys์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” key๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ์ดํ›„ if๋ฌธ์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

required Keys์—์„œ date ํ‚ค๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

 

 

๋งŒ์•ฝ requiredKeys์— ํ•ด๋‹นํ•˜๋Š” name, date๋ฅผ ๋ชจ๋‘ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์„ค์ •ํ•œ๋‹ค๋ฉด ์ •์ƒ์ ์œผ๋กœ ๊ฒ€์ฆ์— ์„ฑ๊ณตํ•˜์—ฌ Job์ด ์‹คํ–‰์ด ๋ฉ๋‹ˆ๋‹ค.

 

 

 

 

์ฐธ๊ณ  ๋ฌธ์„œ

๋ฐ˜์‘ํ˜•

'Spring > Spring Batch' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Spring Batch (11) Repeat  (0) 2023.01.15
Spring Batch (10) @JobScope, @StepScope  (0) 2022.12.08
Spring Batch (8) JobLauncher  (0) 2022.11.11
Spring Batch (7) JobRepository  (0) 2022.11.08
Spring Batch (6) ExecutionContext  (0) 2022.11.05

๋Œ“๊ธ€