관리 메뉴

공부한것들을 정리하는 블로그 입니다.

토비의스프링3.1 7장. 스프링 핵심 기술의 응용 본문

Spring/공부

토비의스프링3.1 7장. 스프링 핵심 기술의 응용

호 두 2022. 7. 26. 23:20
반응형

토비의스프링 7장. 스프링 핵심 기술의 응용


7.1 SQL과 DAO의 분리

SQL을 Dao에서 분리하는 이유?
-> 운영 중에 DB의 테이블 or 필드이름 or SQL문이 변경될 수 있는데, 그 때마다 Dao를 수정해서 다시 컴파일하기에는 무리가 있기 때문


XML 설정을 이용한 분리
 - SQL을 xml설정파일의 프로퍼티 값으로 정의해서 DAO에 주입
 - 스프링의 DI를 사용하여, String값을 외부에서 SQL을 분리하였다.
 - 매번 프로퍼티 추가하는건 굉장히 번거롭다
-> SQL을 하나의 컬렉션으로 묶는다.


SQL 맵 프로퍼티 방식
 - SQL을 하나의 컬렉션으로 담도록 해보자. Key에 대응되는 Value는 SQL 문장이 될 것이다. 프로퍼티를 추가하거나 하지 않고 맵 정보에만 추가해주면 된다.
 - SQL을 맵으로 전환할 때는 setter 설정 필요없이 만 추가해주면 된다.


SQL 제공 서비스
 - 스프링 설정파일 안에 SQL과 DI 설정 정보가 섞여있는건 문제가 있다.
-> 운영 중인 애플리케이션에 빈번하게 참조되는 맵 내용을 수정할 경우 동시성 문제를 일으킬 수도 있다.

따라서, 독립적인 SQL 제공 서비스를 제공해야한다.
-> SQL을 분리하자.


SQL 서비스 인터페이스
 - applicationContext.xml + SQL 서비스 인터페이스
 - SQL에 대한 키 값을 전달하면, 그에 해당하는 SQL을 돌려주게 한다.
 - 이제 이 SqlService에 XML로 주입을 하던, 다른 방법으로 주입을 하던 빈을 DI해주기만 하면 된다.


7.2 인터페이스의 분리와 자기참조 빈
XML 설정 파일에 SQL 문을 넣는 대신, SQL을 담는 전용 XML을 만들어보자.

JAXB(Java Architecture for XML Binding)
- 마샬링(marshalling) : 바인딩 오브젝트를 XML 문서로 변환하는 것
- 언마샬링(unmarshalling) : XML 문서를 읽어서 자바의 오브젝트로 변환하는 것


인터페이스 분리
 - 책임에 따라 XmlSqlService 인터페이스를 분리 한다.
 - 책임 1: SQL 정보를 외부의 리소스로부터 읽어 온다. -> SqlReader
 - 책임 2: 읽어온 SQL을 보관해두고 있다가 필요할 때 제공해준다. -> SqlRegistry
 - 책임 3: XML에서 읽어온 SQL 정보를 관리 -> SqlService

SqlService가 SqlReader에게 Sql을 가져오라고 요청하고, 
SqlReader는 SqlRegistry에 sql을 등록하며, 
SqlService는 SqlRegistry에서 Sql을 검색할 수 있게 된다.


디폴트 의존관계
 - 외부에서 DI 받지 않는 경우 기본적으로 자동 적용되는 의존 관계.
 - 생성자에서 디폴트 의존 객체를 직접 만들어소 스스로 주입해준다.
 - 다른 명시적인 설정이 있다면, 그 설정을 따른다.


7.3 서비스 추상화 적용


7.4 인터페이스 상속을 통한 안전한 기능확장
애플리케이션 재시작 없이 특정 SQL의 내용만을 변경하고 싶을 때 어떻게 해야 할까?


DI와 기능의 확장
 - DI를 의식하면서 설계하는 방식은 유연한 확장과 재사용이 가능한 설계를 만드는 데 많은 도움이 된다


인터페이스를 사용해야 하는 이유
 1. 다형성을 얻기 위해
- 하나의 인터페이스를 통해 여러 개의 구현을 바꿔가면서 사용할 수 있다.

 2. 인터페이스 분리 원칙을 통해 클라이언트와 의존 오브젝트 사이의 관계를 명확하게 해줄 수 있기 때문
- 인터페이스는 하나의 오브젝트가 여러 개를 구현할 수 있기 때문에 관심사가 어디로 연결되어 있는지 직관적으로 알 수 있다. 결국 이를 통해 오브젝트의 응집도를 높여 작은 단위로 설계되게끔 해 준다.

* 인터페이스 분리 원칙(Interface Segregation Principle)은 오브젝트가 그 자체로 충분히 응집도가 높은 작은 단위로 설계됐더라도, 목적과 관심사가 다른 여러 개의 클라이언트가 있다면 인터페이스로 분리시켜야 한다는 원칙이다.
- 이 원칙이 주는 장점은 클라이언트가 자신의 관심에 따른 접근 방식을 불필요한 간섭 없이 유지할 수 있다는 점이다.

 3. 클라이언트에 특화된 의존관계를 만들 수 있음
- DI는 특별한 이유가 없는 한 항상 인터페이스를 사용해야 한다.


인터페이스 상속
 - 인터페이스를 적절히 분리하고 확장하는 방법을 통해 오브젝트 사이의 의존관계를 명확하게 해 줄 수 있다.
 - 새롭게 추가할 기능을 사용하는 클라이언트가 있다면, 새로운 인터페이스를 정의하거나 기존 인터페이스를 확장해야 한다



7.5 DI를 이용해 다양한 구현 방법 적용하기

ConcurrentHashMap 사용하기
 - 그러나 ConcurrentHashMap은 변경이 자주 일어나는 환경에선 동기화의 성능하락에서 자유로울 수 없다. 
 - 그래서 SQL을 담는 DB같은 것을 설계해볼 순 있지만, 관계형 데이터베이스 스키마를 구현하는 것은 배보다 배꼽이 더 커질 수가 있다. 그래서 내장형 DB를 고려해볼 수 있다.


내장형 데이터베이스
 - 내장형 DB(Embedded DB)는 인메모리 DB라고 생각하면 좋다. 
 - Persistence는 보장되지 않지만 메모리에 저장되어 빠른 IO가 가능하다. 
 - 또한 등록, 수정, 검색, 격리수준, 트랜잭션, 최적화된 락킹 등 DB가 제공할 수 있는 것들은 모두 제공할 수 있다. SQL문으로 질의가 가능한 것은 덤이다.


스프링의 내장형 DB 지원
 - 자바에서는 Derby, HSQL, H2등의 내장형 데이터베이스가 널리 쓰인다.
 - EmbeddedDatabase



7.6 스프링 3.1의 DI
DI의 원리는 변하지 않았지만 DI를 적용하는 방법은 많이 변해왔다. 대표적인 두 가지는 아래와 같다.


애너테이션의 메타정보 활용
 - 애너테이션은 코드 실행에 직접적으로 영향을 끼치지 못하고, 인터페이스처럼 타입을 부여하는 것도 아니며, 오버라이드나 상속이 불가능하다. 대신 프레임워크가 코드의 특성을 분석할 수 있는 메타정보로써 활용된다.
 - 에너테이션이 부여된 클래스나 메서드의 패키지, 클래스 이름, 메서드 시그니쳐, 접근제한자, 상속한 클래스나 구현 인터페이스 등을 알 수 있다. 반면에 XML은 모든 내용을 명시적으로 작성해야 하기에 번거롭다.


정책과 관례를 이용한 프로그래밍
 - 애너테이션 같은 메타정보를 활용하는 이유는 코드로 동작 내용을 구체적으로 구현하는 대신, 미리 약속한 규칙이나 관례를 따라 구현했다면, 애너테이션으로 쉽게 부가적인 것들을 부여할 수 있다. 
 - 반복되는 부분을 줄여주고 빠르게 구현할 수 있다는 장점이 있다. 반면에 이 모든 규칙들을 익히는 러닝 커브와 방대한 분량이 문제가 된다.


xml을 애너테이션과 자바코드로 대체하기
 - ContextConfiguration은 스프링 테스트가 DI 정보를 어디서 가져와야할 지 지정하는 애너테이션이다.

 @Configuration
- DI 정보로 사용될 자바 클래스를 만들 때 @Configuration 애너테이션을 사용한다. 해당 애너테이션이 붙은 클래스는 앞으로 XML을 대신하여 DI 설정정보로 이용될 것이다.
 @Bean
- bean 태그에 정의된 DI 정보는 @Bean이 붙은 메서드와 1:1로 매핑된다. @Bean은 @Configuration이 붙은 DI 설정용 클래스에서 사용된다. 메서드를 이용해 빈 오브젝트의 생성과


빈 스캐닝과 자동 와이어링

 @Autowired
- XML의 프로퍼티를 이용해 자바 코드로 작성한 DI 정보를 참조할 수 있었지만, XML에 작성된 DI 정보를 자바 코드에선 어떻게 참조할까? @Autowired를 이용할 수 있다.
- @Autowired는 필드의 타입과 빈의 타입이 일치하면 빈을 자동으로 주입해준다. 빈의 프로퍼티 설정을 직접 해주는 자바 코드나 XML의 양을 줄일 수 있다.
 @Component
- 클래스에 부여되는 애너테이션으로, 부착된 클래스는 자동으로 빈으로 등록된다. 그러나 모든 클래스패스의 클래스를 검사하여 등록하는건 부담이 큰 일이기에, 특정 패키지 하위 주소에서만 찾도록 범위를 좁혀줄 필요가 있다.
 @ComponentScan
- @Component가 부착된 클래스를 찾으면 자동으로 Bean으로 등록하며, 
- 특별히 Bean의 아이디를 지정하지 않았다면(@Component("{Bean의 아이디}")와 같이 지정할 수 있다)
- 클래스의 첫 글자를 소문자로 바꾸어 아이디로 사용한다. 
- 이렇게 자동 빈 등록을 이용하는 경우에는 의존 프로퍼티를 설정할 수 없으므므로, @Autowired를 이용하도록 한다.
 @Repository
- DAO 기능을 제공하는 클래스에 부착하는 @Repository 애너테이션이 존재한다. 이를 권장하기도 한다. 마찬가지로 자동 빈 등록대상이 된다.


반응형
Comments