Spring Boot - Автопровод нулевой внутри абстрактного класса - PullRequest
0 голосов
/ 02 ноября 2019

У меня есть классы ниже.

public interface Operation
public abstract class AbstractOperation  implements Operation
public class Operation extends AbstractOperation

Класс Operation

public interface Operation {
     GenericClientResponse validateCustomerId();

Класс AbstractOperation

public abstract class AbstractOperation  implements Operation {

    protected GenericClientRequest buildClientValidationRequest() {
        return new GenericClientRequest();
    }

В классе Operation есть свойства с автосвязью.

public class Operation extends AbstractOperation {
    @Autowired
    UserAccountsRepository userAccountsRepository; // not autowiring
    @Autowired
    WebClient.Builder webClientBuilder; // not autowiring

Но ни одно из этих свойств не является автоматическим. Они нулевые во время выполнения. Но если я автоматически подключу их в моем классе обслуживания, то автоматическое подключение будет успешно выполнено.

    @Service
    @Transactional
    public class TransactionServiceImpl implements TransactionService {

          @Autowired
          UserAccountsRepository userAccountsRepository; // Autowires successfully.

Ниже приведен класс хранилища.

public interface UserAccountsRepository extends 
             JpaRepository<UserAccountsEntity, Integer> {

    @Query("SELECT account FROM UserAccountsEntity account where 
                 account.accountNo = :acc")
    UserAccountsEntity getAccountByAccNo(@Param("acc") String userId);

В моем коде я храню карту классов операций и получаюсвязанный класс операций в соответствии с ключом.

 operationMap.put("test_op1", new Operation());
 operationMap.put("test_op2", new Operation2());

Затем я вызываю это, чтобы получить правильную операцию

Optional.ofNullable(operationMap.get("test_op1"));

Теперь я понимаю, что создание нового экземпляра вызывает нулевую автопроводку. Как получить новый объект без нового ключевого слова?

Ответы [ 3 ]

0 голосов
/ 02 ноября 2019

Я вижу несколько возможностей, основанных на том, что вы поделились:

  1. Структура пакета неверна - если класс Operation не совпадаетпакет (или подпакет) в качестве класса main, компонент сканирования может выбрать ваш класс. Пожалуйста, прочитайте этот ответ, чтобы убедиться, что вы правильно реализовали структуру пакета.

  2. Возможно, вам не хватает аннотации Spring для класса Operation, например@Component или @Service. Или вы можете создавать экземпляр класса вручную в своем коде вне контекста приложения Spring. Убедитесь, что вы создаете бин правильно.

Если вы пытаетесь создать бин вручную, вы должны сделать это , используя @Bean вкласс конфигурации.

0 голосов
/ 02 ноября 2019

Прежде всего, не выбирайте абстрактный класс вместо интерфейса по возможным причинам:

  1. Абстрактные классы не создаются без конкретного элементареализация классов. Они не будут зарегистрированы в качестве компонента Spring во время выполнения.

  2. Внедрение конструктора в абстрактные классы не поддерживается Spring. Но есть две альтернативы:

    • Конструктор-инжекция в конкретные подклассы.

    • Сеттер-инъекция в абстрактном классе.

Теперь альтернативы, которые вы можете использовать для решения вашей проблемы:

У вас есть интерфейс и класс с тем же именем, что и Operation. Удалите его.

1-й подход: удалите абстрактный класс и непосредственно реализуйте интерфейс.

Обновите код так:

public interface Operation {
   public GenericClientResponse validateCustomerId();
}

@Component
public class OperationImpl implements Operation {

    @Autowired
    UserAccountsRepository userAccountsRepository;

    @Autowired
    WebClient.Builder webClientBuilder;

    public GenericClientRequest buildClientValidationRequest() {
        return new GenericClientRequest();
    }

    public GenericClientResponse validateCustomerId() {
       // code
    }

}

2-й подход: попробуйте использовать конструктор-инъекцию в конкретных подклассах.

public interface Operation {
   public GenericClientResponse validateCustomerId();
}

public abstract class AbstractOperation implements Operation {

      UserAccountsRepository userAccountsRepository;

      WebClient.Builder webClientBuilder;

      public AbstractOperation(UserAccountsRepository userAccountsRepository, WebClient.Builder webClientBuilder) {
         this.userAccountsRepository = userAccountsRepository;
         this.webClientBuilder = webClientBuilder;
      }

      public GenericClientRequest buildClientValidationRequest() {
            return new GenericClientRequest();
      }

      public GenericClientResponse validateCustomerId() {
           // code
      }
}

@Component
public class OperationImpl extends AbstractOperation {

    @Autowired
    public OperationImpl(UserAccountsRepository userAccountsRepository, WebClient.Builder webClientBuilder) {
        super(userAccountsRepository, webClientBuilder);
    }
}

3-й подход: попробуйте использовать сеттер-инъекцию в абстрактном классе.

public interface Operation {
    public GenericClientResponse validateCustomerId();
 }

 public abstract class AbstractOperation implements Operation {

      UserAccountsRepository userAccountsRepository;

      WebClient.Builder webClientBuilder; 

      @Autowired
      public final void setUserAccountsRepository(UserAccountsRepository userAccountsRepository) {
        this.userAccountsRepository = userAccountsRepository;
      }

      @Autowired
      public final void setWebClientBuilder(LogRepository webClientBuilder) {
        this.webClientBuilder = webClientBuilder;
      }

      public GenericClientRequest buildClientValidationRequest() {
            return new GenericClientRequest();
      }

      public GenericClientResponse validateCustomerId() {
           // code
      }
}

@Component
public class OperationImpl extends AbstractOperation {

     public void someMethod() {
          userAccountsRepository.someRepositoryMethod();
     }

}

Надеюсь, эта информация поможет вам.

Подробнее см. здесь .

0 голосов
/ 02 ноября 2019

Вы, вероятно, создаете экземпляр Operation с помощью new следующим образом:

Operation operation = new Operation(...);

Это делает ваш экземпляр Operation не-Spring управляемым. Следовательно, поскольку Spring не знает о вашем экземпляре, он не может автоматически связать ваши зависимости.

Если вам нравится:

@Component
public class Operation {
...
}

, вы получите правильную автосвязь ваших зависимостей. Если вам действительно нужно создать экземпляр Operation самостоятельно и сохранить зависимости с автопроводкой, вам нужно перейти на Configurable. Смотрите пару ссылок:

...