Spring Model/01. Model

@Repository의 역할

은서파 2024. 3. 22. 14:45

이번 포스트에서는 @Repository에 대해서 살펴보자.

 

@Repository

 

용도

@Repository는 묵시적인 빈 등록을 위해서 사용되는 stereo type annotation으로 통상 Repository(DAO) 역할을 하는 빈에 선언한다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
	@AliasFor(annotation = Component.class)
	String value() default "";
}

통상 stereo 타입 annotation은 분류하기 위해서 사용하는데 @Repository는 좀 특별한 기능을 가지고 있다. docs에서 Repository를 찾아보면 이것 저것 이야기가 많다.(https://docs.spring.io/spring-framework/docs/5.3.30/javadoc-api/org/springframework/stereotype/Repository.html)

Repository는 DDD(Domain Driven Design: 도메인 주도 설계)에서 나온 개념으로 스토리지를 캡슐화하고 검색등을 위해 사용되는 녀석이라고 한다.

하단부의 내용이 이번 글을 쓰게되는 출발점인데..

A class thus annotated is eligible for Spring DataAccessException translation when used in conjunction with a 
PersistenceExceptionTranslationPostProcessor. The annotated class is also clarified as to its role in the overall application architecture for the purpose of tooling, aspects, etc.

@Repository로 annotated된 클래스에서는 PersistenceExceptionTranslationPostProcessor와 결합되면  (일반적인 RuntimeException 들이) DataAccessException으로 변환된다는 내용이다.

이 내용을 확인해보자.

 

PersistenceExceptionTranslationPostProcessor

어떤 예외를 PersistenceException으로 바꿔주는 후처리 프로세서인가보다. 이녀석을 찾는데 시간이 많이 걸린것 같다.

문제는 이놈은 spring-dao 에 포함된 녀석인데 "요즘은 잘 안쓰이나?" 십다. 마지막 버전이 무려 2008년 1월이다.

<!-- https://mvnrepository.com/artifact/org.springframework/spring-dao -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-dao</artifactId>
    <version>2.0.8</version>
</dependency>

 

빈 등록

이제 필요한 빈은 위에서 가져온 녀석과 실제 예외를 변경해줄 빈(PresistenceExceptionTranslator)이 필요하다.

@Bean
PersistenceExceptionTranslationPostProcessor persistenceExceptionProcessor() {
    return new PersistenceExceptionTranslationPostProcessor();
}
    
@Bean
TempTranslator TempTranslator() {
    return new TempTranslator();
}
    
static class TempTranslator implements PersistenceExceptionTranslator{
    @Override
    public DataAccessException translateExceptionIfPossible(RuntimeException re) {
        // re에 따라서 적절한 타입으로 만들어 볼 수 있다.
        return new DataAccessException("그냥 만들어봄") {};
    }
}

 

테스팅

먼저 Repository를 만들어보자.

@Repository
public class MyRepo {

    public void method() {
        int i = 1 / 0;
    }
}

즉 method가 호출되면 ArithmeticException이 발생된다.

@SpringBootTest
class TestApplicationTests {
    @Autowired
    MyRepo repo;

    @Test
    void contextLoads() {
        DataAccessException exception = assertThrows(DataAccessException.class, () -> repo.method());
        assertEquals(exception.getMessage(), "그냥 만들어봄");
    }
}

하지만 실제 메서드를 호출해보면 DataAccessException으로 전달된 것을 확인할 수 있다.