@Autowired 대신 Spring Constructor Dependency Injection을 사용하는 이유
자동 유선
내가 본 대부분의 Spring 개발자는 클래스에 종속성을 주입하기 위해 여전히 @Autowired 구문을 사용하고 있습니다. 이것은 더 이상 권장되지 않으며 Intellij는 심지어 사용하려고 할 때 경고를 표시합니다.
오늘 우리는 이러한 방식으로 종속성 주입을 사용하지 않는 한 가지 이유를 살펴보겠습니다. 나는 또한 이것이 이전에도 생산 사건을 일으키는 것을 보았습니다. 필드에 @Autowired가 있으면 필드가 잠재적으로 변경 가능하고 테스트하기가 더 어렵습니다. 주입된 필드를 변경할 수 있게 하면 Spring이 CGLIB 라이브러리를 사용하여 이러한 주입된 클래스를 프록시하는 방법을 방해할 수 있습니다.
DTO 설정
테스트 프로젝트에서 우리는 사용자에게 세션 범위가 지정되어야 하는 DTO를 설정하고 있습니다. 따라서 각 사용자는 자신의 세션과 관련된 Bean의 인스턴스만 볼 수 있습니다.
UserDataDto.java 클래스:
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.SessionScope;
@Component
@SessionScope
public class UserDataDto {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
Spring Security 구성 설정
또한 여기에서 테스트를 위해 사용하는 두 사용자 인스턴스를 모두 초기화하기 위해 몇 가지 Spring Security 설정도 있습니다.
SecurityConfig.class:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user1 = User.withUsername("user1")
.password(passwordEncoder.encode("password"))
.roles("ADMIN")
.build();
UserDetails user2 = User.withUsername("user2")
.password(passwordEncoder.encode("password"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user1, user2);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/**")
.hasRole("ADMIN")
.anyRequest()
.authenticated();
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
}
컨트롤러 클래스 설정
마지막으로 컨트롤러 클래스가 있습니다.
UserController.class:
@RestController("/")
public class UserController {
@Autowired
UserDataDto userDataDto;
@PostMapping("/saveUserName")
public void saveUserName(@RequestBody String userName){
userDataDto.setUserName(userName);
}
@PostMapping("/saveUserNameReplaceInstance")
public void saveUserNameReplaceInstance(@RequestBody String userName){
UserDataDto userDataDto = new UserDataDto();
userDataDto.setUserName(userName);
this.userDataDto = userDataDto;
}
@GetMapping("/getUserName")
public String getUserName(){
return userDataDto.getUserName();
}
}
테스트 의도된 효과
이제 Spring Boot 애플리케이션을 실행하고 테스트를 시작하겠습니다!
Postman을 사용하여 user1을 사용하여/saveUserName 끝점에 POST합니다.
이제 별도의 Chrome 시크릿 창을 사용하여 user2로/getUserName 엔드포인트에서 GET을 시도합니다. 아무것도 보여주지 않아, 좋아!
세션 범위 빈을 싱글톤으로 덮어쓰기
이제 Autowired 빈을 대체할 새 엔드포인트/saveUserNameReplaceInstance로 의도적으로 문제를 일으킬 수 있습니다.
@PostMapping("/saveUserNameReplaceInstance")
public void saveUserNameReplaceInstance(@RequestBody String userName){
UserDataDto userDataDto = new UserDataDto();
userDataDto.setUserName(userName);
this.userDataDto = userDataDto;
}
이번에는 user1과 함께 새 끝점을 사용하여 Postman을 통해 동일한 내용을 보냅니다.
그리고 user2가 있는 Chrome에서 이제 user1의 데이터를 볼 수 있습니다!
안 돼!! 여기서 큰 문제는 기본적으로 SessionScope 빈을 모든 인스턴스 간에 공유되는 싱글톤으로 바꿨다는 것입니다!
생성자 주입
이제 생성자 주입이 이것을 방지하는 방법은 무엇입니까? Intellij는 @Autowired 주석을 클릭하고 창에서 Alt-Enter를 누르고 생성자 생성을 클릭하면 Autowired 코드를 자동으로 리팩터링합니다.
그러나 편의를 위해 다른 수업에서 이것을 했습니다.
ConstructorInjectionController.java:
@RestController
public class ConstructorInjectionController {
final
UserDataDto userDataDto;
public ConstructorInjectionController(UserDataDto userDataDto) {
this.userDataDto = userDataDto;
}
@PostMapping("/saveUserNameCi")
public void saveUserName(@RequestBody String userName){
userDataDto.setUserName(userName);
}
@PostMapping("/saveUserNameReplaceInstanceCi")
public void saveUserNameReplaceInstance(@RequestBody String userName){
UserDataDto userDataDto = new UserDataDto();
userDataDto.setUserName(userName);
//this.userDataDto = userDataDto;
}
@GetMapping("/getUserNameCi")
public String getUserName(){
return userDataDto.getUserName();
}
}
saveUserNameReplaceInstanceCi 매핑이 포함된 줄의 주석을 제거하면 IDE에서 큰 실수를 방지할 수 있습니다. 이렇게 하면 컨트롤러 클래스를 인스턴스화한 후 주입된 필드를 최종적이고 변경할 수 없는 것으로 선언할 수 있습니다.
언제나처럼 코드가 켜져 있습니다Github.
Reference
이 문제에 관하여(@Autowired 대신 Spring Constructor Dependency Injection을 사용하는 이유), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/terencepan/why-use-spring-constructor-dependency-injection-instead-of-autowired-51oh텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)