프로젝트 생성
- Language: Java
- Build system: Gradle - Groovy
프로젝트 설정추가
- build.gradle : Security 추가
- Security 기능 제한 / SpringAuthApplication
// Security
implementation 'org.springframework.boot:spring-boot-starter-security'
package com.sparta.springauth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
@SpringBootApplication(exclude = SecurityAutoConfiguration.class) // Spring Security 인증 기능 제외
public class SpringAuthApplication {
public static void main(String[] args) {
SpringApplication.run(SpringAuthApplication.class, args);
}
}
Bean을 수동으로 등록한다는 것은?
- @Component를 사용하면 @ComponentScan에 의해 자동으로 스캔되어 해당 클래스를 Bean으로 등록 해줍니다.
- 일반적으로 @Component를 사용하여 Bean을 자동으로 등록하는 것이 좋습니다.
- 프로젝트의 규모가 커질 수록 등록할 Bean들이 많아지기 때문에 자동등록을 사용하면 편리합니다.
- 비즈니스 로직과 관련된 클래스들은 그 수가 많기 때문에 @Controller, @Service와 같은 애너테이션들을 사용해서 Bean으로 등록하고 관리하면 개발 생산성에 유리합니다.
- 수동 등록을 사용해야될 때
- 기술적인 문제나 공통적인 관심사를 처리할 때 사용하는 객체들을 수동으로 등록하는 것이 좋습니다.
- 공통 로그처리와 같은 비즈니스 로직을 지원하기 위한 부가 적이고 공통적인 기능들을 기술 지원 Bean이라 부르고 수동등록 합니다.
- 비즈니스 로직 Bean 보다는 그 수가 적기 때문에 수동으로 등록하기 부담스럽지 않습니다.
- 또한 수동등록된 Bean에서 문제가 발생했을 때 해당 위치를 파악하기 쉽다는 장점이 있습니다.
- 기술적인 문제나 공통적인 관심사를 처리할 때 사용하는 객체들을 수동으로 등록하는 것이 좋습니다.
Bean을 수동으로 등록하는 방법
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
- Bean으로 등록하고자하는 객체를 반환하는 메서드를 선언하고 @Bean을 설정합니다.
- Bean을 등록하는 메서드가 속한 해당 클래스에 @Configuration을 설정합니다.
- Spring 서버가 뜰 때 Spring IoC 컨테이너에 'Bean'으로 저장됩니다.
// 1. @Bean 설정된 메서드 호출
PasswordEncoder passwordEncoder = passwordConfig.passwordEncoder();
// 2. Spring IoC 컨테이너에 빈 (passwordEncoder) 저장
// passwordEncoder -> Spring IoC 컨테이너
- 'Bean' 이름: @Bean 이 설정된 메서드명
- public PasswordEncoder passwordEncoder() {..} → passwordEncoder
Bean 등록해보기
- 비밀번호를 암호화할 때 사용하는 PasswordEncoder의 구현체 BCryptPasswordEncoder를 Bean으로 수동등록
package com.sparta.springauth.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
- 등록한 passwordEncoder ‘Bean’을 사용하여 문자열을 암호화
package com.sparta.springauth;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
@SpringBootTest
public class PasswordEncoderTest {
@Autowired
PasswordEncoder passwordEncoder;
@Test
@DisplayName("수동 등록한 passwordEncoder를 주입 받아와 문자열 암호화")
void test1() {
String password = "Robbie's password";
// 암호화
String encodePassword = passwordEncoder.encode(password);
System.out.println("encodePassword = " + encodePassword);
String inputPassword = "Robbie";
// 해시된 비밀번호와 사용자가 입력한 비밀번호를 해싱한 값을 비교
boolean matches = passwordEncoder.matches(inputPassword, encodePassword);
System.out.println("matches = " + matches); // 암호화할 때 사용된 값과 다른 문자열과 비교했기 때문에 false
}
}
같은 타입의 Bean이 2개라면?
- 같은 타입 Bean 등록
package com.sparta.springauth.food;
public interface Food {
void eat();
}
package com.sparta.springauth.food;
import org.springframework.stereotype.Component;
@Component
public class Chicken implements Food {
@Override
public void eat() {
System.out.println("치킨을 먹습니다.");
}
}
package com.sparta.springauth.food;
import org.springframework.stereotype.Component;
@Component
public class Pizza implements Food {
@Override
public void eat() {
System.out.println("피자를 먹습니다.");
}
}
- 테스트 코드 오류
@SpringBootTest
public class BeanTest {
@Autowired
Food food; // 오류 food중에 어떤건지 모름
}
- 테스트 코드 해결 방법 1 - 등록된 Bean 이름 명시하기
@SpringBootTest
public class BeanTest {
@Autowired
Food pizza;
@Autowired
Food chicken;
}
- 테스트 코드 해결 방법 2 - @Primary 사용하기
@Component
@Primary
public class Chicken implements Food {
@Override
public void eat() {
System.out.println("치킨을 먹습니다.");
}
}
@SpringBootTest
public class BeanTest {
@Autowired
Food food;
}
- 테스트 코드 해결 방법 3 - @Qualifier 사용하기
@Component
@Qualifier("pizza")
public class Pizza implements Food {
@Override
public void eat() {
System.out.println("피자를 먹습니다.");
}
}
@SpringBootTest
public class BeanTest {
@Autowired
@Qualifier("pizza")
Food food;
}
- 같은 타입의 Bean들에 Qualifier와 Primary가 동시에 적용되어 있을 때
- Qualifier의 우선순위가 더 높다
- 같은 타입의 Bean이 여러 개 있을 때는 범용적으로 사용되는 Bean 객체에는 Primary를 설정하고 지엽적으로 사용되는 Bean 객체에는 Qualifier를 사용하는 것이 좋다
'Spring' 카테고리의 다른 글
Spring 개념 정리 ) 쿠키와 세션 (0) | 2024.08.23 |
---|---|
Spring 개념 정리 ) 인증과 인가 / 쿠키와 세션, JWT (0) | 2024.08.22 |
Spring 개념 정리 ) JPA CORE (0) | 2024.08.20 |
Spring 개념 정리 ) IoC와 DI, IoC Container와 Bean (0) | 2024.08.19 |
Spring 개념 정리 ) Gradle, 서버, HTTP 란? (0) | 2024.08.14 |