干净的代码-@Autowired应该在哪里应用? [英] Clean code - Where should @Autowired be applied?

查看:117
本文介绍了干净的代码-@Autowired应该在哪里应用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将从一个简单的例子开始.您有一个Spring启动应用程序,该应用程序在初始化时运行CommandLineRunner类.

I'll start with a simple example. You have a Spring boot application that runs a 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();
    }
}

现在,这样,就可以了,一切都很好.但是,IntelliJ会在@Autowired所在的位置报告警告(我在注释中标记了该位置)

Now, like this, this works, everything is OK. However, IntelliJ reports a warning where @Autowired is located (I marked where in the comment)

Spring团队建议:始终在bean中使用基于构造函数的依赖项注入.始终对强制性依赖项使用断言.

Spring team recommends: Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies.

现在,如果我遵循这一点,我将有一个基于构造函数的依赖注入

Now if I follow this, I have a constructor based dependency injection

@Autowired
public MyCommandLineRunner(DataSource ds) { ... }

这也意味着我也必须编辑Application.java,因为构造函数需要一个参数.在Application.java中,如果尝试使用setter注入,则会收到相同的警告.如果我也进行重构,我将得出一些讨厌的代码.

This also means that I have to edit Application.java as well, since the constructor needs an argument. In Application.java if I try to use the setter injection, I'll get the same warning. If I refactor that as well, I'll end up with 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);
    }
}

上面的代码产生相同的结果,但是在IntelliJ中不报告任何警告. 我很困惑,第二个代码比第一个更好吗?我是否遵循错误的逻辑?这应该以不同的方式接线吗?

The above code yields the same result, but doesn't report any warnings in IntelliJ. I'm confused, how is the 2nd code better than the first one? Am I following an incorrect logic? Should this be wired differently?

简而言之,正确的方法是什么?

note DataSource只是一个简单的例子,这个问题适用于所有自动装配的东西.

note DataSource is just a pure example, this question applies to anything being autowired.

注释2 只是说MyCommandLineRunner.java不能有另一个空的构造函数,因为DataSource需要自动装配/初始化.它会报告错误,并且不会被编译.

note 2 Just to say that MyCommandLineRunner.java can't have another, empty, constructor, since DataSource needs to be autowired/initialized. It will report an error and will not be compiled.

推荐答案

有几种改进方法.

  1. 您可以从MyCommandLineRunner中删除@Autowired,因为您正在让@Bean方法构造它的实例.将DataSource作为参数直接注入该方法.

  1. You can remove @Autowired from your MyCommandLineRunner as you are letting a @Bean method construct an instance of it. Inject the DataSource directly into the method as an argument.

或删除@Autowired并删除@Bean并在MyCommandLineRunner上打上@Component注释以检测到它并删除工厂方法.

Or remove @Autowired and remove the @Bean and slap a @Component annotation on your MyCommandLineRunner to have it detected and remove factory method.

在您的@Bean方法内以lambda形式插入MyCommandLineRunner.

Inline your MyCommandLineRunner inside your @Bean method as a lambda.

MyCommandLineRunner

中没有自动装配

No Autowiring in the MyCommandLineRunner

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

的用法

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

所有这些都是构造实例的有效方法.使用哪一种,请使用自己喜欢的一种.还有更多选项(此处提到的所有变体).

All of these are valid ways of constructing your instances. Which one to use, use the one that you feel comfortable with. There are more options (all variations on the ones mentioned here).

这篇关于干净的代码-@Autowired应该在哪里应用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆