스프링 핵심 기술의 응용 (토비의 스프링 vol.1 7장 7.1~7.5)
SQL을 DAO코드에서 분리하자
- XML설정을 이용한 분리
- 설정파일에 넣은 SQL 문장
<bean id="userDao" class="springbook.user.dao.UserDao3dbc"> <property name="dataSource" ref="dataSo니rce" /> <property name="sqlAdd" value="insert into users(id, name, password,email, level, login, recommend) values(?,?,?,?,?,?,?)" /> -
문제점 : 새로운 SQL마다 새로운 프로퍼티와 DI를 위한 변수와 수정자 메소드 필요
- Map 프로퍼티 방식
- 설정파일에 넣은 SQL 문장
<bean id="userDao" class="springbook.user.dao.UserDaoJdbc"> <property name="dataSource" ref="dataSource" /> <property name="sqlMap"〉 <map> <entry key="add" value="insert into users(id, name, password,email, level, login, recommend) values(?,?,?,?,?,?,?)" /〉 <entry key="get" value="select * from users where id = ?" /〉 <entry key="getAll" value="select * from users order by id" /> <entry key="deleteAll" value-"delete from users" /> <entry key="getCount" value="select count(*) from users" /> <entry key="update" value="update users set name = ?, password = ?, email = ?, level = ?, login = ?, recommend = ? where id = ?" /> </map> </property> </bean> -
문제점 : 해당 메소드가 실행되기 전까지 오류 확인이 힘듦
- 별도의 인터페이스를 통해 SQL을 제공
- SqlService 인터페이스
public interface SqlService{ String getSqKString key) throws SqlRetrievalFailureException; } - SqlService 구현
public class SimpleSqlService implements SqIService { private Map<String, String> sqlMap; public void setSqlMap(Map〈String, String> sqlMap) { this.sqlMap = sqlMap; } public String getSqKString key) throws SqlRetrievalFailureException { String sql = sqlMap.get(key); if (sql == null) throw new SqlRetrievalFailureException(key +"에 대한 SQL을 찾을 수 없습니다"); else return sql; } } - JAXB(Java Architecture for XML Binding)
- 자바 객체와 XML 간의 변환을 자동화해주는 API
- 마샬링(Marshalling) : 자바 객체 -> XML 형식
- 언마샬링(Unmarshalling) : XML 데이터 -> 자바 객체

-
매핑용 클래스에는 변환 작업에서 참고할 정보를 어노테이션으로 갖고 있다
- 언제 JAXB를 통해 XML문서를 가져와야 할까?
- SQL을 요청할 때 마다 매번 XML 파일을 읽는 것은 비효율적이다
- 한 번만 읽고 저장해두자
- 생성자에서 사용
- 예외가 발생하면 상속이나 보안에 문제가 생길 수 있다
- 별도의 초기화 메소드 사용
- 빈 설정을 지원해주는 빈 후처리기를 사용하여 자동 실행되도록 해준다
- <context:annotation-config /> 를 통해 등록
- @PostConstruct 어노테이션 사용
- 빈이 생성되고 DI작업을 마친 뒤에 자동으로 실행해줌
책임 분리
SQL 정보를 읽는 작업과 읽은 SQL 보관하고 제공하는 작업을 분리하자

- 한 클래스에서 세 개의 인터페이스를 구현

-
자기참조 빈
-
디폴트 의존관계
- 외부에서 DI 받지 않는 경우 자동 적용되는 기본 의존관계
- 특정 의존 오브젝트가 대부분의 환경에서 거의 기본이라고 할 만큼 사용될 가능성이 있다면 사용
- 생성자를 사용
- 단점
- 다른 의존 오브젝트를 사용해도 일단 디폴트 의존 오브젝트를 만들긴 한다
서비스 추상화 적용
필요에 따라 JAXB가 아닌 다른 기술로 바꿀 수 있어야 한다

- 이런 기술들을 OXM(Object-XML Mapping)이라고 한다
-
스프링이 제공하는 OXM 추상 계층의 API를 이용하자
- OXM 추상화 서비스 인터페이스
- Marshaller : 자바 오브젝트 -> XML
- Unmarshaller : XML -> 자바 오브젝트
OXM 기술에 따라 추상화 서비스 인터페이스를 구현한 클래스가 있음 각 클래스는 해당 기술에서 필요하는 정보를 빈 프로퍼티로 지정할 수 있다
- JAXB용 Unmarshaller 빈 설정
<bean id="unmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> <property name="contextPath" value="springbook.user.sqlservice.jaxb" /> </bean> - Castor용 Unmarshaller 빈 설정
<bean id="unmarshaller" class="org.springframework.oxm.castor.CastorMarshaller"> <property name="mappingLocation" value="springbook/learningtest/spring/oxm/mapping.xml" /> </bean>
현재는 매핑 정보가 담긴 XML 파일이 같은 클래스패스에 존재해야한다
- 자바에는 다양한 위치의 리소스에 대한 단일화된 접근 인터페이스를 제공해주는 클래스가 없다
- URL을 이용해 웹상의 리소스에 접근할 수 있는 java.net.URL클래스는 있으나 이 클래스는 클래스패스나 임의의 스트림으로 가져올 수 있는 방법이 없다
- Resource 인터페이스
- 로우 레벨 자원들에 접근을 추상화하기 위한 인터페이스
- 자원들의 종류와 상관없이 동일한 방식으로 접근 가능
- SqlService 인터페이스
public interface Resource extends InputStreamSource { boolean exists(); boolean isReadable(); boolean isOpen(); boolean isFile(); URL getURL() throws IOException; URI getURI() throws IOException; File getFile() throws IOException; ReadableByteChannel readableChannel() throws IOException; long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String relativePath) throws IOException; String getFilename(); String getDescription(); } public interface InputStreamSource { InputStream getInputStream() throws IOException; } - 스프링에서 리소스는 빈이 아니라 값으로 취급된다
- 다른 구현 클래스를 지정해주는 추상화 방법을 적용할 수 없다
- property의 value 애트리뷰트는 문자열만 넣을 수 있다
- URL클래스와 유사하게 접두어를 이용해 리소스의 종류와 위치를 표현할 수 있다
- 문자열로 리소스를 오브젝트로 반환해주는 인터페이스를 제공한다
- ResourceLoader 인터페이스
package org.springframework.core.io; public interface ResourceLoader { Resource getResource(String location); ... } - ResouceLoader가 처리하는 접두어들

- 접두어를 사용한 리소스 지정
<property name="myFile" value="classpath:com/epril/myproject/myfile.txt" /> <property name="myFile" value="file:/data/myfile.txt" /> <property name="myFile" value="http://www.myserver.com/test.dat" />
ApplicationContext는 ResourceLoader 인터페이스를 상속한다
상속을 통한 안전한 기능확장
DI를 적용할 때는 가능한 인터페이스를 사용하자
- 하나의 인터페이스로 여러개의 구현체를 사용할 수 있다
- 인터페이스 분리 원칙(ISP : Interface Segregation Principle)
- 큰 덩어리의 인터페이스를 구체적이고 작은 단위로 분리시키자
- 객체가 자신이 사용하는 메서드에만 의존하도록 한다
- 인터페이스 분리 원칙을 준수하면 기존 클라이언트에 영향을 주지 않은 채로 오브젝트의 기능을 확장하거나 수정할 수 있다
- 내장형 DB(Embedded DataBase)
- 애플리케이션에 내장되어서 함께 시작되고 종료되는 DB
- 데이터가 메모리에 저장되어서 IO로 발생하는 부하가 적어 성능이 뛰어남
- Map과 같은 컬렉션이나 오브젝트를 이용해 메모리에 데이터를 저장해두는 방법에 비해 매우 효과적이고 안정적인 방법으로 등록, 수정, 검색이 가능
- 자바에서 사용되는 내장형 DB : Derby, HSQL, H2
- 스프링에선 초기화 작업을 지원하는 내장형 DB 빌더를 제공한다
댓글남기기