programing

클리닝 코드 - @Autowire를 적용해야 하는 위치는 어디입니까?

batch 2023. 7. 5. 20:33
반응형

클리닝 코드 - @Autowire를 적용해야 하는 위치는 어디입니까?

간단한 예로 시작하겠습니다.Spring boot 응용 프로그램이 실행 중입니다.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위치(댓글의 위치를 표시했습니다)

스프링 팀은 다음을 권장합니다.콩에는 항상 생성자 기반 의존성 주입을 사용합니다.필수 종속성에는 항상 어설션을 사용합니다.

이제 이걸 따르면, 저는 생성자 기반의 의존성 주입이 있습니다.

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

이것은 또한 내가 편집해야 한다는 것을 의미합니다.Application.java또한, 생성자는 논쟁이 필요하기 때문입니다.Application.java만약 제가 세터 주사를 사용하려고 하면, 저는 같은 경고를 받을 것입니다.만약 제가 그것을 다시 고려한다면, 제 생각에, 저는 몇 가지 끔찍한 코드를 가지게 될 것입니다.

// 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이 질문은 자동 배선되는 모든 항목에 적용됩니다.

참고 2 단지 그것을 말하는 것입니다.MyCommandLineRunner.javaDataSource를 자동 배선/초기화해야 하므로 다른 빈 생성자를 사용할 수 없습니다.오류가 보고되고 컴파일되지 않습니다.

개선할 수 있는 몇 가지 방법이 있습니다.

  1. 제거할 수 있습니다.@Autowired당신의MyCommandLineRunner당신이 말하는 것처럼@Bean메소드는 그것의 인스턴스를 구성합니다.주입합니다.DataSource인수로서 메소드에 직접 포함됩니다.

  2. 또는 제거@Autowired그리고 그것을 제거합니다.@Bean그리고 따귀를 때립니다.@Component에 대한 주석MyCommandLineRunner감지하고 공장 방식을 제거합니다.

  3. 인라인 사용자MyCommandLineRunner마음속에@Bean람다 방법입니다.

자동 배선 없음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

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

이 모든 것은 인스턴스를 구성하는 데 유효한 방법입니다.어떤 것을 사용할지, 당신이 편한 것을 사용하세요.더 많은 옵션(여기에 언급된 옵션에 대한 모든 변형)이 있습니다.

필드를 만드는 것을 고려합니다.ds최종적으로, 그러면 당신은 필요하지 않습니다.@Autowired종속성 주입에 대한 자세한 내용은 http://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-spring-beans-and-dependency-injection.html#using-boot-spring-beans-and-dependency-injection 를 참조하십시오.

코드를 깨끗하게 유지하기 위해 롬복 주석을 사용하는 것을 고려해 본 적이 있습니까? @RequiredArgsConstructor(onConstructor = @__(@Autowired))@Autowired 주석을 사용하여 생성자를 생성합니다.여기서 더 보기 https://projectlombok.org/features/Constructor.html

코드는 다음과 같습니다.

@Slf4j
@RequiredArgsConstructor
// MyCommandLineRunner.java
public class MyCommandLineRunner implements CommandLineRunner {

    //final fields are included in the constructor generated by Lombok
    private final DataSource ds;

    @Override
    public void run(String... args) throws Exception {
        log.info("DataSource: {} ", ds.toString());
    }
}

// Application.java
@SpringBootApplication
@RequiredArgsConstructor(onConstructor_={@Autowired}) // from JDK 8
// @RequiredArgsConstructor(onConstructor = @__(@Autowired)) // up to JDK 7
public class Application {

    private final Datasource ds;

    public static void main(String... args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean 
    public MyCommandLineRunner schedulerRunner() {
        return new MyCommandLineRunner(ds);
    }
}

나중에 편집

Lombok이 없는 솔루션은 콩이 생성될 때 의존성을 주입하기 위해 Spring에 의존합니다.

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    /**
     * dependency ds is injected by Spring
     */
    public MyCommandLineRunner schedulerRunner(DataSource ds) {
        return new MyCommandLineRunner(ds);
    }
}

// MyCommandLineRunner.java
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());
    }
}

언급URL : https://stackoverflow.com/questions/43174074/clean-code-where-should-autowired-be-applied

반응형