我将从一个简单的例子开始。您有一个Spring启动应用程序,该应用程序在初始化时运行CommandLineRunner
类。
// 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();
}
}
现在,这样,就可以了,一切都很好。但是,IntelliJ报告警告
@Autowired
所在的位置(我在注释中标出了位置)现在,如果我遵循这一点,我将有一个基于构造函数的依赖注入(inject)
@Autowired
public MyCommandLineRunner(DataSource ds) { ... }
这也意味着我也必须编辑
Application.java
,因为构造函数需要一个参数。在Application.java
中,如果尝试使用setter注入(inject),则会收到相同的警告。如果我也重构它,我会得出一些讨厌的代码。// 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);
}
}
上面的代码产生相同的结果,但是在IntelliJ中不报告任何警告。
我很困惑,第二个代码比第一个更好吗?我是否遵循错误的逻辑?这应该以不同的方式接线吗?
简而言之,正确的方法是什么?
注意
DataSource
只是一个纯粹的示例,此问题适用于所有 Autowiring 的东西。note 2只是说
MyCommandLineRunner.java
不能有另一个空的构造函数,因为DataSource需要 Autowiring /初始化。它会报告错误,并且不会被编译。 最佳答案
有几种方法可以改善它。
@Autowired
方法构造它的实例时,可以从MyCommandLineRunner
中删除@Bean
。将DataSource
作为参数直接注入(inject)到方法中。 @Autowired
并删除@Bean
并在@Component
上打上MyCommandLineRunner
批注以检测到它并删除工厂方法。 MyCommandLineRunner
作为lambda内联到@Bean
方法中。 MyCommandLineRunner
中没有 Autowiring public class MyCommandLineRunner implements CommandLineRunner {
private final Log logger = LogFactory.getLog(getClass());
private final DataSource ds;
public MyCommandLineRunner(DataSource ds) { this.ds = ds; }
@Override
public void run(String... args) throws Exception {
logger.info("DataSource: " + ds.toString());
}
}
和应用程序类。
@SpringBootApplication
public class Application {
public static void main(String... args) {
SpringApplication.run(Application.class, args);
}
@Bean
public MyCommandLineRunner schedulerRunner(DataSource ds) {
return new MyCommandLineRunner(ds);
}
}
@Component
的用法@Component
public class MyCommandLineRunner implements CommandLineRunner {
private final Log logger = LogFactory.getLog(getClass());
private final DataSource ds;
public MyCommandLineRunner(DataSource ds) { this.ds = ds; }
@Override
public void run(String... args) throws Exception {
logger.info("DataSource: " + ds.toString());
}
}
和应用程序类。
@SpringBootApplication
public class Application {
public static void main(String... args) {
SpringApplication.run(Application.class, args);
}
}
内联
CommandLineRunner
@SpringBootApplication
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class)
public static void main(String... args) {
SpringApplication.run(Application.class, args);
}
@Bean
public MyCommandLineRunner schedulerRunner(DataSource ds) {
return (args) -> (logger.info("DataSource: {}", ds);
}
}
所有这些都是构造实例的有效方法。使用哪种,请使用自己喜欢的一种。还有更多选项(此处提到的所有变化)。