블로그 이름 뭐하지
[Spring] Bean 본문
이전에 작성한 Bean 관련 링크(하단 참고)
[Spring] IOC(제어의 역전)와 DI(의존성 주입)
제어의 역전(Inversion of Control) 개발자가 직접 제어흐름을 제어하지 않고, 외부의 프레임워크나 라이브러리가 제어 흐름을 대신하게 되는 것이다.// 클래스 A에서 new 키워드로 클래스 B의 객체 생
blognameless.tistory.com
Bean 수동 등록
//예시로 드는 passwordEncoder의 경우 아래와 같은 설정이 필요하다
// 1) build.gradle 의존성 설정
implementation 'org.springframework.boot:spring-boot-starter-security'
// 또는
implementation 'org.springframework.security:spring-security-core'
// 권한이나 인증관리가 필요할 때는 전자를, 단순히 비밀번호 인코딩만 필요할 때는 후자를 사용
// 2) 전자를 사용할 경우
// SpringBootApplication에 해당 코드 추가
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);
}
}
@Component를 사용하면 @ComponentScan에 의해 해당 클래스가 Bean으로 자동등록된다.
비즈니스 로직과 관련된 클래스들은 @Controller, @Service, @Repository 같은 애너테이션으로 자동등록한다.
이 외 공통 로그 처리와 같은 비즈니스 로직을 지원하는 부가적, 공통적인 기능을 처리할 때, Bean을 수동등록한다.
Bean 수동 등록 방법
1) Bean으로 등록하고자 하는 객체를 반환하는 메서드 선언 후 @Bean을 설정한다.
2) Bean을 등록하는 메서드가 속한 클래스에 @Configuration을 설정한다.
3) Spring 서버가 뜰 때, Spring IoC 컨테이너에 해당 객체가 bean으로 저장된다.
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
// 1. @Bean 설정된 메서드 호출
PasswordEncoder passwordEncoder = passwordConfig.passwordEncoder();
// 2. Spring IoC 컨테이너에 빈 (passwordEncoder) 저장
// passwordEncoder -> Spring IoC 컨테이너
// Bean 실행
@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 등록
문제 발생
// Food Interface
public interface Food {
void eat();
}
// Food 인터페이스를 구현한 Chicken 클래스
@Component // Bean 등록
public class Chicken implements Food {
@Override
public void eat() {
System.out.println("치킨을 먹습니다.");
}
}
// Food 인터페이스를 구현한 Pizza 클래스
@Component
public class Pizza implements Food {
@Override
public void eat() {
System.out.println("피자를 먹습니다.");
}
}
Food 인터페이스가 있고 그를 구현한 각각의 다른 클래스가 Bean으로 등록되어 있을 때,
Food를 주입하려고 하면 오류가 난다.
@SpringBootTest
public class BeanTest {
@Autowired
Food food;
// Food 타입의 Bean 객체가 두 개 이상 존재해 주입을 할 수 없다는 오류가 난다.
}
해결방안
1) 등록된 Bean 이름 명시
아래와 같이 등록된 Bean의 이름을 정확히 명시하면 해결된다.
@Autowired는 기본적으로 Bean Type으로 의존성을 주입하며,
연결이 되지 않을 경우 Bean Name으로 찾기 때문이다.
@SpringBootTest
public class BeanTest {
@Autowired
Food pizza;
@Autowired
Food chicken;
}
2) @Primary 사용
아래와 같이 주입하고 싶은 클래스에 @Primary 키를 달면 같은 타입의 Bean 객체가 여러 개 있더라도
우선적으로 @Primary가 설정된 객체를 주입한다.
@Component
@Primary // Chicken 클래스에 Primary 어노테이션 적용
public class Chicken implements Food {
@Override
public void eat() {
System.out.println("치킨을 먹습니다.");
}
}
@SpringBootTest
public class BeanTest {
@Autowired
Food food; // Chicken 객체를 주입한다
}
3) @Qualifier 사용
객체가 여러개일 때, 식별이 모호할 경우 사용하는 어노테이션이다.
@Component
@Qualifier("pizza") // Pizza 클래스에 Qualifier 어노테이션 적용
public class Pizza implements Food {
@Override
public void eat() {
System.out.println("피자를 먹습니다.");
}
}
@SpringBootTest
public class BeanTest {
@Autowired
@Qualifier("pizza")// 주입하고자 하는 필드에도 @Qualifier 어노테이션 적용
Food food;
}
'Spring' 카테고리의 다른 글
[Spring] 필터(Filter) (0) | 2024.11.14 |
---|---|
[Spring] 쿠키와 세션, JWT (0) | 2024.11.13 |
[Spring] JPA (0) | 2024.11.13 |
[Spring] IOC(제어의 역전)와 DI(의존성 주입) (0) | 2024.10.10 |
[Spring] 3 Layer Architecture (0) | 2024.10.10 |