How to provide a parameterized component in Spring?

mike :

Currently, I have a component that implements CommandLineRunner and parses the command line arguments with Commons CLI.

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

There is also another component, Requester, which depends on (a subset of) those arguments.

@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;
  }

}

What can I do to autowire a configured Requester into future components? What is the Spring way to create parameterized, singleton beans?


One solution would be to have every component, that has any dependency on the program arguments, implement CommandLineRunner. This way it could parse the program arguments itself, but that is a highly redundant approach. There must be a better solution.

mike :

Inspired by JB Nizet's comment, I now parse the command line arguments and register the beans manually before I start the Spring application.

I identified two ways: provide the c'tor arguments and let Spring create the beans or provide a supplier function to Spring.

Now it's possible to declare @Autowire private Requester requester; in other parts of the application.


In order for this solution to work the @Component annotation needs to be removed from Requester, because otherwise problems may occur when Spring can't provide the necessary constructor arguments.

@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);
    }

}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=113772&siteId=1