Bean์ ์๋์ผ๋ก ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ
@ComponentScan์ด @Component๋ฅผ ์ค์บํด ์๋์ผ๋ก Bean์ ๋ฑ๋กํด์ค. ์ผ๋ฐ์ ์ผ๋ก 3 Layer Annotation์ธ @Controller, @Service, @Repository๋ฅผ ์ฌ์ฉํด์ ์๋์ผ๋ก Bean์ ๋ฑ๋กํด์ฃผ๋๊ฒ ์ข์
→ ํ๋ก์ ํธ ๊ท๋ชจ๊ฐ ์ปค์ง์๋ก Bean ์๋ ๋ฑ๋ก์ ์ฌ์ฉํ๋ฉด ํธ๋ฆฌํจ
ํ์ง๋ง, ๊ธฐ์ ์ ์ธ ๋ฌธ์ (๊ธฐ์ ์ง์ Bean)๋ ๊ณตํต์ ์ธ ๊ด์ฌ์ฌ๋ฅผ ์ฒ๋ฆฌํ ๋ ์ฌ์ฉํ๋ ๊ฐ์ฒด๋ค์ ์๋์ผ๋ก ๋ฑ๋กํ๋ ๊ฒ์ด ์ข์(ex: ๊ณตํต ๋ก๊ทธ ์ฒ๋ฆฌ, ๊ฐ์ ๋น์ฆ๋์ค ๋ก์ง์ ์ง์ํ๊ธฐ ์ํ ๋ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ)
ex) ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํํ๋ ๊ฐ์ฒด๋ฅผ Bean์ผ๋ก ์๋ ๋ฑ๋กํ๊ธฐ
1. Bean์ผ๋ก ๋ฑ๋กํ๊ณ ์ ํ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ๋ฉ์๋ ์ ์ธ
2. ๊ทธ ๋ฉ์๋ ์์ @Bean ์ด๋
ธํ
์ด์
์ถ๊ฐ
3. Bean์ ๋ฑ๋กํ๋ ๋ฉ์๋๊ฐ ์ํด ์๋ Class ์์ @Configuration ์ด๋
ธํ
์ด์
์ถ๊ฐํ๋ฉด
4. Spring Server๊ฐ ๋ฐ ๋ Spring IoC Container์ 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;
// Bean์ผ๋ก ๋ฑ๋กํ๊ณ ์ ํ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ๋ฉ์๋ ์ ์ธ
// ๊ทธ ๋ฉ์๋ ์์ @Bean ์ด๋
ธํ
์ด์
์ถ๊ฐ
// Bean์ ๋ฑ๋กํ๋ ๋ฉ์๋๊ฐ ์ํด ์๋ Class ์์ @Configuration ์ด๋
ธํ
์ด์
์ถ๊ฐํ๋ฉด
// Spring Server๊ฐ ๋ฐ ๋ Spring IoC Container์ Bean์ผ๋ก ์ ์ฅ๋จ
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
// BCrypt๋ ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํํด์ฃผ๋ Hash ํจ์๋ก, Password๋ฅผ Encode ํด์ค
return new BCryptPasswordEncoder();
}
}
ํ ์คํธ ์ํ
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";
// ํด์๋ ๋น๋ฐ๋ฒํธ์ ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๋น๋ฐ๋ฒํธ๋ฅผ ํด์ฑํ ๊ฐ์ ๋น๊ต
// passwordEncoder.matches(์
๋ ฅ ๋ฐ์ ๋ฌธ์์ด, ์ํธํํ ๋น๋ฐ๋ฒํธ)
boolean matches = passwordEncoder.matches(inputPassword, encodePassword);
System.out.println("matches = " + matches); // ์ํธํํ ๋ ์ฌ์ฉ๋ ๊ฐ๊ณผ ๋ค๋ฅธ ๋ฌธ์์ด๊ณผ ๋น๊ตํ๊ธฐ ๋๋ฌธ์ false
}
}

๊ฐ์ ํ์ ์ Bean์ด 2๊ฐ๋ผ๋ฉด?
Food ์ธํฐํ์ด์ค
package com.sparta.springauth.food;
public interface Food {
void eat();
}
Chicken ํด๋์ค
package com.sparta.springauth.food;
import org.springframework.stereotype.Component;
@Component
public class Chicken implements Food {
@Override
public void eat() {
System.out.println("์นํจ์ ๋จน์ต๋๋ค.");
}
}
Pizza ํด๋์ค
package com.sparta.springauth.food;
import org.springframework.stereotype.Component;
@Component
public class Pizza implements Food {
@Override
public void eat() {
System.out.println("ํผ์๋ฅผ ๋จน์ต๋๋ค.");
}
}
- ์ธํฐํ์ด์ค ํด๋์ค ์์ฑ ํ, ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ๊ตฌํ์ฒด ํด๋์ค๋ฅผ ๋ง๋ ๋ค์์ Bean์ผ๋ก ๋ฑ๋ก(@Component, @Controller, ๋ฑ๋ฑ)ํ๋ฉด ํด๋นํ๋ ์ธํฐํ์ด์ค๋ Bean์ผ๋ก ๋ฑ๋ก๋จ

- ์ฆ, ํ๋์ ์ธํฐํ์ด์ค์์ ๋ ๊ฐ์ ๊ตฌํ์ฒด๋ฅผ ๋น์ผ๋ก ๋ฑ๋กํ๋๊ฑด ํฐ ๋ฌธ์ ๋ ์์

- ์๋ ์ฃผ์ ์ ํ๋ ค๊ณ ํ ๋, Food๋ผ๋ ํ์ ์ผ๋ก Bean์ด ํ ๊ฐ์ด์์ด์ด์ ์๋ฌ ๋ฐ์ํจ
- ์ฆ, Food ํ๋์ Bean์ ์ฃผ์ ์ ํด์ผ ํ๋๋ฐ ๊ฐ์ ํ์ ์ Bean ๊ฐ์ฒด๊ฐ ํ๋ ์ด์์ด๋ผ ์ด๋ค Bean์ ๋ฑ๋กํด ์ค์ผ ํ ์ง ๋ชจ๋ฅธ๋ค๋ ์๋ฏธ
๊ฐ์ ํ์ ์ Bean์ด 2๊ฐ ์ด์์ธ ๊ฒฝ์ฐ, ์๋ ์ฃผ์ ์๋ฌ ํด๊ฒฐ ๋ฐฉ๋ฒ
1. ๋ฑ๋ก๋ Bean์ ์ด๋ฆ ๋ช ์
๊ธฐ๋ณธ์ ์ผ๋ก @Autowired๋ Bean DI๋ฅผ ์ง์ํ๊ธฐ ๋๋ฌธ์ Food๋ผ๋ ํ์ ์ผ๋ก Bean์ ์ฐพ์ → ํ์ ์ผ๋ก ์ฐพ์ ๋ Bean์ด 2๊ฐ์ธ ๊ฒ์ ํ์ธ → ๊ทธ ๋ค์ ์ด๋ฆ์ผ๋ก Bean์ ์ฐพ์(chicken, pizza)
@SpringBootTest
public class BeanTest {
@Autowired
Food pizza; // Bean ์ฃผ์
๋ฐ๊ธฐ
@Autowired
Food chicken; // Bean ์ฃผ์
๋ฐ๊ธฐ
}

2. @Primary ์ด๋ ธํ ์ด์ ์ถ๊ฐ
๊ฐ์ ํ์ ์ Bean์ด ์ฌ๋ฌ ๊ฐ ์๋๋ผ๋ ์ฐ์ ์ ์ผ๋ก @Primary๊ฐ ์ ์ฉ์ด ๋์ด์๋ Bean ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํด์ค
@Component
@Primary
public class Chicken implements Food {
@Override
public void eat() {
System.out.println("์นํจ์ ๋จน์ต๋๋ค.");
}
}
@SpringBootTest
public class BeanTest {
@Autowired
Food food; // Bean ์ฃผ์
๋ฐ๊ธฐ
@Test
@DisplayName("ํ
์คํธ")
void test1() {
food.eat();
}
}

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 ์ฃผ์
๋ฐ๊ธฐ
@Test
@DisplayName("ํ
์คํธ")
void test1() {
food.eat();
}
}

๏นก๊ฐ์ ํ์ ์ Bean๋ค์ @Qualifier๋ @Primary๊ฐ ๋์์ ๊ฑธ๋ ค ์๋ค๊ณ ํ๋ฉด, @Qualifier ์ฐ์ ์์๊ฐ ๋ ๋์! ํ์ง๋ง, Qualifier๋ ์ฃผ์ ๋ฐ๊ณ ์ ํ๋ ๊ณณ์ ๋ฐ๋์ @Qualifier๋ฅผ ๋ฐ๋์ ๋ถ์ฌ์ค์ผ ํจ
- ๋ฒ์ฉ์ ์ผ๋ก ์ฌ์ฉ๋๋ Bean ๊ฐ์ฒด์๋ @Primary๋ฅผ ์ฌ์ฉ
- ์ง์ญ์ ์ผ๋ก ์ฌ์ฉ๋๋ Bean ๊ฐ์ฒด์๋ @Qualifier๋ฅผ ์ฌ์ฉ