Açıklaması şöyle
We use this to manage user sessions and prevent session hijacking.
AsyncConfigurer is an Interface provided by Spring, It provides two methods. One is if you want to override the TaskExecutor(Threadpool), another is an Exception handler where you can inject your exception handler so it can catch the uncaught exceptions.getAsyncExecutor metodu
@Configuration
@EnableAsync
public class ServiceExecutorConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(30);
taskExecutor.setMaxPoolSize(40);
taskExecutor.setQueueCapacity(10);
taskExecutor.initialize();
return taskExecutor;
}
}@Slf4j
@Configuration
public class BaseAsyncConfigurer implements AsyncConfigurer {
//replace default Async Executor with Customize One.
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors()*5);
executor.setQueueCapacity(Runtime.getRuntime().availableProcessors()*10);
executor.setThreadNamePrefix("replacedAsync-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
...
}@Slf4j @Configuration public class BaseAsyncConfigurer implements AsyncConfigurer { ... //override the getAsyncUncaughtExceptionHandler() method to return our // custom asynchronous exception handler: //!!! All the exception happened in @async will been handler here. @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (Throwable ex, Method method, Object... params)-> { try { log.error("\n\n[Exception-Async-Handler] Class-Name: {}-{}\n Type: {}\nException: {}\n\n", method.getDeclaringClass().getName(),method.getName(), ex.getClass().getName(), ex.getMessage()); } catch (Throwable e) { log.error("catch Async Exception: {}", e); } }; } }
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;import java.lang.reflect.Method; public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler { @Override public void handleUncaughtException(Throwable throwable, Method method, Object... obj) { System.out.println("Message from exception - " + throwable.getMessage()); System.out.println("Method name " + method.getName()); } }
@Configuration public class AsyncConfig implements AsyncConfigurer { @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new AsyncExceptionHandler(); } }
By default, if you do not explicitly set the concurrency value using setConcurrency on the ConcurrentKafkaListenerContainerFactory, the default value is 1. This means that by default, only a single thread will be used to process messages from a particular Kafka topic.
@KafkaListener(
topics = "word-processor",
concurrency = "3",
groupId = "parallel-consumer")
public void consume(ConsumerRecord<String, String> consumerRecord) {
log.info("Partition : {}, Msg: {}",
consumerRecord.partition(), consumerRecord.value());
}
@KafkaListener(
topics = {"word-processor", "word-processor-two"},
concurrency = "2",
groupId = "multi-topic-parallel-consumer")
public void consume(ConsumerRecord<String, String> consumerRecord) {
log.info("Partition : {}, Msg: {}",
consumerRecord.partition(), consumerRecord.value());
}
@Bean
public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<Long, LogDay>>
onlineKafkaListenerContainerFactory() {
Map<String, Object> propMap = ...;
ConcurrentKafkaListenerContainerFactory<Long, LogDay> factory =
new ConcurrentKafkaListenerContainerFactory<>();
factory.setConcurrency(5);
factory.getContainerProperties().setPollTimeout(1_000l);
factory.setConsumerFactory(new DefaultKafkaConsumerFactory<>(propMap));
return factory;
}
@Configuration
@EnableKafka
public class KafkaConsumerConfig {
// Configure Kafka consumer properties
@Bean
public ConsumerFactory<String, String> consumerFactory() {
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "your-kafka-bootstrap-servers");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "your-consumer-group-id");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
"org.apache.kafka.common.serialization.StringDeserializer");
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
"org.apache.kafka.common.serialization.StringDeserializer");
// Additional consumer properties
return new DefaultKafkaConsumerFactory<>(props);
}
// Configure the listener container factory for parallel consumption
@Bean
public ConcurrentKafkaListenerContainerFactory<String, String>
kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, String> factory =
new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
factory.setConcurrency(3); // Set the number of consumer threads
return factory;
}
}import org.springframework.batch.test.JobLauncherTestUtils;
Spring Batch provides a test framework that enables developers to write unit tests for batch jobs. The framework includes test helpers that simulate the behavior of the batch job and validate the output of the job.
@RunWith(SpringJUnit4ClassRunner.class) @SpringBatchTest @ContextConfiguration(classes = { BatchTestConfig.class, SimpleJobConfig.class }) public class SimpleJobTest { @Autowired private JobLauncherTestUtils jobLauncherTestUtils; @Autowired private DataSource dataSource; @Test public void testSimpleJob() throws Exception { JobExecution jobExecution = jobLauncherTestUtils.launchJob(); // Assert the job execution status assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus()); // Assert the number of records processed JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); assertEquals(3, jdbcTemplate .queryForObject("SELECT COUNT(*) FROM people", Integer.class) .intValue()); } }
In this example, we are using the `JobLauncherTestUtils` helper class to launch the job and verify its execution status. We are also using the JdbcTemplate to query the database and verify the number of records processed.Note that we are using the `@SpringBatchTest` annotation to enable Spring Batch test support, and we are also providing the configuration classes for the batch job and the test environment using the `@ContextConfiguration` annotation.
@Bean
public JdbcBatchItemWriter<Customer> customerItemWriter(DataSource dataSource) {
JdbcBatchItemWriter<Customer> writer = new JdbcBatchItemWriter<>();
writer.setItemSqlParameterSourceProvider(
new BeanPropertyItemSqlParameterSourceProvider<>());
writer.setSql("INSERT INTO customers (id, name, email) VALUES (:id, :name, :email)");
writer.setDataSource(dataSource);
return writer;
}The `JdbcBatchItemWriter` is configured to insert data into a database table called “customers”. It uses a `BeanPropertyItemSqlParameterSourceProvider` to map the `Customer` object to SQL parameters, and the SQL statement is defined as a string.
@Bean
public FlatFileItemReader<Customer> customerItemReader() {
FlatFileItemReader<Customer> reader = new FlatFileItemReader<>();
reader.setResource(new ClassPathResource("customer-data.csv"));
reader.setLineMapper(new DefaultLineMapper<Customer>() {{
setLineTokenizer(new DelimitedLineTokenizer() {{
setNames(new String[] {"id", "name", "email"});
}});
setFieldSetMapper(new BeanWrapperFieldSetMapper<Customer>() {{
setTargetType(Customer.class);
}});
}});
return reader;
}