Classpath Scanning and Managed Components

Spring ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ Classpath Scanning๊ณผ Managed Components๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด XML ์—†์ด๋„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ  ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๋Š” ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™์œผ๋กœ Bean์„ ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์€ ์ฝ”๋“œ์˜ ๊ฐ„๊ฒฐ์„ฑ์„ ๋†’์ด๊ณ  ์„ค์ •์„ ๊ฐ„์†Œํ™”ํ•˜๋Š” ๋ฐ ๊ธฐ์—ฌํ•ฉ๋‹ˆ๋‹ค.

Component ๋ฐ ๊ด€๋ จ ์• ๋…ธํ…Œ์ด์…˜

Spring์€ ์—ฌ๋Ÿฌ ๊ณ„์ธต์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํด๋ž˜์Šค๋“ค์„ ์ ์ ˆํ•˜๊ฒŒ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ Stereotype ์• ๋…ธํ…Œ์ด์…˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค

  • @Component: ๋ชจ๋“  Spring ๊ด€๋ฆฌ ์ปดํฌ๋„ŒํŠธ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ผ๋ฐ˜์ ์ธ ์Šคํ…Œ๋ ˆ์˜คํƒ€์ž… ์• ๋…ธํ…Œ์ด์…˜์ž…๋‹ˆ๋‹ค.

  • @Repository: ์˜์†์„ฑ ๊ณ„์ธต์—์„œ DAO(Data Access Object)๋ฅผ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ์˜ˆ์™ธ ๋ฒˆ์—ญ ๋“ฑ์˜ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

  • @Service: ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์„œ๋น„์Šค ๊ณ„์ธต์„ ๋‚˜ํƒ€๋‚ด๋Š” ์Šคํ…Œ๋ ˆ์˜คํƒ€์ž…์ž…๋‹ˆ๋‹ค.

  • @Controller: ํ”„๋ ˆ์  ํ…Œ์ด์…˜ ๊ณ„์ธต์—์„œ MVC ํŒจํ„ด์˜ ์ปจํŠธ๋กค๋Ÿฌ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํด๋ž˜์Šค์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์Šคํ…Œ๋ ˆ์˜คํƒ€์ž… ์• ๋…ธํ…Œ์ด์…˜๋“ค์€ @Component์˜ ํŠน์ˆ˜ํ™”๋กœ, ๊ฐ ๊ณ„์ธต์— ์ ํ•ฉํ•œ ์ถ”๊ฐ€์ ์ธ ์˜๋ฏธ๋‚˜ ๋„๊ตฌ์— ์˜ํ•œ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Meta-Annotations ๋ฐ Composed Annotations

Spring์˜ ์• ๋…ธํ…Œ์ด์…˜๋“ค์€ ๋‹ค๋ฅธ ์• ๋…ธํ…Œ์ด์…˜์— ๋ฉ”ํƒ€ ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์—ฌ๋Ÿฌ ๋ฉ”ํƒ€ ์• ๋…ธํ…Œ์ด์…˜์„ ๊ฒฐํ•ฉํ•˜์—ฌ Composed Annotation์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, @RestController๋Š” @Controller์™€ @ResponseBody๋ฅผ ๊ฒฐํ•ฉํ•œ ์• ๋…ธํ…Œ์ด์…˜์ž…๋‹ˆ๋‹ค. Composed Annotation์€ ๋ฉ”ํƒ€ ์• ๋…ธํ…Œ์ด์…˜์˜ ์†์„ฑ์„ ์žฌ์ •์˜ํ•˜์—ฌ ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Classpath์—์„œ Bean์„ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ  ๋“ฑ๋กํ•˜๊ธฐ

Spring์€ ํด๋ž˜์Šค ๊ฒฝ๋กœ๋ฅผ ์Šค์บ”ํ•˜์—ฌ ํŠน์ • ์กฐ๊ฑด์— ๋งž๋Š” ํด๋ž˜์Šค๋“ค์„ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ , ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ BeanDefinition์œผ๋กœ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ XML๋กœ Bean์„ ๋“ฑ๋กํ•˜๋Š” ๋Œ€์‹ , ์ปดํฌ๋„ŒํŠธ ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด ์ž๋™์œผ๋กœ Bean์„ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.

์„œ๋น„์Šค ํด๋ž˜์Šค์™€ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ํด๋ž˜์Šค

@Service
public class SimpleMovieLister {
    private MovieFinder movieFinder;

    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}

@Repository
public class JpaMovieFinder implements MovieFinder {
    // ๊ตฌํ˜„ ์ƒ๋žต
}

Configuration ํด๋ž˜์Šค์—์„œ Component ์Šค์บ” ์‚ฌ์šฉ

@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
    // ์„ค์ • ๋ฉ”์„œ๋“œ ์ƒ๋žต
}

๋˜๋Š” XML์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ™์€ ์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="...">
    <context:component-scan base-package="org.example"/>
</beans>

์ด ๊ตฌ์„ฑ์—์„œ๋Š” context:component-scan์ด context:annotation-config ๊ธฐ๋Šฅ์„ ์ž๋™์œผ๋กœ ํ™œ์„ฑํ™”ํ•˜๋ฏ€๋กœ, ๋‘ ์š”์†Œ๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์Šค์บ” ์ปค์Šคํ„ฐ๋งˆ์ด์ง•: ํ•„ํ„ฐ ์‚ฌ์šฉ

๊ธฐ๋ณธ์ ์œผ๋กœ Spring์€ @Component, @Repository, @Service, @Controller, @Configuration ์• ๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํด๋ž˜์Šค๋งŒ์„ ๊ฐ์ง€ํ•˜์—ฌ Bean์œผ๋กœ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด ๋™์ž‘์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. includeFilters ๋˜๋Š” excludeFilters ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ XML ์„ค์ •์—์„œ context:include-filter ๋˜๋Š” context:exclude-filter ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, @Repository ์• ๋…ธํ…Œ์ด์…˜์ด ์žˆ๋Š” ํด๋ž˜์Šค๋ฅผ ์ œ์™ธํ•˜๊ณ  Stub ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋งŒ ํฌํ•จํ•˜๋Š” ์„ค์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

@Configuration
@ComponentScan(basePackages = "org.example",
               includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
               excludeFilters = @Filter(Repository.class))
public class AppConfig {
    // ์„ค์ • ์ƒ๋žต
}

XML๋กœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

<context:component-scan base-package="org.example">
    <context:include-filter type="regex" expression=".*Stub.*Repository"/>
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

Bean ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ •์˜

Spring ์ปดํฌ๋„ŒํŠธ์—์„œ @Bean ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ถ”๊ฐ€์ ์ธ Bean ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, @Component ํด๋ž˜์Šค์—์„œ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Bean์„ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

@Component
public class FactoryMethodComponent {

    @Bean
    @Qualifier("public")
    public TestBean publicInstance() {
        return new TestBean("publicInstance");
    }

    @Bean
    protected TestBean protectedInstance(@Qualifier("public") TestBean spouse) {
        return new TestBean("protectedInstance");
    }
}

Autowired ๋ฐ Lazy ์˜์กด์„ฑ ์ฃผ์ž…

@Autowired ํ•„๋“œ์™€ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ์ง€์›์ด ์žˆ์œผ๋ฉฐ, @Lazy ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ง€์—ฐ ๋กœ๋“œํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€์—ฐ ๋กœ๋“œ๋œ Bean์€ ํ•„์š”ํ•  ๋•Œ๊นŒ์ง€ ์ƒ์„ฑ๋˜์ง€ ์•Š๊ณ , ๋” ๋‚˜์•„๊ฐ€ ObjectProvider์™€ ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋” ๋ณต์žกํ•œ ์ƒํ˜ธ์ž‘์šฉ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฆ„ ์ž๋™ ๊ฐ์ง€

ํด๋ž˜์Šค๊ฐ€ ์Šค์บ”๋  ๋•Œ BeanNameGenerator ์ „๋žต์— ์˜ํ•ด ์ด๋ฆ„์ด ์ž๋™ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ AnnotationBeanNameGenerator๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์Šคํ…Œ๋ ˆ์˜คํƒ€์ž… ์• ๋…ธํ…Œ์ด์…˜์—์„œ value ์†์„ฑ์— ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ๊ทธ ์ด๋ฆ„์ด Bean ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํด๋ž˜์Šค๋Š” ๊ฐ๊ฐ myMovieLister์™€ movieFinderImpl๋ผ๋Š” ์ด๋ฆ„์˜ Bean์œผ๋กœ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค:

@Service("myMovieLister")
public class SimpleMovieLister {
    // ...
}

@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}

Bean ์ด๋ฆ„์ด ์ถฉ๋Œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ, BeanNameGenerator๋ฅผ ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆํ•˜์—ฌ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. FullyQualifiedAnnotationBeanNameGenerator์™€ ๊ฐ™์€ ์ „๋žต์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Autodetected ์ปดํฌ๋„ŒํŠธ์˜ ๋ฒ”์œ„ ์ง€์ •

๊ธฐ๋ณธ์ ์œผ๋กœ ์ž๋™ ๊ฐ์ง€๋œ ์ปดํฌ๋„ŒํŠธ๋Š” singleton ๋ฒ”์œ„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ @Scope ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, prototype ๋ฒ”์œ„๋กœ ์„ค์ •๋œ Bean์€ ๋งค๋ฒˆ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค:

@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}

Qualifier ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ œ๊ณต

์ž๋™ ๊ฐ์ง€๋œ ์ปดํฌ๋„ŒํŠธ์—์„œ @Qualifier ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ธ๋ฐ€ํ•œ ์ฃผ์ž… ์ œ์–ด๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํŠน์ • Bean์ด ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ์„ ๋•Œ, ์–ด๋–ค Bean์„ ์ฃผ์ž…ํ• ์ง€ ์ง€์ •ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค:

@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
    // ...
}

๋˜ํ•œ ์ปค์Šคํ…€ ์• ๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ๋” ๊ตฌ์ฒด์ ์ธ ์ œ์–ด๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Last updated