@Configruation 의 용도는?
Spring context 에 의해 만들어지는 Bean들 보다 먼저 생성되는 Bean.
즉 @Configuration 이 붙은 것들은 다른것 보다 먼저 생성되어진다는 말이다.
아무 설정도 안하면 기본적으로 Spring은 많은수의 Bean들을 기본적으로 만든다.
그중 사용자의 입맛에 맞게 수정(Ovride 해야 할 일이 있을 경우) 해당 annotation을 붙여서 재 정의 한다.
재정의의 가장 흔한 예)
DataSource 라는 Bean 이 생성 될때 해당 내용을 입맛에 맞게 db 정보를 변경하는 예.
@Configuration
public class CustomConfig {
@Bean
public DataSource dataSource() {
// 기본적으로 제공되는 DataSource 빈을 커스터마이징
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
dataSource.setUsername("user");
dataSource.setPassword("password");
return dataSource;
}
}
아래와 같은 소스가 있었다.
@Service
@Slf4j
public class UserServiceImpl implements UserService {
UserRepository userRepository;
BCryptPasswordEncoder passwordEncoder;
@Autowired
public UserServiceImpl(UserRepository userRepository, BCryptPasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
.....
}
멤버 변수에 @Autowired 를 하지 않고
spring 이 추천 하는 생성자를 통한 주입.
근데 UserRepository 소스를 보는 순간 의문이 생겼다.
UserRepository 는 interface 다
그리도 아무런 annotation이 붙어 있지 않다 (@Bean , @Configuration, @Component 등등)
package com.example.userservice.jpa;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<UserEntity, Long> {
UserEntity findByUserId(String userId);
UserEntity findByEmail(String username);
}
UserServiceImpl 이 생성되어 Bean으로 등록 되기 전에
이미 UserRepository 가 Bean으로 먼저 생성이 되어 있어야 하는데
생성하는 annotation이 하나도 없는데 어떻게 주입이 되는거지?
Interface 라 그런가?
답은 Perplexity 가 알려 줬다.
Spring에서 생성자 주입을 사용하는 것은 좋은 실천 방법입니다. UserRepository가 인터페이스임에도 불구하고 에러 없이 주입되는 이유에 대해 설명드리겠습니다.
인터페이스 주입
UserRepository는 인터페이스이지만, Spring Data JPA가 이를 자동으로 구현하고 빈으로 등록합니다
. 이는 다음과 같은 이유로 가능합니다:
- Spring Data JPA의 자동 구현: Spring Data JPA는 CrudRepository를 상속받은 인터페이스를 발견하면, 해당 인터페이스의 구현체를 자동으로 생성합니다.
- 프록시 객체 생성: Spring은 UserRepository 인터페이스를 기반으로 프록시 객체를 생성하고, 이를 빈으로 등록합니다.
- 자동 빈 등록: @EnableJpaRepositories 어노테이션(보통 @SpringBootApplication에 포함됨)이 설정되어 있으면, Spring Data JPA가 자동으로 리포지토리 인터페이스를 스캔하고 빈으로 등록합니다.
동작 원리
- 인터페이스 스캔: Spring Data JPA는 애플리케이션 컨텍스트가 로드될 때 UserRepository 인터페이스를 스캔합니다.
- 구현체 생성: 스캔된 인터페이스를 바탕으로 실제 구현체를 동적으로 생성합니다.
- 빈 등록: 생성된 구현체를 Spring 컨테이너에 빈으로 등록합니다.
- 의존성 주입: Abc 클래스의 생성자에서 UserRepository를 요청할 때, Spring은 등록된 빈을 주입합니다.
주의사항
- 명시적 구현 불필요: UserRepository에 @Repository나 다른 어노테이션을 추가할 필요가 없습니다. Spring Data JPA가 자동으로 처리합니다.
- 타입 기반 주입: Spring은 타입을 기반으로 의존성을 주입하므로, 인터페이스 타입만으로도 주입이 가능합니다.
- 프록시 패턴: Spring Data JPA는 프록시 패턴을 사용하여 실제 메서드 호출 시 쿼리를 생성하고 실행합니다.
결론적으로, UserRepository는 인터페이스이지만 Spring Data JPA의 자동 구현 및 빈 등록 메커니즘 덕분에 별도의 어노테이션 없이도 Abc 클래스에 주입될 수 있습니다. 이는 Spring의 강력한 기능 중 하나로, 개발자가 반복적인 CRUD 작업을 줄이고 비즈니스 로직에 집중할 수 있게 해줍니다.
또 의문이 되는 소스를 봤다.
WebSecurityNew() 생성자 메소드 위에 @Autowired 가 없는데 어떻게
Member 변수들이 주입되는가??
답: @Configuration이 붙은 class 에 생성자 메소드에 정의한 Member 변수들은 @Autowired 를 안 붙여도 자동 주입 해준댄다.
명시적으로 이해하기 편하게 그래도 생성자 메소드 위에 @Autowried 를 붙이는 습관으로 개발 하랜다.
먼눔의 알아야 할것들이 이리 많은가 몇줄 ctrl+c+v 하는게 이리 힘들어서야.
@Configuration
public class WebSecurityNew {
private UserService userService;
private BCryptPasswordEncoder bCryptPasswordEncoder;
private Environment env;
public static final String ALLOWED_IP_ADDRESS = "127.0.0.1";
public static final String SUBNET = "/32";
public static final IpAddressMatcher ALLOWED_IP_ADDRESS_MATCHER = new IpAddressMatcher(ALLOWED_IP_ADDRESS + SUBNET);
public WebSecurityNew(Environment env, UserService userService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.env = env;
this.userService = userService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}'SI 업무 > spring boot' 카테고리의 다른 글
| mybatis-config.xml 설정 안 먹을때 (2) | 2024.12.27 |
|---|---|
| @RequestMapping 과 @GetMapping 의 중복 / (0) | 2024.12.26 |
| 5. JWT, Spring Security (0) | 2024.12.02 |
| 4. profile 로 다른 설정 관리 (0) | 2024.11.29 |
| 3. log는 어떻게 남기지? (1) | 2024.11.29 |