@Repository의 역할
이번 포스트에서는 @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으로 전달된 것을 확인할 수 있다.