did_story

[Spring Boot / JAVA] Bean๋ถ€ํ„ฐ @Component, @Controller, @Service, @Repository ๊นŒ์ง€. ๋ณธ๋ฌธ

BackEnd๐Ÿƒ/Spring boot

[Spring Boot / JAVA] Bean๋ถ€ํ„ฐ @Component, @Controller, @Service, @Repository ๊นŒ์ง€.

์–ด์ œ์‹œ์ž‘ 2025. 6. 30. 15:43

์šฐ๋ฆฌ๊ฐ€ Spring์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๊ฐ€ ๋ฌด์—‡์ผ๊นŒ?

์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ!.

 

์Šคํ”„๋ง์€ ์ž๋ฐ” ๋นˆ์„ ์ฐพ์•„์„œ ApplicationContext๋ผ๊ณ  ํ•˜๋Š” ์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ ์˜ค๋ธŒ์ ํŠธ์— ๋“ฑ๋ก์„ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋Œ๋‹ค๊ฐ€ ์–ด๋–ค ํ”„๋กœ์ ํŠธ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์˜์กดํ•˜๋Š” ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ฐพ์•„์„œ ์—ฐ๊ฒฐํ•ด์ค€๋‹ค.

 

์Šคํ”„๋ง์€ ์–ด๋–ป๊ฒŒ ์ž๋ฐ” ๋นˆ์„ ์ฐพ์•„๊ฐ€์ง€๊ณ  ์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋กํ•˜๋Š”๊ฑธ๊นŒ???

๊ทธ๋ฆฌ๊ณ  ์ž๋ฐ” ๋นˆ์€ ๋ฌด์—‡์ด๊ณ  ์Šคํ”„๋ง ๋นˆ์€ ๋ฌด์—‡์„์„ ์˜๋ฏธํ• ๊นŒ???

์ž๋ฐ” ๋นˆ(Java Bean)์ด๋ž€??

์ˆœ์ˆ˜ํ•œ ์ž๋ฐ” ํด๋ž˜์Šค(Java class)์ด๋‹ค

 

์ฆ‰ ์ž๋ฐ” ์–ธ์–ด์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ผ์ •ํ•œ ๊ทœ์น™์„ ๋”ฐ๋ฅด๋Š” ํด๋ž˜์Šค๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

DTO ํ˜น์€ VO์˜ ํ˜„ํƒœ๊ฐ€ Java Bean์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์‰ฝ๋‹ค!

  • getter / setter
  • public์˜ no-argument ์ƒ์„ฑ์ž
  • ๋ชจ๋“  ํ•„๋“œ๋Š” private๋กœ getter์™€ setter๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ

getter์™€ setter, ์ƒ์„ฑ์ž๋ฅผ ๊ฐ€์ง€๋Š” ํด๋ž˜์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋œป์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋งŒํผ POJO(Plain Old Java Object)์™€ ๊ฑฐ์˜ ๋™์ผํ•œ ๊ฐœ๋…์ด๋ผ๊ณ  ์ดํ•ดํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

// Java Bean์˜ ์˜ˆ์ œ
public class User {

	// field๋Š” private๋กœ ์„ ์–ธ 
    private String name;
    private int age;
		
	// ์ƒ์„ฑ์ž
    public User() {}

	// getter
    public String getName() {
        return name;
    }
		
	// setter
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Spring Bean ์ด๋ž€?

๋นˆ(Bean)์€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋Š” ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์†Œํ”„ํŠธ์›จ์–ด ์ปดํฌ๋„ŒํŠธ์ด๋‹ค.
์Šคํ”„๋ง IoC์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” Java ๊ฐ์ฒด๋ฅผ ๋œปํ•œ๋‹ค

 

์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์€ Spring์ด ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.

๋นˆ์€ ์ธ์Šคํ„ด์Šคํ™”๋œ ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋œ ๊ฐ์ฒด๋ฅผ ์Šคํ”„๋ง ๋นˆ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์‰ฝ๊ฒŒ ์ดํ•ดํ•˜์ž๋ฉด new ํ‚ค์›Œ๋“œ ๋Œ€์‹  ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๋ณด๋ฉด ํŽธํ•ฉ๋‹ˆ๋‹ค.

์™œ ์‚ฌ์šฉํ•˜์ง€??

๊ฐ€์žฅ ํฐ ์ด์œ ๋Š” ์Šคํ”„๋ง ๊ฐ„ ๊ฐ์ฒด๊ฐ€ ์˜์กด ๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์— ๊ฐ€์žฅ ํฐ ๋ชฉ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ์ฒด๊ฐ€ ์˜์กด๊ด€๊ณ„๋ฅผ ๋“ฑ๋กํ•  ๋•Œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ํ•ด๋‹น ๋นˆ์„ ์ฐพ๊ณ , ๊ทธ ๋นˆ๊ณผ ์˜์กด์„ฑ์„ ๋งŒ๋“ค๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ๋Œ์•„์™€์„œ, @Component, @Controller, @Service, @Repository ๊ฐ€ ๋ฌด์—‡์ด์ง€?!

  • @Component๋Š” ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ํ˜•ํƒœ์˜ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ, ํŠน์ • ์—ญํ• ์— ์ข…์†๋˜์ง€ ์•Š๋Š” ์ผ๋ฐ˜์ ์ธ Spring Bean์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๊ณตํ†ต ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋‚˜, ํŠน์ • ๊ณ„์ธต์— ์†ํ•˜์ง€ ์•Š๋Š” ์ผ๋ฐ˜์ ์ธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • @Service๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํด๋ž˜์Šค์— ์‚ฌ์šฉ๋˜๋ฉฐ ์„œ๋น„์Šค ๋ ˆ์ด์–ด์˜ Bean์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • @Controeller๋Š” Spring MVC์—์„œ ์›น ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค์— ์‚ฌ์šฉ๋˜๋ฉฐ ํ”„๋ ˆ์  ํ…Œ์ด์…˜ ๋ ˆ์ด์–ด์˜ Bean์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • @Repository๋Š” ๋ฐ์ดํƒ€๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํด๋ž˜์Šค์— ์‚ฌ์šฉ๋˜๋ฉฐ, ๋ฐ์ดํ„ฐ ์—‘์„ธ์Šค ๋ ˆ์ด์–ด์˜ Bean์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

 

@Controller, @Repository ๋Œ€์‹  @Component ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋˜๋‚˜์š”?

Spring 6(Spring Boot 3) ์ด์ „ ๋ฒ„์ „์—์„œ๋Š” @Component + @RequestMapping์œผ๋กœ๋„ Bean ๋ฐ ํ•ธ๋“ค๋Ÿฌ๋กœ ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ Spring 6 ์ดํ›„ ๋ถ€ํ„ฐ @Controller ์™ธ์—๋Š” ํ•ธ๋“ค๋Ÿฌ๋กœ ๋“ฑ๋กํ•˜์ง€ ์•Š์•„ ์›น ์š”์ฒญ์„ ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
		implements MatchableHandlerMapping, EmbeddedValueResolverAware {
    ...
    @Override
    protected boolean isHandler(Class<?> beanType) {
        return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class); // ์ปจํŠธ๋กค๋Ÿฌ ์• ๋„ˆํ…Œ์ด์…˜์ธ์ง€ ํ™•์ธ
    }
    ...
}

@Repository๋ฅผ @Component๋กœ ๋Œ€์ฒดํ•  ๊ฒฝ์šฐ, PersistenceExceptionTranslationPostProcessor์— ์˜ํ•ด ์˜ˆ์™ธ๊ฐ€ DataAccessException์œผ๋กœ ๋ณ€ํ™˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค ๊ณ„์ธต์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์— ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ⇒ why? @Component์—๋Š” ์˜ˆ์™ธ ๋ณ€ํ™˜์„ ์œ„ํ•œ ํŠน์ˆ˜ ๊ธฐ๋Šฅ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์กฐ๊ธˆ๋” ์„ค๋ช…์„ ํ•˜์ž๋ฉด,

Spring์€ JPA, JDBC, Hibernate ๋“ฑ์˜ ๋ฐ์ดํ„ฐ ์—‘์„ธ์Šค ๊ธฐ์ˆ ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ํ”Œ๋žซํผ ๋…๋ฆฝ์ ์ธ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด์„œ org.springframework.dao.DataAccessException ๊ณ„์—ด์˜ ์˜ˆ์™ธ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š”๋ฐ, ์ด๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ๊ณณ์ด ๋ฐ”๋กœ

→ PersistenceExceptionTranslationPostProcessor

์ด ํด๋ž˜์Šค๋Š” AOP๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, @Repository๋กœ ๋งˆํ‚น๋œ ํด๋ž˜์Šค์˜ public ๋ฉ”์„œ๋“œ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋ฅผ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜์—ฌ ์ ์ ˆํ•œ DataAccessException์œผ๋กœ ๊ฐ์‹ธ์„œ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 

PersistenceExceptionTranslationPostProcessor (Spring Framework 6.2.8 API)

Bean post-processor that automatically applies persistence exception translation to any bean marked with Spring's @Repository annotation, adding a corresponding PersistenceExceptionTranslationAdvisor to the exposed proxy (either an existing AOP proxy or a

docs.spring.io

 

DataAccessException (Spring Framework 6.2.8 API)

Root of the hierarchy of data access exceptions discussed in Expert One-On-One J2EE Design and Development. Please see Chapter 9 of this book for detailed discussion of the motivation for this package. This exception hierarchy aims to let user code find an

docs.spring.io

 

๋˜ @Service, @Controller, @Repository๋Š” ๊ฐ๊ฐ ํŠน์ • ๊ณ„์ธต์„ ๋‚˜ํƒ€๋‚ด๋ฏ€๋กœ, AOP์˜ ํฌ์ธํŠธ์ปท์„ ์ •์˜ํ•  ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. @Component๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ๊ณ„์ธต ๊ตฌ๋ถ„์ด ๋ถˆ๋ถ„๋ช…ํ•ด์ ธ AOP ์ ์šฉ์ด ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

์ฐธ์กฐ
- ๋งค์ผ๋ฉ”์ผ,
- https://coding-nyan.tistory.com/158
- https://galid1.tistory.com/494