첫 프로젝트의 설정이 전부 XML이었고 파일도 여럿이었다. 어느 파일을 봐야 하는지부터 몰랐다.
Table of contents
Open Table of contents
어디에 뭐가 있는지 몰랐다
Spring 설정 XML이 여덟 개였다. DataSource를 고치려면 어디를 열어야 하는지, 화면 매핑은 또 어디인지 매번 찾아야 했다.
며칠 보니 이름에 규칙이 있었다. 앞에 context-가 붙은 것은 애플리케이션 전체 설정이고 servlet-이 붙은 것은 화면 요청 처리다. 앞부분만 보면 어느 쪽인지 갈린다.
한 파일에 다 넣지 않고 나눈 이유도 짐작이 됐다. 한 파일이면 길어져서 찾기 어렵고, 주제별로 나누면 무엇을 고칠지 알면 어느 파일인지도 안다.
패턴으로 읽고 있었다
파일들이 어떻게 이어지는지 봤다. 들어가는 지점은 web.xml의 ContextLoaderListener 설정에 적혀 있었다.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:context-*.xml</param-value>
</context-param>
이름 패턴으로 전부 읽고 있었다. 그러면 파일을 추가할 때 어딘가에 적을 필요 없이 이름만 맞추면 된다.
대신 이름을 틀리면 조용히 안 읽힌다. dao-context.xml처럼 앞뒤를 바꿔 지으면 context-*.xml 패턴에 안 걸리는데 오류 없이 그 설정이 없는 것처럼 동작한다. 실제로 겪었고 원인이 파일 이름이었다.
읽힌 파일 목록은 log4j에서 org.springframework를 DEBUG로 올리면 볼 수 있었다. 목록에 내 파일이 있는지 보면 된다.
연결이 코드에 없었다
또 헷갈린 것은 객체가 어디서 들어오는지가 Java 코드에 없다는 점이었다. 필드 선언과 setter만 있고 대입하는 줄이 없는데, XML의 <property name="userDao" ref="userDao"/>가 그 자리를 채운다.
setter 이름과 XML의 name이 맞아야 이어진다. ref가 가리키는 bean이 없으면 NoSuchBeanDefinitionException이 난다.
이 오류가 시작할 때 난다는 것이 다행이었다. 배포하자마자 알 수 있으니 그 기능을 실제로 쓰는 순간까지 모르는 것보다 낫다. 일찍 나는 오류가 나은 종류였다.
트랜잭션도 이름 규칙
트랜잭션도 XML에 있었다. TransactionProxyFactoryBean의 transactionAttributes에 메서드 이름 패턴이 적혀 있었다. insert*는 트랜잭션이 걸리고 get*은 PROPAGATION_REQUIRED,readOnly가 된다.
여기가 앞의 것과 성격이 달랐다. 메서드를 saveUser로 지으면 insert*에 안 걸리는데 오류가 안 난다. 코드는 그대로 돌고 중간에 실패해도 되돌아가지 않을 뿐이다. 언제 드러날지 모르는 종류라 앞의 것보다 무서웠다.
메서드 이름을 규칙대로 짓고 그 규칙을 문서에도 적어 뒀다. 설정에만 있으면 XML을 열어 봐야 알 수 있어서 새로 오는 사람이 모른다. 트랜잭션이 실제로 걸렸는지 확인하는 방법도 같이 적었다. 로그 수준을 올리면 트랜잭션 시작과 커밋이 찍혀서 눈으로 볼 수 있다.
정리
- 설정 파일이 여럿이면 이름 앞부분으로 어느 영역인지 갈린다
- 패턴으로 읽으면 파일 추가가 자동인 대신 이름을 틀리면 조용히 빠진다
- 읽힌 파일 목록은 로그 수준을 올려 확인할 수 있다
- 객체 연결이 코드에 없고 이름으로 이어진다
- 이름이 안 맞으면 시작할 때 오류가 난다. 일찍 나는 편이 낫다
- 트랜잭션은 메서드 이름 규칙으로 걸린다
- 이름이 규칙과 다르면 조용히 안 걸리고 오류도 안 난다
- 규칙과 확인 방법을 문서에도 적어 둔다