I'll start with a simple example. You have a Spring boot application that runs the CommandLineRunner class on initialization.
// MyCommandLineRunner.java public class MyCommandLineRunner implements CommandLineRunner { private final Log logger = LogFactory.getLog(getClass()); @Autowired //IntelliJ Warning private DataSource ds; @Override public void run(String... args) throws Exception { logger.info("DataSource: " + ds.toString()); } } // Application.java @SpringBootApplication public class Application { public static void main(String... args) { SpringApplication.run(Application.class, args); } @Bean public MyCommandLineRunner schedulerRunner() { return new MyCommandLineRunner(); } }
Now, like this, it works, everything is in order. However, IntelliJ reports a warning that @Autowired is @Autowired (I noted in the comment)
The Spring team recommends: Always use constructor-based dependency injection in beans. Always use assertions for required dependencies.
Now, if I follow this, I have a constructor-based dependency injection
@Autowired public MyCommandLineRunner(DataSource ds) { ... }
It also means that I need to edit Application.java as well, since the constructor needs an argument. In Application.java , if I try to use installer injection, I will get the same warning. If I reorganize this, I will eventually find some, in my opinion, nasty code.
// MyCommandLineRunner.java public class MyCommandLineRunner implements CommandLineRunner { private final Log logger = LogFactory.getLog(getClass()); private DataSource ds; @Autowired // Note that this line is practically useless now, since we're getting this value as a parameter from Application.java anyway. public MyCommandLineRunner(DataSource ds) { this.ds = ds; } @Override public void run(String... args) throws Exception { logger.info("DataSource: " + ds.toString()); } } // Application.java @SpringBootApplication public class Application { private DataSource ds; @Autowired public Application(DataSource ds) { this.ds = ds; } public static void main(String... args) { SpringApplication.run(Application.class, args); } @Bean public MyCommandLineRunner schedulerRunner() { return new MyCommandLineRunner(ds); } }
The code above gives the same result, but does not report any warnings in IntelliJ. I am confused, how is the second code better than the first? Am I following the wrong logic? Should it be connected otherwise?
In short, what is the right way to do this?
Thanks in advance!
Note that if there is syntax or a small logical error, I am typing the code here directly. DataSource is just a pure example, this question applies to everything that was auto-notified.
note 2 Just to say that MyCommandLineRunner.java cannot have another, empty, constructor, since the DataSource must be auto-updated / initialized. It will report an error and will not be compiled.