728x90

Historically, offline processing (such as batch jobs) has been launched from the command-line, as described earlier. However, there are many cases where launching from an HttpRequest is a better option. Many such use cases include reporting, ad-hoc job running, and web application support. Because a batch job (by definition) is long running, the most important concern is to launch the job asynchronously:

 

Figure 1. Asynchronous Job Launcher Sequence From Web Container

 

 

The controller in this case is a Spring MVC controller. See the Spring Framework Reference Guide for more about Spring MVC. The controller launches a Job by using a JobLauncher that has been configured to launch asynchronously, which immediately returns a JobExecution. The Job is likely still running. However, this nonblocking behavior lets the controller return immediately, which is required when handling an HttpRequest. The following listing shows an example:

@Controller
public class JobLauncherController {

    @Autowired
    JobLauncher jobLauncher;

    @Autowired
    Job job;

    @RequestMapping("/jobLauncher.html")
    public void handle() throws Exception{
        jobLauncher.run(job, new JobParameters());
    }
}
Copied!

 

'Java > Spring Boot JPA' 카테고리의 다른 글

not importing JSONException and JSONObject issue  (0) 2024.04.04
JobParametersIncrementer  (0) 2024.04.03
Builder and AllArgsConstructor Annotation  (0) 2024.04.02
Item Processing in Spring Batch  (0) 2024.04.01
ItemReaders and ItemWriters  (0) 2024.03.27
728x90

Although Source code used to take Builder annotation, two annotation between Builder and AllArgusConstructor was not chained in IntelliJ.

 

Let show e.g


@Builder(toBuilder = true)
public class BlahBlahEntity {


    no usages
    public BulkMailDetailEntity(Long id, ...) {
        this.id = id;

    }

}

 

Since AllArgsConstructor and NoArgsConstructor will obscure dependency relationship when you launch to compile your sourcue code, make constructor manually as possible. 

 

Though use Builder annotation, the same constructor as AllArgsConstructor, to be defined for goals was not chained.

Since, In fact, the constructor was not used to take part in.

 

 

728x90

The ItemReader and ItemWriter interfaces are both very useful for their specific tasks, but what if you want to insert business logic before writing? One option for both reading and writing is to use the composite pattern: Create an ItemWriter that contains another ItemWriter or an ItemReader that contains another ItemReader. The following code shows an example:

public class CompositeItemWriter<T> implements ItemWriter<T> {

    ItemWriter<T> itemWriter;

    public CompositeItemWriter(ItemWriter<T> itemWriter) {
        this.itemWriter = itemWriter;
    }

    public void write(Chunk<? extends T> items) throws Exception {
        //Add business logic here
       itemWriter.write(items);
    }

    public void setDelegate(ItemWriter<T> itemWriter){
        this.itemWriter = itemWriter;
    }
}
Copied!

The preceding class contains another ItemWriter to which it delegates after having provided some business logic. This pattern could easily be used for an ItemReader as well, perhaps to obtain more reference data based on the input that was provided by the main ItemReader. It is also useful if you need to control the call to write yourself. However, if you only want to “transform” the item passed in for writing before it is actually written, you need not write yourself. You can just modify the item. For this scenario, Spring Batch provides the ItemProcessor interface, as the following interface definition shows:

public interface ItemProcessor<I, O> {

    O process(I item) throws Exception;
}
Copied!

An ItemProcessor is simple. Given one object, transform it and return another. The provided object may or may not be of the same type. The point is that business logic may be applied within the process, and it is completely up to the developer to create that logic. An ItemProcessor can be wired directly into a step. For example, assume an ItemReader provides a class of type Foo and that it needs to be converted to type Bar before being written out. The following example shows an ItemProcessor that performs the conversion:

public class Foo {}

public class Bar {
    public Bar(Foo foo) {}
}

public class FooProcessor implements ItemProcessor<Foo, Bar> {
    public Bar process(Foo foo) throws Exception {
        //Perform simple transformation, convert a Foo to a Bar
        return new Bar(foo);
    }
}

public class BarWriter implements ItemWriter<Bar> {
    public void write(Chunk<? extends Bar> bars) throws Exception {
        //write bars
    }
}
Copied!

 

In the preceding example, there is a class named Foo, a class named Bar, and a class named FooProcessor that adheres to the ItemProcessor interface. The transformation is simple, but any type of transformation could be done here. The BarWriter writes Bar objects, throwing an exception if any other type is provided. Similarly, the FooProcessor throws an exception if anything but a Foo is provided. The FooProcessor can then be injected into a Step, as the following example shows:

Java Configuration
@Bean
public Job ioSampleJob(JobRepository jobRepository, Step step1) {
	return new JobBuilder("ioSampleJob", jobRepository)
				.start(step1)
				.build();
}

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
	return new StepBuilder("step1", jobRepository)
				.<Foo, Bar>chunk(2, transactionManager)
				.reader(fooReader())
				.processor(fooProcessor())
				.writer(barWriter())
				.build();
}
Copied!

A difference between ItemProcessor and ItemReader or ItemWriter is that an ItemProcessor is optional for a Step.

 

 

A difference between ItemProcessor and ItemReader or ItemWriter is that an ItemProcessor is optional for a Step.

Chaining ItemProcessors

Performing a single transformation is useful in many scenarios, but what if you want to “chain” together multiple ItemProcessor implementations? You can do so by using the composite pattern mentioned previously. To update the previous, single transformation, example, Foo is transformed to Bar, which is transformed to Foobar and written out, as the following example shows:

public class Foo {}

public class Bar {
    public Bar(Foo foo) {}
}

public class Foobar {
    public Foobar(Bar bar) {}
}

public class FooProcessor implements ItemProcessor<Foo, Bar> {
    public Bar process(Foo foo) throws Exception {
        //Perform simple transformation, convert a Foo to a Bar
        return new Bar(foo);
    }
}

public class BarProcessor implements ItemProcessor<Bar, Foobar> {
    public Foobar process(Bar bar) throws Exception {
        return new Foobar(bar);
    }
}

public class FoobarWriter implements ItemWriter<Foobar>{
    public void write(Chunk<? extends Foobar> items) throws Exception {
        //write items
    }
}
Copied!
 

 

A FooProcessor and a BarProcessor can be 'chained' together to give the resultant Foobar, as shown in the following example:

CompositeItemProcessor<Foo,Foobar> compositeProcessor =
                                       CompositeItemProcessor<Foo,Foobar>();
List itemProcessors =  ArrayList();
itemProcessors.add( FooProcessor());
itemProcessors.add( BarProcessor());
compositeProcessor.setDelegates(itemProcessors);

Just as with the previous example, you can configure the composite processor into the Step:

@Bean
public Job ioSampleJob(JobRepository jobRepository, Step step1) {
	return new JobBuilder("ioSampleJob", jobRepository)
				.start(step1)
				.build();
}

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
	return new StepBuilder("step1", jobRepository)
				.<Foo, Foobar>chunk(2, transactionManager)
				.reader(fooReader())
				.processor(compositeProcessor())
				.writer(foobarWriter())
				.build();
}

@Bean
public CompositeItemProcessor compositeProcessor() {
	List<ItemProcessor> delegates = new ArrayList<>(2);
	delegates.add(new FooProcessor());
	delegates.add(new BarProcessor());

	CompositeItemProcessor processor = new CompositeItemProcessor();

	processor.setDelegates(delegates);

	return processor;
}
Copied!

 

Filtering Records

One typical use for an item processor is to filter out records before they are passed to the ItemWriter. Filtering is an action distinct from skipping. Skipping indicates that a record is invalid, while filtering indicates that a record should not be written.

For example, consider a batch job that reads a file containing three different types of records: records to insert, records to update, and records to delete. If record deletion is not supported by the system, we would not want to send any deletable records to the ItemWriter. However, since these records are not actually bad records, we would want to filter them out rather than skip them. As a result, the ItemWriter would receive only insertable and updatable records.

To filter a record, you can return null from the ItemProcessor. The framework detects that the result is null and avoids adding that item to the list of records delivered to the ItemWriter. An exception thrown from the ItemProcessor results in a skip.

* Core Part

Validating Input

The ItemReaders and ItemWriters chapter discusses multiple approaches to parsing input. Each major implementation throws an exception if it is not “well formed.” The FixedLengthTokenizer throws an exception if a range of data is missing. Similarly, attempting to access an index in a RowMapper or FieldSetMapper that does not exist or is in a different format than the one expected causes an exception to be thrown. All of these types of exceptions are thrown before read returns. However, they do not address the issue of whether or not the returned item is valid. For example, if one of the fields is an age, it cannot be negative. It may parse correctly, because it exists and is a number, but it does not cause an exception. Since there are already a plethora of validation frameworks, Spring Batch does not attempt to provide yet another. Rather, it provides a simple interface, called Validator, that you can implement by any number of frameworks, as the following interface definition shows:

 {

    ;

}

The contract is that the validate method throws an exception if the object is invalid and returns normally if it is valid. Spring Batch provides an ValidatingItemProcessor, as the following bean definition shows:

Java
XML

Java Configuration

{
	ValidatingItemProcessor processor =  ValidatingItemProcessor();

	processor.setValidator(validator());

	 processor;
}

{
	SpringValidator validator =  SpringValidator();

	validator.setValidator( TradeValidator());

	 validator;
}

You can also use the BeanValidatingItemProcessor to validate items annotated with the Bean Validation API (JSR-303) annotations. For example, consider the following type Person:

{

     String name;

    {
     .name = name;
    }

    {
      name;
    }

    {
     .name = name;
    }

}

You can validate items by declaring a BeanValidatingItemProcessor bean in your application context and register it as a processor in your chunk-oriented step:

{
    BeanValidatingItemProcessor<Person> beanValidatingItemProcessor =  BeanValidatingItemProcessor<>();
    beanValidatingItemProcessor.setFilter();

     beanValidatingItemProcessor;
}

Fault Tolerance

When a chunk is rolled back, items that have been cached during reading may be reprocessed. If a step is configured to be fault-tolerant (typically by using skip or retry processing), any ItemProcessor used should be implemented in a way that is idempotent. Typically that would consist of performing no changes on the input item for the ItemProcessor and updating only the instance that is the result.

 

https://docs.spring.io/spring-batch/reference/processor.html

728x90

All batch processing can be described in its most simple form as reading in large amounts of data, performing some type of calculation or transformation, and writing the result out. Spring Batch provides three key interfaces to help perform bulk reading and writing: ItemReader, ItemProcessor, and ItemWriter.

Section Summary

+ Recent posts