JiwonDev

#8 ์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ ์˜์กด๊ด€๊ณ„ ์ž๋™์ฃผ์ž…

by JiwonDev

ํ•ด๋‹น ๊ธ€์€ ๊น€์˜ํ•œ๋‹˜์˜ ์ธํ”„๋Ÿฐ ๊ฐ•์˜๋ฅผ ๊ณต๋ถ€ํ•˜๊ณ  ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

 

# ์ปดํฌ๋„ŒํŠธ ์Šค์บ”?

์•ž์—์„œ ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•  ๋•Œ Java ์–ด๋…ธํ…Œ์ด์…˜ ์ฝ”๋“œ (@Bean)์ด๋‚˜ XML <bean>๋“ฑ์„ ํ†ตํ•ด ์„ค์ •์ •๋ณด์— ์ง์ ‘ ๋“ฑ๋กํ•œ ์Šคํ”„๋ง ๋นˆ์„ ์ง€์ •ํ•ด์ฃผ์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ์ž‘์—…์€ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์ง€๋ฉด ์ผ์ผ์ด ํ•˜๋‚˜ํ•˜๋‚˜ ์ ์–ด์ฃผ๊ธฐ๋„ ๋ฒˆ๊ฑฐ๋Ÿฝ๊ณ , ์ˆ˜์ •ํ•  ๋•Œ ๋ˆ„๋ฝ๋˜๋Š” ๊ฒฝ์šฐ๋„ ์ž์ฃผ ๋ฐœ์ƒํ•œ๋‹ค.

 

๊ทธ๋ž˜์„œ ์Šคํ”„๋ง์€ ์„ค์ • ์ •๋ณด๊ฐ€ ์—†์–ด๋„ ์ž๋™์œผ๋กœ ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•ด์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์ด๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ๋˜ ๋“œ๋””์–ด ๋งจ๋‚  ๋ณด๋˜ @Autowired ๋ผ๋Š” ์˜์กด๊ด€๊ณ„๋ฅผ ์ž๋™์œผ๋กœ ์ฃผ์ž…ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ๋„ ์ œ๊ณตํ•œ๋‹ค.

 

# ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ์‚ฌ์šฉํ•ด๋ณด์ž

๊ฐ„๋‹จํ•˜๋‹ค. @ComponentScan ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฐธ๊ณ ๋กœ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ํ•˜๊ฒŒ๋˜๋ฉด @Configuration์ด ๋ถ™์€ ์„ค์ • ์ •๋ณด๋„ ์ž๋™์œผ๋กœ ๋“ฑ๋ก๋œ๋‹ค. @Configuration ๋‚ด๋ถ€์— @Componet๊ฐ€ ์„ ์–ธ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ž˜์„œ ์˜ˆ์ œ์—์„œ ์ ์€ ์„ค์ •์ •๋ณด๋ฅผ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์— ์ œ์™ธํ•˜๊ธฐ ์œ„ํ•ด excludeFilter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•„๋ž˜์™€ ๊ฐ™์ด ์ ์–ด์ฃผ์—ˆ๋‹ค. (* ๋ณดํ†ต์€ ๊ตณ์ด ์„ค์ •์ •๋ณด๋ฅผ excludeFilter๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ๊ทธ๋ƒฅ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ์‚ฌ์šฉํ•œ๋‹ค.)

@Configuration
@ComponentScan(excludeFilters = @Filter(type = FilterType.ANNOTATION,
        classes = Configuration.class))
public class AutoAppConfig {
    // ์ƒ๋žตํ•œ๊ฒŒ ์•„๋‹ˆ๋‹ค. ๋“ฑ๋กํ•œ ํด๋ž˜์Šค๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋‹ค.
}

์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ๋“ฑ๋กํ–ˆ๋‹ค๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ๊ฐ์˜ ํด๋ž˜์Šค์— @Component ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ์ž.

@Component
public class MemoryMemberRepository implements MemberRepository {
    public static Map<Long, Member> store = new HashMap<>();

    @Override
    public void save(Member member) {
        store.put(member.getId(), member);
    }

    @Override
    public Member findById(Long memberId) {
        return store.get(memberId);
    }
}
@Component
public class RateDiscountPolicy implements DiscountPolicy {
    private int discountPercent = 10;

    @Override
    public int discount(Member member, int price) {
        if (member.getGrade() == Grade.VIP) {
            return price * discountPercent / 100;
        }
        return 0;
    }
}

 

์œ„์—๋„ ์–ธ๊ธ‰ํ–ˆ๋‹ค์‹ถ์ด @Autowired๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์˜์กด๊ด€๊ณ„๋ฅผ ์ž๋™์œผ๋กœ ์ฃผ์ž… ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰ ์•ž์—์„œ AppConfig์—์„œ ์ธํ„ฐํŽ˜์ด์Šค์— ๊ตฌํ˜„์ฒด๋ฅผ ๋„ฃ์–ด์ฃผ๋Š” ๊ณผ์ •์„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์Šค์บ”ํ•˜์—ฌ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌ ํ•ด์ค€๋‹ค. (๋‹ค๋ฅธ ๊ธฐ๋Šฅ๋„ ์žˆ๋Š”๋ฐ, ์ด๋Š” ๋‚˜์ค‘์— ์ถ”๊ฐ€๋กœ ์„ค๋ช…ํ•˜๊ฒ ๋‹ค.)

@Component
public class MemberServiceImpl implements MemberService {
    private final MemberRepository memberRepository;

    @Autowired
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
    
    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }

}

 

์ปดํฌ๋„ŒํŠธ ์Šค์บ”์ด ์ •๋ง ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์•Œ์•„๋ณด์ž. 

public class AutoAppConfigTest {
    @Test
    void basicScan() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
        
        MemberService memberService = ac.getBean(MemberService.class);
        assertThat(memberService).isInstanceOf(MemberService.class);
    }
}

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ์ฝ˜์†”์„ ์‚ดํŽด๋ณด๋ฉด, BeanDefinitionScanner๊ฐ€ ๋™์ž‘ํ•ด์„œ ์ž๋™์œผ๋กœ ๊ตฌํ˜„์ฒด๊ฐ€ ๋“ฑ๋ก๋˜์—ˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 


# ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์˜ ๋™์ž‘๊ณผ์ •

@ComponentScan์„ ์„ค์ •ํ•˜๋ฉด, @Component๊ฐ€ ๋ถ™์€ ๋ชจ๋“  ํด๋ž˜์Šค๋ฅผ ์ž๋™์œผ๋กœ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค. ์ด์ „์ฒ˜๋Ÿผ AppConfig์—์„œ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ๋ฉ”์„œ๋“œ์— ํ•˜๋‚˜ํ•˜๋‚˜ @Bean์„ ๋ถ™์—ฌ์ฃผ์ง€ ์•Š์•„๋„ ๋œ๋‹ค. (@Configuration ์ฒ˜๋Ÿผ ํ•ด๋‹น ํƒœ๊ทธ ๋‚ด๋ถ€์— @Component๊ฐ€ ์„ ์–ธ๋˜์–ด ์žˆ๋Š” ํด๋ž˜์Šค๋„ ์ƒ์„ฑ ๋Œ€์ƒ์ด ๋จ์„ ์œ ์˜ํ•˜์ž.)

๋ฌผ๋ก  ๋“ฑ๋ก๋  ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์€ ์ง์ ‘ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ์ƒ์„ฑ์ž์— @Autowired๋ฅผ ์ง€์ •ํ•˜๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์ด AppConfig์˜ @Bean ๋ฉ”์„œ๋“œ์—์„œ ์˜์กด๊ด€๊ณ„๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ์ฃผ์ž…ํ•ด์ฃผ๋˜ ๊ฒƒ์„ ๋Œ€์‹  ํ•ด์ค€๋‹ค.

//* @ComponentScan ์œผ๋กœ ๋นˆ ๋“ฑ๋ก, @Autowired๋กœ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•œ ์ฝ”๋“œ *
@Configuration
@ComponentScan(excludeFilters = @Filter(type = FilterType.ANNOTATION,
        classes = Configuration.class))
public class AutoAppConfig {
    // ์ƒ๋žตํ•œ๊ฒŒ ์•„๋‹ˆ๋‹ค. ๋“ฑ๋กํ•ด์•ผํ•˜๋Š” ํด๋ž˜์Šค๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋‹ค.
}
//* ๊ธฐ์กด์˜ ์ฝ”๋“œ *
@Configuration // ๊ตฌํ˜„์ฒด๋ฅผ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋กœ ์œ ์ง€์‹œ์ผœ์ฃผ๋Š” ํƒœ๊ทธ.
public class AppConfig {
    @Bean // memoryRepository ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
    
    @Bean // memberService์— ์˜์กด๊ด€๊ณ„ ์ฃผ์ž….
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }
 
    @Bean // OrderService์— ์˜์กด๊ด€๊ณ„ ์ฃผ์ž….
    public OrderService orderService() {
        return new OrderServiceImpl(
                memberRepository(),
                discountPolicy());
    }
     ... ์ƒ๋žต ...
}

@Autowired์˜ ์›๋ฆฌ๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ [๋“ฑ๋ก๋œ ์Šคํ”„๋ง ๋นˆ]์ค‘์—์„œ ํƒ€์ž…์ด ๊ฐ™์€ ๋นˆ์„ ์ฐพ์•„ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค. ๊ธฐ๋ณธ ๋™์ž‘์€ ๊ฐ™์€ ํƒ€์ž…์˜ ๋นˆ์„ ์กฐํšŒํ•˜๋Š” getBean(MemberRepositoryt.class) ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ memoryMemberRepository๋ฅผ ์ฐพ์•„ ๋“ฑ๋กํ•ด์ฃผ๋Š” ๋ฐฉ์‹์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. 

์ƒ์„ฑ์ž์— ํŒŒ๋ผ๋ฉ”ํƒ€๊ฐ€ ๋งŽ์•„๋„, ๋‹ค ์ฐพ์•„์„œ ์ฃผ์ž…ํ•ด์ค€๋‹ค.

 

 


# ์ปดํฌ๋„ŒํŠธ ํƒ์ƒ‰ ์œ„์น˜์ง€์ •

@ComponentScan๋Š” ํ”„๋กœ์ ํŠธ ๋‚ด์˜ ๋ชจ๋“  ์ž๋ฐ” ํด๋ž˜์Šค, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋’ค์ ธ์„œ @Component๋ฅผ ์ฐพ์•„ ์Šค์บ”ํ•œ๋‹ค. ์ด ๊ณผ์ •์€ ์‹œ๊ฐ„์ด ์˜ค๋ž˜๊ฑธ๋ฆฌ๊ฒŒ ๋˜๋Š”๋ฐ, basekPackages ์˜ต์…˜์„ ์ด์šฉํ•˜์—ฌ ํƒ์ƒ‰ํ•  ์œ„์น˜๋ฅผ ์ง€์ •ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

  • basePackages : ํƒ์ƒ‰ํ•  ํŒจํ‚ค์ง€์˜ ์‹œ์ž‘ ์œ„์น˜๋ฅผ ์ง€์ •ํ•œ๋‹ค. ์ด ํŒจํ‚ค์ง€๋ฅผ ํฌํ•จํ•œ ํ•˜์œ„ ํŒจํ‚ค์ง€๋ฅผ ๋ชจ๋‘ ํƒ์ƒ‰ํ•œ๋‹ค.
  • basePackages = {"hello.core", "hello.service"} ์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์ง€์ •ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค. ๋™์ž‘์€ ๋™์ผํ•˜๋‹ค.
  • basePackageClasses : ์ง€์ •ํ•œ ํด๋ž˜์Šค๊ฐ€ ์†ํ•œ ํŒจํ‚ค์ง€๋ฅผ ํƒ์ƒ‰ ์‹œ์ž‘์œ„์น˜๋กœ ์ง€์ •ํ•œ๋‹ค.
    (=> ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด @ComponentScan์ด ๋ถ™์€ ์„ค์ • ํด๋ž˜์Šค๊ฐ€ ์‹œ์ž‘์œ„์น˜๊ฐ€ ๋œ๋‹ค.)

์Šคํ”„๋ง์—์„œ ๊ถŒ์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์€, ์„ค์ • ํด๋ž˜์Šค(AppConfig)๋ฅผ ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ ๋ฃจํŠธ์— ๋‘๊ณ  ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ( ์Šคํ”„๋ง ๋ถ€ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด @SpringBootApplication์„ ์•ฑ ์‹œ์ž‘์— ๋‘๋Š”๊ฒŒ ์ผ๋ฐ˜์ ์ธ๋ฐ, ํ•ด๋‹น ํƒœ๊ทธ ์•ˆ์— @ComponentScan์ด ํฌํ•จ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๊ธฐ๋„ ํ•˜๋‹ค.)

@ComponentScan(
     basePackages = "hello.core"
)

์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ์•ฑ ์‹œ์ž‘์ ์—๋Š” @SpringBootApplication์„ ๋ถ™์ด๋Š”๊ฒŒ ์ผ๋ฐ˜์ ์ด๋‹ค.


# ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๊ธฐ๋ณธ๋Œ€์ƒ

์ฐธ๊ณ ๋กœ @ComponentScan์€ @Component ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์•„๋ž˜์˜ ํƒœ๊ทธ๋“ค๋„ ์ž๋™ ์Šค์บ”๋Œ€์ƒ์— ์ถ”๊ฐ€ํ•œ๋‹ค. (์ด๋Š” ํ•ด๋‹น ํƒœ๊ทธ ์•ˆ์— @Component ํƒœ๊ทธ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.)

  • @Component : ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์—์„œ ์‚ฌ์šฉ
  • @Configuration : ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด์—์„œ ์‚ฌ์šฉ
  • @Controller : ์Šคํ”„๋ง MVC ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์‚ฌ์šฉ + ์Šคํ”„๋ง MVC ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์ธ์‹ํ•จ.
  • @Repository : ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต์—์„œ ์‚ฌ์šฉ + DB์—์„œ ํ„ฐ์ง„ ์˜ˆ์™ธ๋ฅผ ์Šคํ”„๋ง ์˜ˆ์™ธ๋กœ ์ถ”์ƒํ™”ํ•ด์„œ ๋ณ€ํ™˜ํ•ด์คŒ.
  • @Service : ์Šคํ”„๋ง ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ์‚ฌ์šฉ + ํŠน๋ณ„ํ•œ ์ฒ˜๋ฆฌ๋Š” ์—†์Œ. ๊ทธ๋ƒฅ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ž„์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•จ.

* ํ•œ๋ฒˆ ์–ธ๊ธ‰ํ•˜๊ณ  ๋„˜์–ด๊ฐ€์ž๋ฉด, ์–ด๋…ธํ…Œ์ด์…˜์€ 'Java'์˜ ๊ธฐ๋Šฅ์ด์ง€๋งŒ ์ด๋ฅผ ์ƒ์†ํ•˜๋“ฏ์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฑด '์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ'์—์„œ ์ง€์›ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ์ฆ‰ ์ปค์Šคํ…€ ์–ด๋…ธํ…Œ์ด์…˜ ํƒœ๊ทธ๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๊ณ , ์Šคํ”„๋ง์˜ ์˜ต์…˜ (userDefaultFilters)์„ ๋ฐ”๊ฟ” ๊ธฐ๋ณธ ์Šค์บ”๋Œ€์ƒ์„ ๋ชจ๋‘ ์ œ์™ธํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 


# ์Šค์บ”๋Œ€์ƒ ํ•„ํ„ฐ

์•ž์—์„œ๋„ ์–ธ๊ธ‰ํ–ˆ์ง€๋งŒ, @ComponentScan์— ์•„๋ž˜ ์˜ต์…˜์„ ํ†ตํ•ด ์Šค์บ”๋Œ€์ƒ์„ ์ œ์™ธ/์ถ”๊ฐ€์ง€์ • ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค. ํ•„ํ„ฐ์˜ ์ •ํ™•ํ•œ ์‚ฌ์šฉ๋ฐฉ๋ฒ•์€ ์Šคํ”„๋ง ์–ด๋…ธํ…Œ์ด์…˜์„ ์•Œ์•„์•ผ ํ•˜๋ฏ€๋กœ, ์ผ๋‹จ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š”๊ฑฐ๋งŒ ์•Œ๊ณ  ๋„˜์–ด๊ฐ€์ž.

  • includeFilters : ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ์„ ์ถ”๊ฐ€๋กœ ์ง€์ •ํ•œ๋‹ค.
  • excludeFilters : ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์—์„œ ์ œ์™ธํ•  ๋Œ€์ƒ์„ ์ง€์ •ํ•œ๋‹ค.
@Configuration
@ComponentScan(
 includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
 excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
) 
class ComponentFilterAppConfig {}

@Filter์˜ type ๊ธฐ๋ณธ๊ฐ’์€ ANNOTATION์œผ๋กœ ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์„ ์ธ์‹ํ•ด์„œ ๋™์ž‘ํ•˜๋„๋ก ๋˜์–ด์žˆ๋‹ค. ์ž˜ ์‚ฌ์šฉํ•  ์ผ์€ ์—†์ง€๋งŒ  ํŠน์ • ํด๋ž˜์Šค๋‚˜ ์ •๊ทœํ‘œํ˜„์‹์„ ํ•„ํ„ฐ์กฐ๊ฑด์œผ๋กœ ๋„ฃ์–ด์ค„ ์ˆ˜๋„ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด BeanA๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ์ œ์™ธํ•˜๊ณ ์‹ถ์œผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค. @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = BeanA.class)

FilterType์œผ๋กœ ์ œ๊ณต๋˜๋Š” 5๊ฐ€์ง€.

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
	// ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์— ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€ ์–ด๋…ธํ…Œ์ด์…˜ ์ •์˜
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
	// ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์— ์ œ์™ธํ•˜๊ณ  ์‹ถ์€ ์–ด๋…ธํ…Œ์ด์…˜ ์ •์˜
}

@MyIncludeComponent
public class BeanA {
	// ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์— ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€ ํด๋ž˜์Šค
}

@MyExcludeComponent
public class BeanB {
	// ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์— ์ œ์™ธํ•˜๊ณ  ์‹ถ์€ ํด๋ž˜์Šค
}

์•„๋ž˜์™€ ๊ฐ™์€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ œ๋Œ€๋กœ ๋“ฑ๋ก/์ œ์™ธ ๋˜์—ˆ๋Š”์ง€๋„ ํ™•์ธํ•ด๋ณด์ž.

public class ComponentFilerAppConfigTest {
    @Test
    void filterScan() {
        ApplicationContext ac = new
                AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);
        BeanA beanA = ac.getBean("beanA", BeanA.class);
        assertThat(beanA).isNotNull();
        Assertions.assertThrows(
                NoSuchBeanDefinitionException.class,
                () -> ac.getBean("beanB", BeanB.class));
    }
    
    // ํ…Œ์ŠคํŠธ์šฉ AppConfig ์ด๋ฆ„ -> ComponentFilterAppConfig
    @Configuration
    @ComponentScan(
            includeFilters = @Filter(type = FilterType.ANNOTATION, classes =
                    MyIncludeComponent.class),
            excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
                    MyExcludeComponent.class)
    )
    static class ComponentFilterAppConfig {}
}

 


# ์ปดํฌ๋„ŒํŠธ ์ค‘๋ณต ๋“ฑ๋ก๊ณผ ์ถฉ๋Œ

๋นˆ ์ด๋ฆ„์„ ๊ฐ™๊ฒŒ ๋“ฑ๋กํ•˜๊ฒŒ๋˜๋ฉด ๋ฎ์–ด์”Œ์›Œ์ง€๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์•ž์—์„œ ๋ฐฐ์› ๋‹ค. ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์—์„œ ๊ฐ™์€ ๋นˆ ์ด๋ฆ„์„ ๋“ฑ๋กํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ์•„๋ž˜ ๋‘ ๊ฐ€์ง€ ์ƒํ™ฉ์„ ์ƒ๊ฐํ•ด๋ณด์ž.

@์ž๋™ ๋นˆ ๋“ฑ๋ก vs ์ž๋™ ๋นˆ ๋“ฑ๋ก

์ด๋Š” ๊ฐ„๋‹จํ•˜๋‹ค. ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์— ์˜ํ•ด ๋“ฑ๋ก๋˜๋‹ค๊ฐ€ ์ด๋ฆ„์ด ๊ฐ™์€ ๋นˆ์„ ๋ฐœ๊ฒฌํ•œ ๊ฒฝ์šฐ ์Šคํ”„๋ง์€ ์˜ˆ์™ธ(ConflictingBeanDefinitionException)๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. 

 

 

@์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก vs ์ž๋™ ๋นˆ ๋“ฑ๋ก

๊ทธ๋ ‡๋‹ค๋ฉด ๋‚ด๊ฐ€ ์ง์ ‘ํ•œ ๋นˆ๊ณผ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ๋นˆ ์ด๋ฆ„์ด ๊ฒน์นœ๋‹ค๋ฉด? ์ด ๊ฒฝ์šฐ ์ˆ˜๋™์œผ๋กœ ๋“ฑ๋กํ•œ ๋นˆ์ด ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•œ ๋นˆ์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•ด๋ฒ„๋ฆฐ๋‹ค.

// ์ž๋™, ์ปดํฌ๋„ŒํŠธ ์Šค์บ”
@Component
public class MemoryMemberRepository implements MemberRepository {}
// ์ˆ˜๋™์œผ๋กœ @Bean ๋“ฑ๋ก ๋ฐ ์˜์กด๊ด€๊ณ„ ์ƒ์„ฑ
@Configuration
@ComponentScan(
        excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
                Configuration.class)
)
public class AutoAppConfig {
    @Bean(name = "memoryMemberRepository")
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
}

์‹ค์ œ ์Šคํ”„๋ง ์ฝ˜์†”์ฐฝ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์˜ค๋ฒ„๋ผ์ด๋”ฉ ๋˜์—ˆ์Œ์„ ๋ฉ”์‹œ์ง€๋กœ ์•Œ๋ ค์ค€๋‹ค. ์˜๋„์ ์œผ๋กœ ์ด๋ ‡๊ฒŒ ํ–ˆ๋‹ค๋ฉด ๋‹คํ–‰์ด์ง€๋งŒ, ๋ณดํ†ต์˜ ๊ฒฝ์šฐ ์„ค์ •์ด ๊ผฌ์—ฌ์„œ ๋ฎ์–ด์”Œ์›Œ์ง€๊ฒŒ ๋˜๋Š”๋ฐ ์ด๋Š” ๋ฒ„๊ทธ๋ผ๊ณ  ํ•˜๊ธฐ์— ์• ๋งคํ•œ ์ƒํ™ฉ์ด๋ผ ์ •๋ง ์žก๊ธฐ ์–ด๋ ค์šด ์žฅ์• ๋ฅผ ๋งŒ๋“ค์–ด ๋‚ผ ์ˆ˜ ์žˆ๋‹ค. (๊ทธ๋ž˜์„œ ์ตœ๊ทผ ์Šคํ”„๋ง ๋ถ€ํŠธ CoreApplication์—์„œ๋Š” ์ˆ˜๋™ vs ์ž๋™ ์ถฉ๋Œ์ด๋‚˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋‚˜๋„๋ก ๊ธฐ๋ณธ๊ฐ’์„ ๋ฐ”๊พธ์—ˆ๋‹ค.)

Overriding bean definition for bean 'memoryMemberRepository' with a different 
definition: replacing

 


# ์˜์กด๊ด€๊ณ„ ์ž๋™์ฃผ์ž… (@Autowired)

์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ด 4๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

  • ์ƒ์„ฑ์ž ์ฃผ์ž…
  • ์ˆ˜์ •์ž ์ฃผ์ž…(์ƒ์„ฑ์ž ๋Œ€์‹  setter์‚ฌ์šฉ)
  • ํ•„๋“œ ์ฃผ์ž…
  • ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ ์ฃผ์ž…

 

@ ์ƒ์„ฑ์ž ์ฃผ์ž…

ํŠน๋ณ„ํ•œ ์ด์œ ๊ฐ€ ์—†๋‹ค๋ฉด, ์ƒ์„ฑ์ž๋กœ ์ฃผ์ž…ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

์•ž์—์„œ ๊ณ„์† ์‚ฌ์šฉํ–ˆ๋˜ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์€์ ์ด ํ˜ธ์ถœ ์‹œ์ ์— ๋”ฑ 1๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜์–ด ๋ถˆ๋ณ€ํ•œ ๊ฐ์ฒด ์˜์กด๊ด€๊ณ„๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค. ๋˜ ํ•„๋“œ์— final ํ‚ค์›Œ๋“œ๋ฅผ ์ ์–ด ํ˜น์‹œ๋‚˜ ์ดˆ๊ธฐํ™”(์„ค์ •)๋˜์ง€ ์•Š๋Š” ์˜ค๋ฅ˜๋ฅผ ์ปดํŒŒ์ผ ์‹œ์ ์— ์žก์„ ์ˆ˜ ์žˆ๋‹ค.

* ์ƒ์„ฑ์ž๊ฐ€ ๋”ฑ 1๊ฐœ๋งŒ ์žˆ๋‹ค๋ฉด, @Autowired๋ฅผ ์ƒ๋žตํ•ด๋„ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•œ๋‹ค. (๋ฌผ๋ก  ์Šคํ”„๋ง ๋นˆ์—๋งŒ ํ•ด๋‹น๋˜๋Š” ๋‚ด์šฉ์ด๋‹ค.)

* ๋งŒ์•ฝ ์ž๋™์œผ๋กœ ์ฃผ์ž…ํ•  ์Šคํ”„๋ง ๋นˆ์ด ๋“ฑ๋ก๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค -> @Autowired(required=true) ์˜ต์…˜

@Component
public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    // ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด์„œ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค.
    // Autowired ํ‚ค์›Œ๋“œ๋Š” ํ˜„์žฌ ๋“ฑ๋ก๋œ ๋นˆ๋“ค์˜ ํƒ€์ž…์„ ๋น„๊ตํ•ด์„œ, ํ•„์š”ํ•œ ๊ตฌํ˜„์ฒด๋ฅผ ์—ฐ๊ฒฐ์‹œํ‚จ๋‹ค.
    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy
            discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}

 


@ ์ˆ˜์ •์ž ์ฃผ์ž…(Setter)

๊ตฌํ˜„์ฒด๊ฐ€ [์„ ํƒ, ๋ณ€๊ฒฝ] ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ƒ์„ฑ์ž ๋Œ€์‹  ์ˆ˜์ •์ž(Setter)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฃผ์ž…ํ•œ๋‹ค. ๋‹ค๋งŒ ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ๊ตฌํ˜„์ฒด์˜ ๋ถˆ๋ณ€์„ฑ์„ ์ง€ํ‚ค๊ธฐ ์œ„ํ•ด ์ƒ์„ฑ์ž๋กœ ์ฃผ์ž…ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค. 

@Component
public class OrderServiceImpl implements OrderService {
    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;

    @Autowired
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Autowired
    public void setDiscountPolicy(DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
}

 


@ ํ•„๋“œ ์ฃผ์ž…( @Autowired Object a; )

์ด๋ฆ„ ๊ทธ๋Œ€๋กœ ํ•„๋“œ์— ๋ฐ”๋กœ ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•์ธ๋ฐ, ์‹ค์ œ ์•ฑ์—์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค. ์ฝ”๋“œ๋Š” ์งง์•„์ง€์ง€๋งŒ, ์™ธ๋ถ€์—์„œ ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅํ•ด์„œ ๋‚˜์ค‘์— ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ํ•„๋“œ ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ์‹ค์ œ ์ฝ”๋“œ์™€ ์ƒ๊ด€์—†๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๊ฐ„๋‹จํžˆ ์ž‘์„ฑํ•  ๋•Œ, ํ˜น์€ ์Šคํ”„๋ง ์„ค์ •์„ ๋ชฉ์ ์œผ๋กœ ํ•˜๋Š” @Configuration ๊ฐ™์€ ํŠน๋ณ„ํ•œ ์šฉ๋„๋กœ๋งŒ ์‚ฌ์šฉ๋œ๋‹ค.

@Component
public class OrderServiceImpl implements OrderService {
    @Autowired
    private MemberRepository memberRepository;
    
    @Autowired private DiscountPolicy discountPolicy;
}
// ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค. ๋ง ๊ทธ๋Œ€๋กœ ํ…Œ์ŠคํŠธ์šฉ ์ฝ”๋“œ๋‹ˆ๊นŒ
@SpringBootTest
class CoreApplicationTests {
    @Autowired OrderService orderService;
    
    @Test
    void contextLoads() {
        ...
    }
}

 


@ ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ ์ฃผ์ž…

์ƒ์„ฑ์ž, setter, ํ•„๋“œ ์ด์™ธ์—๋„ ์•„๋ฌด ๋ฉ”์„œ๋“œ์—๋„ Autowried๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ž๋™์œผ๋กœ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ธดํ•˜๋‹ค. ํ•˜์ง€๋งŒ ๋ณดํ†ต ์‚ฌ์šฉํ•  ์ผ์ด ์—†๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

@Autowired
public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy){
        this.memberRepository=memberRepository;
        this.discountPolicy=discountPolicy;
}

 

* ํ•œ๋ฒˆ ๋” ๋งํ•˜์ง€๋งŒ, ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด๋ผํ•จ์€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” @Bean๋“ค์˜ ์˜์กด๊ด€๊ณ„๋ฅผ ๋งํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์Šคํ”„๋ง ๋นˆ ๊ฐ์ฒด๋กœ ๋“ฑ๋ก๋˜์ง€ ์•Š์€ ์ž๋ฐ” ํด๋ž˜์Šค(Member)์— @Autowired ์ฝ”๋“œ๋ฅผ ์ ์–ด๋ด์•ผ ์ž๋™์œผ๋กœ ์ฃผ์ž…๋˜์ง€ ์•Š๋Š”๋‹ค.

 


# ์˜ต์…˜์ฒ˜๋ฆฌ, ์Šคํ”„๋ง ๋นˆ์ด ์—†์–ด๋„ ๋™์ž‘ํ•ด์•ผ ํ•  ๋•Œ

์ž๋™์œผ๋กœ ์ฃผ์ž…ํ•  ์Šคํ”„๋ง ๋นˆ์ด ๋“ฑ๋ก๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค -> @Autowired(required=true) ์˜ต์…˜

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์ž๋™ ์ฃผ์ž…ํ•  ๋นˆ์ด ์—†์„ ๋•Œ, ์˜ต์…˜์œผ๋กœ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ์ฐธ๊ณ ๋กœ @Nullable๊ณผ Optional์€ Autowired์„ ์‚ฌ์šฉํ•  ๋•Œ ๋ฟ ์•„๋‹ˆ๋ผ ํŠน์ • ํ•„๋“œ์—๋งŒ ๋”ฐ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

  • @Autowired(required=false) : ์ž๋™ ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์œผ๋ฉด ํ•ด๋‹น ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์ด ์•ˆ๋˜๋„๋ก ๋ง‰์Œ.
  • org.springframework.lang.@Nullable : ์ž๋™ ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์œผ๋ฉด null์ด ์ž…๋ ฅ๋œ๋‹ค.
  • Optional<> : ์ž๋™ ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์œผ๋ฉด Optional.empty ๊ฐ€ ์ž…๋ ฅ๋œ๋‹ค
// Member๋ผ๋Š” ์Šคํ”„๋ง ๋นˆ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์—†๋‹ค = ์ž๋™ ์˜์กด์ฃผ์ž…์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
//ํ˜ธ์ถœ ์•ˆ๋จ, ์‹คํ–‰์กฐ์ฐจ ๋˜์ง€ ์•Š๊ณ  ๋ฌด์‹œ๋จ (Member๋Š” ์Šคํ”„๋ง๋นˆ์ด ์•„๋‹Œ ๊ทธ๋ƒฅ ์ž๋ฐ”๊ฐ์ฒด์ด๋ฏ€๋กœ)
@Autowired(required = false)
public void setNoBean1(Member member){
        System.out.println("setNoBean1 = "+member);
}
        
//null ํ˜ธ์ถœ
@Autowired
public void setNoBean2(@Nullable Member member){
        System.out.println("setNoBean2 = "+member);
}
        
//Optional.empty ํ˜ธ์ถœ
@Autowired(required = false)
public void setNoBean3(Optional<Member> member){
        System.out.println("setNoBean3 = "+member);
}
// setNoBean1()์€ ํ˜ธ์ถœ์ž์ฒด๊ฐ€ ์•ˆ๋จ.
setNoBean2 = null
setNoBean3 = Optional.empty

 


# final ํ‚ค์›Œ๋“œ์˜ ์‚ฌ์šฉ

์ƒ์„ฑ์ž ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•„๋“œ์— final ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ์ด์šฉํ•˜๋ฉด ์ƒ์„ฑ์ž์—์„œ ํ˜น์‹œ๋ผ๋„ ๊ฐ’์ด ์ดˆ๊ธฐํ™”(์„ค์ •)๋˜์ง€ ์•Š๋Š” ์˜ค๋ฅ˜๋ฅผ ์ปดํŒŒ์ผ ์‹œ์ ์— ๋ง‰์•„์ค„ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

@Component
public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy
            discountPolicy) {
        this.memberRepository = memberRepository;
    }
    //...
}

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ