Как отложить инициализацию Spring Bean на основе переменной - PullRequest
0 голосов
/ 25 февраля 2020

Моя проблема в том, что мне нужно получить токен аутентификации, прежде чем я вызову API. API должен быть вызван при запуске приложения. Однако я испытываю затруднения в том, что оба вызова выполняются одновременно, что приводит к ошибке отсутствия маркера аутентификации перед выполнением вызова API.

Мне в основном нужен tokenUtilityClass для создания токена перед созданием экземпляра класса Paypal. Я пробовал аннотации @Preconstruct и @Lazy, но ни одна из них не работает для меня.

У меня есть логическое значение validToken, которое возвращает true после создания токена аутентификации.

Вот так выглядит мой файл конфигурации Springboot

@Autowired
private TokenUtilityClass tokenUtilityClass;


  @Bean ResourceConfig resourceConfig() {
      return new ResourceConfig().registerClasses(Version1Api.class); }

  @PostConstruct
  public void postConstruct() {
      tokenUtilityClass.tokenTimer();
  }


@DependsOn("TokenUtilityClass")
@ConditionalOnProperty(name ="tokenUtilityClass.validToken", havingValue ="true")
@Lazy
public Paypal eventPublisherBean() {
    return new Paypal();
}

Кто-нибудь есть идеи об инициализации класса Paypal только после того, как токен аутентификации был сгенерирован.

Буду признателен за любую помощь

Ответы [ 4 ]

1 голос
/ 26 февраля 2020

То, что вы объявили, не может работать:

@DependsOn("TokenUtilityClass")
@ConditionalOnProperty(name ="tokenUtilityClass.validToken", havingValue ="true")
@Lazy

, потому что tokenUtilityClass.validToken не свойство, а метод bean, а ConditionalOnProperty ожидает свойства.

У кого-нибудь возникнут идеи об инициализации класса Paypal только после того, как будет создан токен аутентификации.

Конкретно, вы не можете достичь этого напрямую с помощью Spring, потому что компоненты создаются, как только они требуются другими компонентами в их зависимостях.

Но заявив, что:

@Bean
@Lazy
public Paypal eventPublisherBean() {
    return new Paypal();
}

может сработать, если этот bean-компонент никогда не используется в качестве загружаемой зависимости других bean-компонентов, а скорее требуется в удобное для вас время: после того, как токен был
Чтобы добиться этого, у вас есть два способа:

1) не использовать внедрение зависимостей для экземпляра PayPal, а использовать исключительно фабрику бобов.
Не проверено, но звучит как @Lazy javado c:

Если эта аннотация отсутствует в определении @Component или @Bean, будет выполнена активная инициализация. Если он присутствует и установлен в значение true, @Bean или @Component не будут инициализированы до тех пор, пока на него не будет ссылаться другой компонент или он явно не будет извлечен из включающего BeanFactory.

Поэтому вставьте BeanFactory в компонент, ответственный за получение токен и использовать эту фабрику для инициализации bean-компонента после его получения.
Что-то вроде этого:

@Service
public class TokenUtility {

   private BeanFactory factory;

   public TokenUtility(BeanFactory factory){
     this.factory = factory;
   }

   public Token retrieveToken(){
     // call service to get the token
     //...
     // init the bean now -(it will also invoke its @PostConstruct method)
     PayPal payPal = beanFactory.getBean(PayPal.class);
   }

}

2) Более простая альтернатива BeanFactory - объявить bean-компонент как ленивую зависимость:

@Service
public class TokenUtility {

  @Lazy
  @Autowired
  Paypal paypal;

  public Token retrieveToken(){
         // call service to get the token
         //...
         // init the bean by invoking any method on that
          paypal.init();
       }
}

Я только что создал очень простой c проект (Java 11) для проверки: https://github.com/ebundy/lazy-init-spring-example/.

Когда вы выполните spring-boot:run, вы должны получить:

2020-02-26 09:38:05.883  INFO 7002 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 682 ms
TokenUtility init with status code=200
PayPal init
0 голосов
/ 25 февраля 2020

Похоже, вы делитесь кодом внутри класса с аннотацией @Configuration. Кажется, вы помечаете TokenUtilityClass аннотацией @Component (или аналогичной).

Проблема в том, что @PostConstruct подключен к вашему классу конфигурации, а не к TokenUtilityClass. Я предлагаю перенести @PostConstruct метод на TokenUtilityClass.

0 голосов
/ 26 февраля 2020

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

@Component
class TokenUtilityClass {
    private String freshToken;
    private Instant freshUntil;

    public String getToken() {
        if (freshUntil != null && Instant.now().isBefore(freshUntil)) {
            refreshToken();
        }
        return freshToken;
    }

    public void refreshToken() {
        // do something
    }
}

@Configuration
class ConfigurationClass {

    @Bean public Paypal eventPublisherBean(TokenUtilityClass tokenUtilityClass) {
        String token = tokenUtilityClass.getToken();
        // do something with token and return your bean
        return new Paypal();
    }

}
0 голосов
/ 25 февраля 2020

Вы ищете @Order аннотацию.

@Component
@Order(1)
public class First {

    @PostConstruct
    public void init() {
        System.out.println("first");
    }
}

@Component
@Order(2)
public class Second {

    @PostConstruct
    public void init() {
        System.out.println("second");
    }
}

@Order работает с обоими типами объявлений: @Component / @Service / @Repository / @Controller и с @Bean

Однако, если у вас есть четкая зависимость одного компонента от другого компонента, используйте аннотацию @DependsOn.

@Component("first")
public class First {

    public First() { // inject dependencies here if any
        System.out.println("The very first thing")
    }


    @PostConstruct
    public void init() {
        System.out.println("first");
    }
}

@Component
@DependsOn({"first"})
public class Second {

    @PostConstruct
    public void init() {
        System.out.println("second");
    }
}

Дополнительную информацию можно получить здесь

...