Toby 스프링3 1부 7장 스프링 핵심기술의 응용 1
05 Sep 2017 | 스프링 spring Resource interface7.3.3 리소스 추상화
기존 코드의 문제점 : query 정보를 담은 xml파일의 위치가 [DAO classpath]에 제한되어 있다.
여기서 [DAO classpath]는 소스코드의 위치가 아닌 빌드된 위치 .clss 생성된 위치를 말한다.
실습 할때는 빌드시 해당 sqlmap.xml이 삭제되어 Resources디렉토리로 옮기고 읽어들이도록 하였다.
자바에서는 다양한 위치에 존재하는 리소스에 대해 단일화된 접근 인터페이스를 제공해주는 클래스가 없다.
URL (java.net.URL) 의 경우 원격만 가능하고 리소스 파일의 존재여부를 미리 알수가 없다.
그래서 스프링에서는 Resource라는 추상화 interface를 제공한다.
Resource
(org.springframework.core.io) Resource는 다른 서비스 추상화의 오브젝트와 달리, 빈이 아니라 값으로 취급된다. property의 ref가 아닌 value로 밖에 등록할 수 없다.
value로 취급함으로 객체로 변환해줄 장치가 필요하다 이게 ResourceLoader 이다.
ResourceLoader
(org.springframework.core.io) 스프링에서는 리소스의 종류와 위치를 문자열로 지정하면 이를 Resource 객체로 변환하는 ResourceLoader를 제공한다.
스프링의 ApplicationContext는 ResourceLoader를 상속받는다.
스프링에서 제공하는 빈으로 등록가능한 클래스에 파일 지정이 가능하다면 거의 모두 Resource type이다.
Resource 타입은 빈으로 등록하지 않고
7.4. 인터페이스 상속을 통한 안전한 기능 확장
기능 개선: Application을 재시작하지 않고 특정 SQL의 내용만 변경
7.4.1 DI와 기능의 확장
DI의 가치를 제대로 얻으려면, 먼저 DI에 적함한 오브젝트 설계가 필요하다.
DI를 의식하는 설계
많은 고민과 학습, 훈련, 경험이 필요하다. (즉, 시간과 노력이 필요하다.)
DI를 적용하려면 커다란 오브젝트만 존재해서는 안된다. ( 통짜 프로그램 이거하나면 다되요.) 최소한 두개 이상의 의존관계를 가지고 서로 협력해서 일하는 오브젝트가 필요하다. (레고 블록도 하나만 있으면 안된다. 2개 이상이 있어야 서로 맞물려 먼가를 만들지…) DI는 런타임시 의존 오브젝트를 다이내믹하게 연결해서 유연한 확장을 꾀하는게 목적이기 때문에 항상 확장을 염두에두고 오브젝트 사이의 관계를 생각해야 한다.
DI와 인터페이스 프로그래밍
- 다형성
- interface 분리원칙을 통해 클라이언트와 의존오브젝트 사이의 관계를 명확하게 해줄 수 있다.
interface 분리원칙: 오브젝트가 그 자체로 충분히 응집도가 높은 작은 단위로 설계됐더라도, 목적과 관심이 각기 다른 클라이언트가 있다면 인터페이스를 통해 이를 적절하게 분리할 필요가 있다.
미래 바뀔거 같은 기능이 있다 이는 interface로 정의 해주고 추후에 구현체로 바꿔줄 수 있게 만든다. ( 레볼 블록의 표준화된 규격을 생각하면 된다. 규격만 맞으면 어떤 레고 블록도 꽂을 수 있다.)
이러한 오브젝트는 여러 인터페이스를 동시게 갖을 수 있다. 물론 클래스는 동시 상속이 안되지만 인터페이스는 가능하다. 여러 인터페이스를 구현한 클래스 객체를 생성하고 다른 클라이언트에서 필요한 인터페이스에 맞춰 사용할 수 있다.
7.4.2 인터페이스 상속
인터페이스 상속을 통한 확장
기존 오브젝트를 확장하는 방법에는 interface를 새로 추가하거나 기존의 interface를 상속하는 방법이 있다.
7.5 DI를 이용한 다양한 구현방법 적용하기
운영중인 시스템에서 사용하는 정보를 실시간으로 변경하는 작업을 할 때 가장 고려사항은 동시성 문제이다.
7.5.1 ConcurrentHashMap을 이용한 수정 가능 SQL 레지스트리
HashMap은 멀티 스레드 환경에서는 예상하지 못한 결과를 발생 시킬 수 있다.
멀티 스레드 환경에서 안전하게 HashMap을 조작하려면 Collections.sychronizedMap()등을 이용하면되지만 빈번하게 서비스 요청이 있을 시 성능문제가 발생한다.
이럴 때는 ConcurrentHashMap을 사용한다. ConcurrentHashMap은 데이터 조작시 전체 데이터에 대해 락을 걸지 않고 조회에는 아예 조회를 걸지 않아 성능 향상을 꾀한다.
단위 테스트를 별도로 만든다.
- SQL 등록한 것이 잘 조회 되는가?
- SQL 수정이 잘 되는가?
- 존재하지 않는 SQL을 수정 시 적절한 예외를 발생시키는 가?
테스트를 만들 때 중요한건 코드를 작성한 다음 테스트를 만들어 검증하는 그 사이의 간격을 가능한 짧게하고, 예외 사항을 포함한 기능을 세세하게 검증하도록 테스트를 만드는 것이다.
테스트를 철저하게 만들어서 기능을 검증하고 구현방식이 변경 될 때마다 테스트를 실행해서 기능에 영향을 주는지 확인하는 일이 중요하다.
7.5.2 내장형 데이터베이스를 이용한 SQL 레지스트리 만들기
스프링의 내장형 DB 지원
내장형 DB 빌더 학습 테스트
실습 시 문제점 : SimpleJdbcTemplate는 더이상 사용되지 않는다. JdbcTemplate로 실습하면 된다.
내장형 DB를 이용한 SqlRegistry 만들기
XML 설정을 통한 내장형 DB의 생성과 적용
실습 시 문제점 : 실습 예제에 아래 코드 부분이 빠져 있다. 그래서 아래와 같은 에러가 발생한다.
Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 38 in XML document from class path resource [applicationContent.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 38; columnNumber: 63; cvc-complex-type.2.4.c: 일치하는 와일드 카드 문자가 엄격하게 적용되지만 'jdbc:embedded-database' 요소에 대한 선언을 찾을 수 없습니다.
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd 추가해주면 된다.
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
">
xsd(XML SCHEMA Definition)란 XML스키마 정의를 말한다.
‘jdbc:embedded-database’ 여기에 대한 요소 정의가 xsd 파일에 있는데 이파일이 빠져서 해당 요소 정의를 찾지 못하여 Bean 생성 시 에러를 출력하게 된다.
7.5.3 트랜잭션 적용
앞에서의 실습 코드는 트랜잭션이 적용 되지 않아 맵으로 일괄 변경 작업이 일어날 때는 문제가 발생할 수 있다.
컬랙션에 트랜잭션을 적용하기는 어렵지만 내장형 DB에 트랜잭션을 적용하기는 상대적으로 쉽다.
스프링에서 트랜잭션을 적용할 때 트랜잭션 경계가 DAO밖에 있고 범위가 넓은 경우라면 AOP를 이용하는 것이 편리하지만 SQl레지스트리로 제한된 오브젝트내에 서비스 특화된 간단한 트랜잭션이 필요할 때는 간단한 트랜잭션 추상화 API를 직접 사용하는게 편리하다.
다중 SQL 수정에 대한 트랜잭션 테스트
코드를 이용한 트랜잭션 적용
PlatformTransactionManager를 직접사용해서 트랜잭션 처리 코드를 만들어도 되지만 그보다 간결하게 트랜잭션 적용 코드에 템플릿/콜백 패턴을 적용한 TransactionTemplate를 쓰는 것이 낫다.
일반적으로 트랜잭션 매니저를 싱글톤 빈으로 등록해서 사용하는데, 이유는 여러 개의 AOP를 통해 만들어지는 트랜잭션 프록시가 같은 트랜잭션 매니저를 공유하기 때문이다.
앞에서 만들 EmbeddedDbSqlRegistry는 내장형 DB를 사용함으로 트랜잭션 메니저를 공유할 필요가 없다.
TransactionTemplate은 멀티스레드 환경에서 공유해도 안전함으로 처음 만들때 인스턴스 변수에 저장하여 사용한다.
Comments