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.
Have you checked the annotation @Value? It allows you to inject values from properties files at run time. You should be using that one each time you need to inject some external value from resources. For instance your code can be:
@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;
}
}
In your application.properties file:
...
host = myhost
port = 1234
...
If you want to pass the parameters as command line arguments you can simply invoke the command as you did:
java -jar app.jar --host 123.123.222 --port 8080
and these parameters will override the ones from the property files since they are given higher priority as can be seen in the documentation.
Use post @PostConstruct to deal with that.
Lets assume that this is your CommandLineRunner implementation :
@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");
}
}
Then create Getters for all the args you want, And the the Requester will look like that:
@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;
}
}
The @PostConstruct will happen when the component is created
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With