Как предоставить параметризованный компонент в Spring? - PullRequest
0 голосов
/ 26 ноября 2018

В настоящее время у меня есть компонент, который реализует CommandLineRunner и анализирует аргументы командной строки с помощью Commons CLI.

java -jar app.jar --host 123.123.222 --port 8080

Существует также другой компонент, Requester, который зависит (подмножество) этих аргументов.

@Component
public class Requester
{

  // host and port need to be configured once
  private final String host;
  private final int port;

  public Requester(String host, int port)
  {
    this.host = host;
    this.port = port;
  }

  public boolean doRequest(String name) throws Exception
  {
    String url = "http://" + host + ":" + port + "/?command=" + name;

    URL obj = new URL(url);
    HttpURLConnection connection = (HttpURLConnection) obj.openConnection();
    int responseCode = connection.getResponseCode();
    return 200 == responseCode;
  }

}

Что я могу сделать для автоматической передачи настроенного Requesterв будущие компоненты?Как Spring может создавать параметризованные одноэлементные компоненты?


Одним из решений было бы использование каждого компонента, который имеет какую-либо зависимость от аргументов программы, реализующего CommandLineRunner.Таким образом, он может анализировать аргументы программы сам, но это очень избыточный подход.Должно быть лучшее решение.

Ответы [ 3 ]

0 голосов
/ 26 ноября 2018

Используйте post @PostConstruct, чтобы справиться с этим.
Предположим, что это ваша реализация CommandLineRunner:

@Component
public class CLIArgs implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        // Parse the args, and for each arg set system property
        System.setProperty("ArgName", "value");
    }
}

Затем создайте геттеры для всех аргументов, которые выхочу, и Requester будет выглядеть так:

@Component
public class Requester {
    @Autowired
    private Environment env; // This is a spring component

    // host and port need to be configured once
    private String host;
    private int port;

    @PostConstruct
    public void init () {
        this.host = env.getProperty("host");
        this.port = Integer.parseInt(env.getProperty("port"));
    }

    public boolean doRequest(String name) throws Exception {
        String url = "http://" + host + ":" + port + "/?command=" + name;

        URL obj = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) obj.openConnection();
        int responseCode = connection.getResponseCode();
        return 200 == responseCode;
    }
}

При создании компонента @PostConstruct произойдет

0 голосов
/ 27 ноября 2018

Вдохновленный комментарием Дж. Б. Низета, я теперь анализирую аргументы командной строки и вручную регистрирую bean-компоненты перед запуском приложения Spring.

Я определил два способа: предоставить аргументы c'tor и позволить Spring создатьbean-компоненты или предоставляют функцию поставщика для Spring.

Теперь можно объявить @Autowire private Requester requester; в других частях приложения.


Чтобы это решение работало, аннотацию @Component необходимо удалить из Requester, поскольку в противном случае могут возникнуть проблемы, когда Spring не может предоставить необходимые аргументы конструктора.

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        // parse args here
        String host = getHost();
        int port = getPort();

        SpringApplication application = new SpringApplication(Application.class);

        // provide c'tor arguments and let Spring create the instance
        BeanDefinitionCustomizer bdc = bd -> {
            // working with bd.getPropertyValues() uses setter instead of c'tor
            ConstructorArgumentValues values = bd.getConstructorArgumentValues();
            values.addIndexedArgumentValue(0, host);
            values.addIndexedArgumentValue(1, port);
        };
        application.addInitializers((GenericApplicationContext ctx) -> ctx.registerBean(Requester.class, bdc));

        // or create the instance yourself
        Requester requester = new Requester(host, port);
        application.addInitializers((GenericApplicationContext ctx) -> ctx.registerBean(Requester.class, () -> requester));
        application.run(args);
    }

}
0 голосов
/ 26 ноября 2018

Вы проверили аннотацию @ Значение ?Это позволяет вам вводить значения из файлов свойств во время выполнения.Вы должны использовать это каждый раз, когда вам нужно добавить какую-то внешнюю ценность из ресурсов.Например, ваш код может быть:

@Component
public class Requester
{
  @Value("${host}")
  private final String host;
  @Value("${port}")
  private final int port;

  public boolean doRequest(String name) throws Exception
  {
    String url = "http://" + host + ":" + port + "/?command=" + name;

    URL obj = new URL(url);
    HttpURLConnection connection = (HttpURLConnection) obj.openConnection();
    int responseCode = connection.getResponseCode();
    return 200 == responseCode;
  } 
}

В вашем application.properties файле:

...
host = myhost
port = 1234
...

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

java -jar app.jar --host 123.123.222 --port 8080

, и эти параметры переопределяют параметры из файлов свойств, поскольку они имеют более высокий приоритет, как это видно из документации .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...