Служба Spring Batch: UnsatisfiedDependencyException при расширении DefaultBatchConfiguration

Вопрос или проблема

Я оценю вашу помощь в поиске причины исключения, указанного ниже, которое возникает при попытке расширить DefaultBatchConfiguration. Сервис Spring Batch, показанный ниже, работает нормально, когда не расширяет «Default Batch Configuration». Я новичок в сервисе Spring Batch, я обучаюсь, следуя учебнику Spring по этой ссылке «https://spring.io/guides/gs/batch-processing#header» для создания Batch Service. Будет большой помощью, если кто-то из сообщества StakeOverflow объяснит, как настроить сервис Spring Batch, когда он расширяет DefaultBatchConfiguration, цель – устранить проблему и создать прочное понимание того, как расширить Default Batch Configuration.

Детали реализации:

  • Использует SpringBootApplication для запуска задания
  • Использует две базы данных
    • MySQL в качестве репозитория заданий
    • PostgreSQL в качестве данных
  • Проект Maven
  • IDE Eclipse

Используемые библиотеки и версии:

  • Java JDK версия 22
  • Spring Batch версия 5.1.2
  • Spring Boot версия 5.1.2
  • PostgreSQL версия 42.7.2
  • MySQL Connector версия 8.0.33
Лог отладки:
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::               (v3.2.10)

2024-11-05T14:30:17.788-05:00  INFO 2912 --- [           main] c.e.b.BatchProcessingApplication         : Запуск BatchProcessingApplication с использованием Java 22 с PID 2912 (D:\User\Gilmar\git-repo\spring-batch-mastery\spring-batch-initial\target\classes, запущенный Gilmar в D:\User\Gilmar\git-repo\spring-batch-mastery\spring-batch-initial)
2024-11-05T14:30:17.790-05:00  INFO 2912 --- [           main] c.e.b.BatchProcessingApplication         : Профиль не установлен, используется 1 профиль по умолчанию: "default"
2024-11-05T14:30:18.464-05:00  WARN 2912 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'batchConfiguration' типа [com.example.batchprocessing.BatchConfiguration$$SpringCGLIB$$0] не может быть обработан всеми BeanPostProcessors (например, не подходит для автоматического проксирования). В настоящее время созданный BeanPostProcessor [jobRegistryBeanPostProcessor] объявляется через нестатический фабричный метод в этом классе; рассмотрите возможность объявления его как статического.
2024-11-05T14:30:18.488-05:00  WARN 2912 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'jobRegistry' типа [org.springframework.batch.core.configuration.support.MapJobRegistry] не может быть обработан всеми BeanPostProcessors (например, не подходит для автоматического проксирования). Этот bean внедряется с ожиданием в текущий создаваемый BeanPostProcessor [jobRegistryBeanPostProcessor]? Проверьте соответствующее объявление BeanPostProcessor и его зависимости.
2024-11-05T14:30:18.562-05:00  INFO 2912 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Запуск...
2024-11-05T14:30:19.026-05:00  INFO 2912 --- [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Добавлено соединение com.mysql.cj.jdbc.ConnectionImpl@6778aea6
2024-11-05T14:30:19.028-05:00  INFO 2912 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Запуск завершен.
2024-11-05T14:30:19.061-05:00  INFO 2912 --- [           main] c.e.batchprocessing.BatchConfiguration   : ******jobTemplate запущен******
2024-11-05T14:30:19.078-05:00  INFO 2912 --- [           main] c.e.batchprocessing.BatchConfiguration   : ******FlatFileItemReader******
2024-11-05T14:30:19.095-05:00  INFO 2912 --- [           main] c.e.batchprocessing.BatchConfiguration   : ******PersonItemProcessor******
2024-11-05T14:30:19.096-05:00  INFO 2912 --- [           main] c.e.batchprocessing.BatchConfiguration   : ******JdbcBatchItemWriter******
2024-11-05T14:30:19.118-05:00  INFO 2912 --- [           main] o.s.b.c.r.s.JobRepositoryFactoryBean     : Тип базы данных не установлен, используются метаданные, указывающие: MYSQL
2024-11-05T14:30:19.145-05:00  WARN 2912 --- [           main] s.c.a.AnnotationConfigApplicationContext : Исключение, возникшее во время инициализации контекста - отмена попытки обновления: org.springframework.beans.factory.UnsatisfiedDependencyException: Ошибка при создании bean с именем 'importUserJob', определенной в классе по пути [com/example/batchprocessing/BatchConfiguration.class]: Неудовлетворенная зависимость, выраженная через метод 'importUserJob', параметр 1: Ошибка при создании bean с именем 'step1', определенной в классе по пути [com/example/batchprocessing/BatchConfiguration.class]: Неудовлетворенная зависимость, выраженная через метод 'step1', параметр 0: Ошибка при создании bean с именем 'jobRepository', определенной в классе по пути [com/example/batchprocessing/BatchConfiguration.class]: Не удалось создать экземпляр [org.springframework.batch.core.repository.JobRepository]: Фабричный метод 'jobRepository' выдал исключение с сообщением: Невозможно настроить репозиторий заданий по умолчанию
2024-11-05T14:30:19.147-05:00  INFO 2912 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Инициализирована остановка...
2024-11-05T14:30:19.196-05:00  INFO 2912 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Остановка завершена.
2024-11-05T14:30:19.220-05:00  INFO 2912 --- [           main] .s.b.a.l.ConditionEvaluationReportLogger : 

Ошибка при запуске ApplicationContext. Чтобы отобразить отчет об оценке условий, перезапустите приложение с включенной отладкой.
2024-11-05T14:30:19.249-05:00 ERROR 2912 --- [           main] o.s.boot.SpringApplication               : Не удалось запустить приложение

org.springframework.beans.factory.UnsatisfiedDependencyException: Ошибка при создании bean с именем 'importUserJob', определенной в классе по пути [com/example/batchprocessing/BatchConfiguration.class]: Неудовлетворенная зависимость, выраженная через метод 'importUserJob', параметр 1: Ошибка при создании bean с именем 'step1', определенной в классе по пути [com/example/batchprocessing/BatchConfiguration.class]: Неудовлетворенная зависимость, выраженная через метод 'step1', параметр 0: Ошибка при создании bean с именем 'jobRepository', определенной в классе по пути [com/example/batchprocessing/BatchConfiguration.class]: Не удалось создать экземпляр [org.springframework.batch.core.repository.JobRepository]: Фабричный метод 'jobRepository' выдал исключение с сообщением: Невозможно настроить репозиторий заданий по умолчанию
    по адресу org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:795) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:542) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1355) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1185) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.2.10.jar:3.2.10]
    по адресу org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.2.10.jar:3.2.10]
    по адресу org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.2.10.jar:3.2.10]
    по адресу org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.2.10.jar:3.2.10]
    по адресу org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.2.10.jar:3.2.10]
    по адресу com.example.batchprocessing.BatchProcessingApplication.main(BatchProcessingApplication.java:11) ~[classes/:na]
Причина: org.springframework.beans.factory.UnsatisfiedDependencyException: Ошибка при создании bean с именем 'step1', определенной в классе по пути [com/example/batchprocessing/BatchConfiguration.class]: Неудовлетворенная зависимость, выраженная через метод 'step1', параметр 0: Ошибка при создании bean с именем 'jobRepository', определенной в классе по пути [com/example/batchprocessing/BatchConfiguration.class]: Не удалось создать экземпляр [org.springframework.batch.core.repository.JobRepository]: Фабричный метод 'jobRepository' выдал исключение с сообщением: Невозможно настроить репозиторий заданий по умолчанию
    по адресу org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:795) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:542) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1355) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1185) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.2.10.jar:3.2.10]
    по адресу org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.2.10.jar:3.2.10]
    по адресу org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.2.10.jar:3.2.10]
    по адресу org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.2.10.jar:3.2.10]
    по адресу org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.2.10.jar:3.2.10]
    по адресу com.example.batchprocessing.BatchProcessingApplication.main(BatchProcessingApplication.java:11) ~[classes/:na]
Причина: org.springframework.beans.factory.BeanCreationException: Ошибка при создании bean с именем 'jobRepository', определенной в классе по пути [com/example/batchprocessing/BatchConfiguration.class]: Не удалось создать экземпляр [org.springframework.batch.core.repository.JobRepository]: Фабричный метод 'jobRepository' выдал исключение с сообщением: Невозможно настроить репозиторий заданий по умолчанию
    по адресу org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:648) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:485) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1355) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1185) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1443) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:904) ~[spring-beans-6.1.13.jar:6.1.13]
    по адресу org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:782) ~[spring-beans-6.1.13.jar:6.1.13]
    ... 18 общих фреймов
Причина: org.springframework.batch.core.configuration.BatchConfigurationException: Невозможно настроить репозиторий заданий по умолчанию
    по адресу org.springframework.batch.core.configuration.support.DefaultBatchConfiguration.jobRepository(DefaultBatchConfiguration.java:151) ~[spring-batch-core-5.1.2.jar:5.1.2]
    по адресу com.example.batchprocessing.BatchConfiguration$$SpringCGLIB$$0.CGLIB$jobRepository$29(<генерируется>) ~[classes/:na]
    по адресу com.example.batchprocessing.BatchConfiguration$$SpringCGLIB$$FastClass$$1.invoke(<генерируется>) ~[classes/:na]
    по адресу org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) ~[spring-core-6.1.13.jar:6.1.13]
    по адресу org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:348) ~[spring-context-6.1.13.jar:6.1.13]
    по адресу com.example.batchprocessing.BatchConfiguration$$SpringCGLIB$$0.jobRepository(<генерируется>) ~[classes/:na]
    по адресу java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
    по адресу java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
    по адресу org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:146) ~[spring-beans-6.1.13.jar:6.1.13]
    ... 47 общих фреймов
Причина: org.springframework.batch.core.configuration.BatchConfigurationException: Для использования конфигурации по умолчанию должен быть определен bean источника данных с именем 'dataSource' в контексте приложения, но он не был найден. Переопределите getDataSource(), чтобы предоставить источник данных, который нужно использовать для метаданных Batch.
    по адресу org.springframework.batch.core.configuration.support.DefaultBatchConfiguration.getDataSource(DefaultBatchConfiguration.java:250) ~[spring-batch-core-5.1.2.jar:5.1.2]
    по адресу org.springframework.batch.core.configuration.support.DefaultBatchConfiguration.jobRepository(DefaultBatchConfiguration.java:132) ~[spring-batch-core-5.1.2.jar:5.1.2]
    ... 55 общих фреймов

——Код——

@SpringBootApplication
public class BatchProcessingApplication {
    public static void main(String[] args) {
    System.exit(SpringApplication.exit(SpringApplication.run(BatchProcessingApplication.class, args)));
    }
}
@Configuration
public class BatchConfiguration extends DefaultBatchConfiguration {
//public class BatchConfiguration {

    private static final Logger log = LoggerFactory.getLogger(BatchConfiguration.class);

    @Bean("jdbcTemplate")
    public JdbcTemplate jdbcTemplate( @Qualifier("pgDataSource")DataSource dataSource) {
        log.info("******jobTemplate запущен******");
        return new JdbcTemplate(dataSource);
    }

    @Bean("reader")
    public FlatFileItemReader<Person> reader() {
        log.info("******FlatFileItemReader******");
      return new FlatFileItemReaderBuilder<Person>()
        .name("personItemReader")
        .resource(new ClassPathResource("sample-data.csv"))
        .delimited()
        .delimiter(",")
        .names("firstName", "lastName")
        .targetType(Person.class)
        .build();
    }
    @Bean("processor")
    public PersonItemProcessor processor() {
      log.info("******PersonItemProcessor******");
      return new PersonItemProcessor();
    }

    @Bean("writer")
    public JdbcBatchItemWriter<Person> writer( @Qualifier("pgDataSource") DataSource dataRepository) {
        log.info("******JdbcBatchItemWriter******");
      return new JdbcBatchItemWriterBuilder<Person>()
        .sql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)")
        .dataSource(dataRepository)
        .beanMapped()
        .build();
    }

    @Bean("importUserJob")
    public Job importUserJob(@Qualifier(
            "mySQLJobRepository")JobRepository jobRepository,
            Step step1,
            JobCompletionNotificationListener listener) {

        log.info("******importUserJob******");
        return new JobBuilder("importUserJob", jobRepository)
            .listener(listener)
            .start(step1)
            .build();
    }
    @Bean("step1")
    public Step step1(JobRepository jobRepository,  
            DataSourceTransactionManager transactionManager,
            @Qualifier("reader")FlatFileItemReader<Person> reader,
            @Qualifier("processor")PersonItemProcessor processor,
            @Qualifier("writer")JdbcBatchItemWriter<Person> writer) {

        log.info("******step1******");
        return new StepBuilder("step1", jobRepository)
        .<Person, Person> chunk(3, transactionManager)
        .reader(reader)
        .processor(processor)
        .writer(writer)
        .build();
    }

    /***** Источники данных Spring Batch и репозиторий заданий*****/
    /**
     * Этот метод создает репозиторий заданий 
     * @param mySQLDataSource содержит объект dataSource для создания репозитория заданий
     * @return
     * @throws Exception
     */
    @Bean("mySQLJobRepository")
    public JobRepository jobRepository(DataSource mySQLDataSource) throws Exception {

        JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
        factory.setDataSource(mySQLDataSource);
        factory.setTransactionManager(new DataSourceTransactionManager(mySQLDataSource));
        factory.setIsolationLevelForCreate("ISOLATION_SERIALIZABLE");
        factory.setMaxVarCharLength(255);
        factory.afterPropertiesSet();

        return factory.getObject();
    }
    /**
     * Этот метод создает источник данных на основе настроек свойств в "application.properties" для управления базой данных MySQL, используемой в качестве репозитория заданий.
     * 
     * @return объект источника данных
     * 
     * Примечание:
     *    Аннотации @ConfigurationProperty @Value избыточны для учебных целей, одной достаточно.
     */
    @Primary
    @Bean("mySQLDataSource")
    @ConfigurationProperties(prefix = "db.job.repo")
    public DataSource mySQLDataSource(
            @Value("${db.job.repo.driverClassName}") String className,
            @Value("${db.job.repo.jdbc-url}") String url,
            @Value("${db.job.repo.username}") String userName,
            @Value("${db.job.repo.schema}") String password) {
        return DataSourceBuilder
                .create()
                .driverClassName(className)
                .url(url)
                .username(userName)
                .password(password)
                .build();
    }

    /**
     * Этот метод создает источник данных на основе настроек свойств в "application.properties" для управления базой данных PostgreSQL, используемой в качестве репозитория данных.
     * @return созданный объект dataSource
     * 
     * Примечание:
     *    Аннотации @ConfigurationProperty @Value избыточны для учебных целей, одной достаточно.  
     */
    @Bean("pgDataSource")
    @ConfigurationProperties(prefix = "db.src")
    public DataSource pgDataRepository(
            @Value("${db.src.driverClassName}") String className,
            @Value("${db.src.jdbc-url}") String url, 
            @Value("${db.src.username}") String userName,
            @Value("${db.src.password}") String password) {

        return DataSourceBuilder
                .create()
                .driverClassName(className)
                .url(url).username(userName)
                .password(password)
                .build();
    }
}
@Component
public class JobCompletionNotificationListener implements JobExecutionListener {

    private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);

    private final JdbcTemplate jdbcTemplate;

    /**
     * Конструктор - Позволяет создать объект/экземпляр JdbcTemplate, потому что spring data jdbc на пути JAVA библиотеки
     * @param jdbcTemplate
     */
    public JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
          }

    @Override
    public void beforeJob(JobExecution jobExecution) {
        JobExecutionListener.super.beforeJob(jobExecution);
        log.info("Работа {} начата", jobExecution.getJobInstance().getJobName());
    }

    @Override
    public void afterJob(JobExecution jobExecution) {
        JobExecutionListener.super.afterJob(jobExecution);
        log.info("Работа {} завершена", jobExecution.getJobInstance().getJobName());
        if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
            log.info("!!! РАБОТА ЗАВЕРШЕНА! Время проверить результаты");

            jdbcTemplate.query("SELECT first_name, last_name FROM people", new DataClassRowMapper<>(Person.class))
                    .forEach(person -> log.info("Найдено - имя, фамилия ( {},{}) в базе данных.", person.firstName(),person.lastName() ));
        }
    }
}
public record Person(String firstName, String lastName) {}
public class PersonItemProcessor implements ItemProcessor<Person, Person> {

    private static final Logger log = LoggerFactory.getLogger(PersonItemProcessor.class);

    @Override
    public Person process(final Person person) {
        final String firstName = person.firstName().toUpperCase();
        final String lastName = person.lastName().toUpperCase();

        final Person transformedPerson = new Person(firstName, lastName);

        log.info("Преобразуем (" + person + ") в (" + transformedPerson + ")");

        return transformedPerson;
    }
}

src/main/resource

***application.properties***

db.job.repo.driverClassName=com.mysql.cj.jdbc.Driver
db.job.repo.jdbc-url=jdbc:mysql://localhost:3306/batch-initial?currentSchema=batch-initial
db.job.repo.username=****
db.job.repo.password=*****
db.job.repo.schema=batch-initial
# Нужно ли заполнять схему для Spring Batch в случае, если она отсутствует
#batch.db.initialize-schema=ALWAYS
db.job.repo.initialize-schema=ALWAYS

db.src.jdbc-url=jdbc:postgresql://127.0.0.1:5432/SPRINGBATCH?currentSchema=batch-initial
db.src.username=******
db.src.password=******
db.src.driverClassName=org.postgresql.Driver
***data.sql***

DROP TABLE people IF EXISTS;

CREATE TABLE people  (
 --   id BIGINT AUTO_INCREMENT PRIMARY KEY,
    person_id BIGINT AUTO_INCREMENT NOT NULL PRIMARY KEY,
    first_name VARCHAR(20),
    last_name VARCHAR(20)
);
***sample-data.txt***

Jill,Doe
Joe,Doe
Justin,Doe
Jane,Doe
John,Doe

Файл pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.10</version>
        <relativePath/> <!-- искать родителя в репозитории -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>batchprocessing</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Демо проект для Batch Service</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>22</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
                <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.7.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Я ожидал расширить DefauldBatchConfiguration при настройке сервиса Spring Batch

Ответ или решение

Обзор ошибки UnsatisfiedDependencyException при расширении DefaultBatchConfiguration в Spring Batch

При разработке приложения на основе Spring Batch часто возникает необходимость настройки и расширения конфигураций. Однако, когда вы пытаетесь расширить DefaultBatchConfiguration, это может привести к ошибке UnsatisfiedDependencyException, как указывает ваш лог. Давайте глубже изучим эту проблему и предложим решение.

Суть проблемы

Ошибка UnsatisfiedDependencyException возникает, когда Spring не может создать необходимый для компонента объект. В вашем случае возникает проблема с созданием JobRepository, который используется для управления метаданными заданий в Spring Batch. Конкретное сообщение об ошибке:

Unable to configure the default job repository

указывает на то, что Spring не может найти необходимый бин DataSource для конфигурации JobRepository.

Причины

  1. Отсутствие бина DataSource: Сообщение об ошибке явно указывает на то, что Spring не смог найти бин DataSource, который требуется для конфигурации JobRepository.

  2. Проблемы с конфигурацией: Если вы расширяете DefaultBatchConfiguration, не забудьте предоставить необходимые бины для работы. DefaultBatchConfiguration ожидает, что в контексте будет доступен DataSource, именуемый dataSource.

Решение

Чтобы устранить это предупреждение и ошибку, выполните следующие шаги:

  1. Обеспечьте наличие бина DataSource:

    Убедитесь, что у вас есть DataSource, названный dataSource, в вашем контексте Spring. Вы можете изменить вашу конфигурацию следующим образом:

    @Bean(name = "dataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
       return DataSourceBuilder.create().build();
    }

    В этом методе вы объявляете основной DataSource, который будет использоваться для JobRepository.

  2. Обновление метода JobRepository:

    Убедитесь, что ваш метод для создания JobRepository использует правильный бин dataSource. Вы можете настроить его следующим образом:

    @Bean
    @Override
    public JobRepository jobRepository() throws Exception {
       JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
       factory.setDataSource(dataSource()); // Здесь используем бин dataSource
       factory.setTransactionManager(new DataSourceTransactionManager(dataSource()));
       factory.setIsolationLevelForCreate("ISOLATION_SERIALIZABLE");
       factory.afterPropertiesSet();
       return factory.getObject();
    }
  3. Проверка файла application.properties:

    Убедитесь, что ваш файл application.properties настроен правильно и содержит все необходимые данные для подключения к MySQL.

    spring.datasource.url=jdbc:mysql://localhost:3306/batch-initial
    spring.datasource.username=ваш_пользователь
    spring.datasource.password=ваш_пароль
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

Заключение

Настройка Spring Batch с использованием DefaultBatchConfiguration требует внимательного подхода к обеспечению наличия необходимых бинов для работы вашего приложения. Обеспечив наличие корректного DataSource и соответствующих методов, вы сможете избежать возникновения ошибок, таких как UnsatisfiedDependencyException.

Если все сделано правильно, ваше приложение должно начать работать без ошибок. Это поможет вам углубить понимание работы Spring Batch и его конфигураций, а также успешного расширения стандартного функционала. Если у вас появятся дополнительные вопросы, не стесняйтесь обращаться за помощью к сообществу Spring или использовать ресурсы официальной документации.

Оцените материал
Добавить комментарий

Капча загружается...