Component와 Util(static)은 어떤 차이를 가지고 사용할까?

2024-11-14

@Component 사용하는 경우

  • Spring 컨테이너에 의해 관리되고 다른 Bean과 상호작용
  • 비즈니스 로직을 처리하거나 특정 책임 수행
  • 의존성 주입

Util 클래스

  • 상태를 가지지 않는 정적 메소드
  • 객체 생성 없이 바로 메서드 호출
  • 코드 재사용성 높이거나 공통된 연산

Util 클래스 PasswordEncoder 예시

  • 단순히 입력된 값을 처리하는 형태라면 static 메소드로 사용해도 무방 ```java public class PasswordEncoderUtil {

    public static String encode(String rawPassword) { return BCrypt.withDefaults().hashToString(BCrypt.MIN_COST, rawPassword.toCharArray()); }

    public static boolean matches(String rawPassword, String encodedPassword) { BCrypt.Result result = BCrypt.verifyer().verify(rawPassword.toCharArray(), encodedPassword); return result.verified; } }


### @Component PasswordEncoder 예시
- Interface 구현
```java
public interface PasswordEncoder {
    String encode(String rawPassword);
    boolean matches(String rawPassword, String encodedPassword);
}

  • BCryptPasswordEncoder 구현체 ```java import at.favre.lib.crypto.bcrypt.BCrypt; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component;

@Component @Profile(“prod”) // 프로덕션 환경에서만 활성화됨 public class BCryptPasswordEncoder implements PasswordEncoder {

@Override
public String encode(String rawPassword) {
    return BCrypt.withDefaults().hashToString(BCrypt.MIN_COST, rawPassword.toCharArray());
}

@Override
public boolean matches(String rawPassword, String encodedPassword) {
    BCrypt.Result result = BCrypt.verifyer().verify(rawPassword.toCharArray(), encodedPassword);
    return result.verified;
} }
- NoOpPasswordEncoder 구현체 (개발 환경용)
```java
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

@Component
@Profile("dev") // 개발 환경에서만 활성화됨
public class NoOpPasswordEncoder implements PasswordEncoder {

    @Override
    public String encode(String rawPassword) {
        // 암호화를 하지 않고 원래 문자열을 반환
        return rawPassword;
    }

    @Override
    public boolean matches(String rawPassword, String encodedPassword) {
        // 단순히 문자열이 같은지 비교
        return rawPassword.equals(encodedPassword);
    }
}

Service 사용 예시

  • PasswordEncoder 인터페이스에 의존하도로 설계한 서비스. 환경에 따라 적절한 구현체가 주입된다. ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;

@Service public class UserService {

private final PasswordEncoder passwordEncoder;

@Autowired
public UserService(PasswordEncoder passwordEncoder) {
    this.passwordEncoder = passwordEncoder;
}

public void registerUser(String rawPassword) {
    String encodedPassword = passwordEncoder.encode(rawPassword);
    // 사용자 등록 로직 수행 (예: 데이터베이스에 저장)
    System.out.println("Encoded password: " + encodedPassword);
} }
### 프로파일 설정 (application.properties)
- 개발과 실제 배포 환경 중 선택하여 프로파일을 활성화
- application-dev.properties

application-dev.properties=dev

- application-prod.properties

spring.profiles.active=prod ```

정리

프로파일 기반의 설정: 개발 환경에서는 NoOpPasswordEncoder가 활성화되고 실제 배포 환경에서는 BCryptPasswordEncoder가 활성화된다. @Profile 어노테이션을 통해 제어되고PasswordEncoder 인터페이스를 통해 구체적인 구현체가 서비스에 주입된다.

테스트 및 확장성: 필요에 따라 다른 환경에서 구현체를 교체하거나 새로 추가할 수 있다. 스프링 컨테이너가 의존성을 관리하므로 이를 쉽게 변경할 수 있다.