토비의 스프링 Ver7

존스노우·2021년 11월 28일
0

스프링

목록 보기
8/22

스프링 핵심 기술의 응용

SQL과 DAO 분리

DB 테이블과 필드정보를 고스란히 담고 있는 SQL 문장을 분리해보자

이 두정보는 완벽하게 하면 변경될 일이 없지만
변화가 있을 수 있다 어쩔수 없이..

XML 설정을 이용한 분리

이렇게 하면 스프링 설정을 통해 빈 값에 주입해줄수 있다.

개별 SQL 프로퍼티 방식

이렇게 해두면 XML 파일만 변경해 주면 된다.

SQL 맵 프로퍼티 방식

SQL 이 많아지면? DAO 에 DI 용 프로퍼티를 계속 추가해줘서 곤란해짐

그래서 하나의 컬렉션 안에 담아두자.

이런식으로 하면 편리해지지만 SQL 을 가져올때 문자열로된 키값이 오타와 같은

실수가있으면 실행 되기전 오류 확인이 힘듬..

SQL 제공 서비스

위에도 단점이 존재하기에

DAO가 사용할 SQL을 제공해주는 기능을 독립 시킬 필요가 있다

SQL 서비스 인터페이스

DI 해주고..

SqlService는 모든 DAO 에서 서비스 빈을 사용하게 만들자..

스프링 설정을 사용하는 단순 SQL 서비스

SqlService 인터페이스에는 어떤 기술적인 조건이나 제약사항도 담겨 있지 않다.

인터페이스의 분리와 자기참조 빈

SqlService 구현방법 고민

XML 파일 매핑

XML에 SQL 정보를 넣어두는건 좋은 방법이 아님.

SQL 전용 포맷을 가진 독립적인 파일을 이용하는편이 바람직

JAXB

XML에 담긴 정보를 읽어오기

장점: XML 문서정보를 거의 동일한 구조의 오브젝트로 직접 매핑

XML을 오브젝트 처럼 다룰 수 있다.

SQL 맵을 위한 스키마 작성과 컴파일

위에 XML 문서의 구조를 정의하는 스키마를 만들면..

sqlmap.xsd 파일로 저장 되고 JAXB컴파일러로 컴파일해보기

언마샬링

sqlmap.xml 이라는 이름으로 저장

Xml 문서를 읽어서 자아 오브젝트로 변환하는것을 언마샬링 이라 함.

오브젝트를 xml 로 마꾸는걸 마샬링

자바 오브젝트를 바이트 스트림으로 바꾸는걸 직렬화 라고 함.

XML 파일을 이용하는 SQL 서비스

맵 XML 파일

XML SQL 서비스

생성자에서 XML파일을 읽어서 맵에 저장,

빈의 초기화 작업

개선점

생성자에서 예외가 발생할 수도 있는 복잡한 초기화 작업은 다루지 안흔ㄴ게 좋음
-> 초기 상태를 가진 오브젝트를 만들고 별도의 초기화 메소드를 사용하자

읽어들일 파일의 위치와 이름을 코드에 고정하는건 좋지 않음

XmlSqlService 오브젝트는 빈이므로 스프링에 제어권이 있따.
생성 초기화는 스프링에게 맡겨야됨.

빈후처리기 -> 스프링컨테이너가 빈을 생성한뒤 부가적인 작업을 수행할 수 있게 해줌.

애노테이션을 이용한 빈 설정 지원해주는 몇 가지 빈 후처리기

편리한방법 context 스키마의 annotation-config 태크를 사용하면 편리함

변화를 위한 준비: 인터페이스 분리

XML 대신 다른 포맷의 파일에서 SQL을 읽어오게 하려면 어떻게 해야 할까?

XmlSqlService 단일책임원칙 위반.

책임에 따른 인터페이스 정의

분리 가능한 관심사 구분

XmlSqlService

첫째는 sQL 정보를 외부 리소스로부터 읽어오는것.

SQLdl 담겨 있는 리소스가 어떤 것이든 상관엇ㅂ이 애플리케이션에서 활용 가능하도록 메모리에 읽어들이는 것을 하나의 책임

읽어온 SQL을 보관해 뒀다가 필요할 때 제공

...

서비스를 위해서 한번 가져온 sql 을 필요에 따라 수정할 수 있게하자

SqlReader / SqlRegistry 는 각각 SQL 정보를 읽어 가져오는 방법과 이를 저장해두는 방법의 구체적인 기술과 구현으로 독립적으로 사용 하도록 만든 인터페이스.

자기참조 빈으로 시작하기 / 다중 인터페이스 구현과 간접 참조

인터페이스를 통해서만 의존 오브젝트에 접근해야 됨.

인터페이스는? 한 개 이상을 상속하는 것이 허용 됨.

인터페이스 구현은 타입을 상속 하는 것.

인터페이스를 이용한 분리

자기 참조 빈 설정

디폴트 의존관계

확장 가능한 기반 클래스

디폴트 의존관계를 갖는 빈 만들기

이런 구조도 좋지만 빈을 여러개 등록해줘야되는 불편함이 존재..

디폴트 의존관계는 자동으로 적용되는 의존관계

에러가남. sqlmapFile 프로퍼티가 비어있기때문에..

서비스 추상화 적용

JaxXmlSqlReader 개선

자바에는 JAXB 외에도 다양한 XML 과 자바오브젝트를 매핑하느 ㄴ기술이 있따

XML 파일을 좀 더 다양한 소스에서 가져올 수 있게 만든다 현재는 UserDAo 클래스와 같은 클래스패스 안에서만

XML을 읽을수 있다 이것을 임의의 클래스나 파일 스스템상의 절대위치 또는 HTTP 프로토콜을 통해

원격에서 가져오도록 확장할 수는 없는가 하는 점이다.

OXM 서비스 추상화

XML과 자바오브젝트를 매핑해서 상호 변환해 주는 기술을 OXM 이라 함.

OXM 서비스 인터페이스

JAXB 구현 테스트

Castor 구현 테스트

OXM 서비스 추상화 적용

멤버 클래스를 참조하는 통합 클래스

OxmSqlService 는 SqlReader 타입의 의존 오브젝트를 사용하되

이를 스태틱 멤버 클래스로 내장하고 자신만이 사용할 수 있도록 만들자

의존 오브젝트를 자신만이 사용하도록 독점하는 구조다

이런식으로 확장 변경을 제한두는 이유?

OXM을 이용하는 서비스 구조로 최적화하기 위해서다.

빈 의 등록과 설정은 단순해지고 쉽게 사용함


위임을 이용한 BaseSqlService의 재사용

OxmlSqlService 외형적인 틀을 유지한채 SqlService 구현은 BaseSqlService로 위임하자

프록시 이용 해도 되지만 빈을 여러개 등록해야되서 또 복잡해짐

리소스 추상화

여러가지 종류의 리소스를 어떻게 단일 인터페이스 메소드로 추상화 할까?

리소스 접근 방법이 통일되면 좋지 않을까?

리소스

애플리케이션 컨텍스트가 사용할 설정정보 파일을 지정하는 것부터 시작해서
스프링의 거의 모든 API는 외부의 리소스 정보가 필요할 때는 항 상 이 Resource 추상화를 이용

리소스 인터페이스는 빈이 아니라 값으로 취급

단순한 정보를 가진 값

리소스 로더

리로스로더의 대표적인 예 : 스프링의 애플리케이션 컨텍스트

리소스 인터페이스 상속 따라서 모든 애플리케이션 컨텍스트는 리소스 로더임

Resource를 이용해 XML 파일 가져오기

리소스를 사용할 때는 리소스오브젝트가 실제 리소스가 아님

단지 리소스에 접근할 수 있는 추상화된 핸들러.

리소스 오브젝트가 만들어져도 실제로 리소스가 존재하지 않을 수 있음.


인터페이스 상속을 통한 안전하 ㄴ기능확장

서버 가동중에 SQL 변경??

재시작을해야되는 문제점..

DI와 기능의 확장

DI의 적합한 오브젝트 설계가 필요 가치를 얻으려면..

DI를 의식하는 설계

DI 와 인터페이스 프로그래밍

인터페이스 사용하는 이유 : 다형성 때문에

인터페이스 분리 원칙을 통해 클라이언트와 의존 오브젝트 사이의 관계를 명확하게 해줄수 있기 때문.

인터페이스는 하나의 오브젝트가 여러 개를 구현할 수 있으므로 하나의 오브젝트를 바라보는 창이

여러 가지 일수 있다는 뜻.

인터페이스 분리 원칙

인터페이스 상속

하나의 오브젝트가 구현하는 인터페이스를 여러 개 만들어 구분 하는이유?

오브젝트의 기능이 발전하는 과정에서 다른 종류의 클라이언트가 나오기 때문

인터페이스 여러개 만드는것도 좋지만 상속을 통해 확장도 있따.

베이스 서비스는 기존 조회랑 등록역할만 하면되기때문에

업데이트는 새로운 클라이언트를 제공해서

만들어주자 정리하면 각각 자신의 필요에 맞는 인터페이스에만 의존..?

각각 관심과 필요에 따라서 다른 인터페이스를 통해 접근

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

실시간으로 변경 작업을 만들때 고려해야 될 사항은 동시성 문제.

자바에서 제공하는 주요 기술을 이용해 간단한 방식으로

안전한 업데이트가 가능한 SQL 레지스트리를 구성해 보자.

ConcurrentHashMap을 이용한 수중 가능 SQL 레지스트리

기존 HASHMAP은 동시성 처리하기 적합하지 않다.

수정가능 SQL 레지스트리 테스트

내장형 데이터베이스를 이용한 SQL 레지스트리 만들기

ConcurrentHashMap 대신 내장형 DB를 이용해 쿼리를 저장하고

수정하자

ConcurrentHashMap이 멀티스레드 환경에서 최소한의 동시성을 보장해주고 성능도 그리 나쁜편은 아니지만 , 저장되는 데이터양이 많아지고 잦은 조회와 변경이 일어나는 환경일때라는 한계가 있음

스프링의 내장형 DB 지원 기능

Derby ,HJSQL, H2

내장형 DB 빌더 학습테스트

내장형 디비 이기때문에 초기 테이블과 데이터를 필요에 의해 셋팅해준다.

내장형 DB를 이용해 SqlRegistry 만들기

빈으로 등록 될 수 없고 초기화 코드가 필요하면 팩토리 빈으로

EmbeddedDatabaseBuilder을 만들어 줘야됨.

UpdatableSqlRegistry 테스트 코드의 재사용

DataSource 대체하기 힘들다 그래서 EmbeddedDbSqlRegistry 도 뒤의 내장형 DB 까지 연동돼서 테스트 하는게 더 간편함

추상업데이트 테스트를 만들어주고

이전에 만들어주었던 해쉬맵 테스트와 임베디드 테스트를 상속받아서

처리했다 각 데이터베이스 생성?? 연결을 분리하기위해.

테스트에서도 이렇게 인터페이스를 분리해서 중복되기 쉬운

코드를 따로 정리해준다.

XML 설정을 통한 내장형 DB생성과 적용

트랜잭션 적용

하나 이상의 SQL 맵을 받아 수정할때 문제가 발생할 수 있음

Hash맵은 트랜잭션 개념 하기 어려움

내장형 디비는 트랜잭션 적용이 쉬움.

다중 SQL 수정에 대한 트랜잭션 테스트

트랜잭션 적용 전이라 테스트가 실패한다.

코드를 이용한 트랜잭션 적용

스프링 3.1의 DI

자바 언어의 변화와 스프링

애노테이션의 메타정보 활용

  1. 자바 코드의 메타정보를 이용한 프로그래밍 방식

자바 소스는 컴파일된후 클래스 파일에 저장됬다 JVM에 의해 메모리로 로딩되어 실행됨.

애노테이션 활용이 늘어남

핵심 로직을 담은 자바 코드와 이를 지원하는 IoC 방식의 프레임워크

그리고 프레임워크가 참조하는 메타정보라는 세가지 방식과 잘어울리기 때문

메타정보를 활용하는데 애노테이션이 적절함.

정책과 관례를 이용한 프로그래밍

애노테이션 같은 메타정보 활용하는 프로그래밍이

미리 약속한 규칙 관례를 따라서 프로그램이 동작하도록 만드는 프로그래밍 스타일을 적극적으로 포용하게 만들어옴.

애노테이션에 많은 정보함축 우선순위도 매기고..

애노테이션에 메타정보로 이용하면서 명시적으로 정보를 넣도록 하지 않았다.

코드는 간결해짐. 그러나 정책을 기억 못하거나 잘못 알고 있을 경우 의도한대로 동작하지 않는 코드가 만들어 짐..

자바 코드를 이용한 빈 설정

XML 없애기

XML -> 자바 코드로 변경하도록

테스트 컨텍스트의 변경

XML 을 최종적으로 사용하지 않게하는게 목적

@ContedxtConfiguration 스프링 테스트가 테스트용 DI 정보를 어디서 가져와야 하는지 지정할때 사용하는 애노테이션

스프링 시작점을 만들어주고..

테스트 클래스에 위치를 위에와 같이 변경해준다.

아직은 빈정보가 없기때문에 XML을 임포트해서 사용한다.

<context:annotation-config /> 제거

본격적으로 자바코드로 이동 .

이제까지 작성해왔던 DI XML

<context:annotation-config> 는 @PostConstruct를 붙인 메소드가 빈이 초기화 된후에 자동으로 실행되도록 사용함

@Configuration 사용하면 이제 필요가 없음

빈후처리기를 등록해주기 때문

Bean의 전환

@bean 으로 만들어주고 Id 는 메소드 명으로

@Autowired 가 붙은 필드의 타입과 같은 빈이 있으면 해당 빈을

필드에 자동으로 주입해줌

@Resource 태그 사용

필드 이름 기준으로 주입받고 Autowird datasource 와 혼동을
일으킬수 잇어서 리소스 어노테이션으로 받는다.

전용 태그 변환

@EnableTransactionManagement

빈 스캐닝과 자동와이어링

@Autowired를 이용한 자동와이어링

자동와이어링을 이용하면 컨테이너가 이름이나 타입을 기준으로

주입될 빈을 찾아줌. 빈의 프로퍼티 설정을 직접 해주는 자바코드나

XML의 양을 대폭 줄일 수 있다.

직접 주입 대상 지정 방식.

이방식을 자동와이어링 방식으로..

여기서는
DataSource 타입의 빈을 모두 찾는다. 두 개이상이면?
동일한 이름이 있는지 .. 빈은 2개 존재함 dataSource / embeddedDatabase 빈

그중 dataSource 빈이 수정자 메소드 프로퍼티와 이름이 일치해 넣어줌

자동 와이어링으로 sqlService 를 받으니

밑에 함수는 생략해도되고
UserDao에서는 그냥 가져오면됨

첫번째는 그림은 JdbcTemplate를 생성해서 주입해주기때문에

삭제하면 안됌

오토와이어드는 DI 코드 폭을 대폭 줄일 수있지만

빈 설정정보를 보고 다른 빈과 의존관계가 어떻게 되 어 있는가

파악하기 힘들다.

@Component를 이용한 자동 빈 등록

@Component 클래스는 클래스가 자동 빈 등록 대상이 된다..

일종의 마커라고 보면 됨..

@Component 사용하려면 빈 스캔 기능을 사용하겠다는 애노테이션 필요함

@Component가 붙은 클래스가 발견되면 새로운 빈을 추가함

빈 아이디를 따로 지정하지않으면 클래스 이름 첫 글자를 소문자로 바꿔서 사용한다.

스프링은 컴포넌트 애노테이션 외에 자동으로 빈등록이 가능하다 다른 애노테이션들로

여러 개의 애노테이션에 공통적인 속성을 부여하려면? 메타 애노테이션을 사용한다.


오토와이어드는 타입기준으로 적용할 빈을찾지만

두 개이상 발견되면 이름 기준으로 다시 찾는다.

컴포넌트 애노테이션 에 빈아이디를 지정해주자.

컨텍스트 분리와 @import

성격이 다른 DI 분리

테스트용 컨텍스트 분리

TestUserSerivce 는 UserServiceImpl 를 상속해서 만들어서

UserDa는 자동와이어링 적용 대상이라 생략해도 된다.

테스트용 빈과 실제 사용할 빈 설정정보를 딸 ㅗ분리하기때문에 컴포넌트애노테이션을 붙이지 않는다.

Import

SQL 서비스 는 그자체로 독립적인 모듈로 취급하는게 나아보임.

테스트용 설정정보는 애플리케이션 핵심 설정정보와 또 분리하는 편이 낫지만

SQL 서비스는 애플리케이션이 동작할 때 항상 필요한 정보다..

프로파일

실제 운영서버에서 작동할 메일샌더를 넣어준다.

그러나 실제 메일샌더랑 TestAppContext에 정의해둔 메일샌더랑

충돌이 일어난다.

운영 테스트 에 공통으로 사용되는 빈은 따로 컨텍스트를 분리해준다

@Profile과 @ActiveProfiles

환경에 따라서 빈 설정정보가 달라져야 하는 경우에는

파일을 여러 개로 쪼개고 조합하는 방법 대신.!

간단히 설정정보를 구성하는 기능을 제공한다.

test 프로파일의 빈 설정정보를 담은 클래스

@Profile 붙은 설정 클래스는 임포트로 가져오든 콘텍스트컨피규레이션에 직접
명시하든 상관없이 현재 컨테이너의 활성 프로파일 목록에 자신의 프로파일이름이

들어 있지 않으면 무시된다.

@ActiveProfiles 로 활성 프로파일을 지정해주자

컨테이너의 빈 등록 정보 확인

중첩 클래스를 이용한 프로파일 적용

프로파일에 따라 분리했던 설정정보를 하나의 파일로 모아보자

스태틱 중첩 클래스 이용

지정했던 클래스를 내부로 이동시킨 클래스로 변경해주자.

프로퍼티 소스

datasource DB 연결정보가 종속 되있음..

운영 개발 로컬에 같은 디비 환경은 같다 정햇을때

연결정보는 환경에 다라 다르게설정해주자

@PropertySource

컨테이너가 프로퍼티 값을 가져오는 대상을 프로퍼티 소스라고 함.

PropertySourcesPlaceholderConfigurer

@Vlue 애노테이션 이용.

이름 그대로 값을 주입받을때 ..

값을 주입받을 수 있게 치환자를 이용해주자

빈 팩토리 후처리기로 사용되는 빈을 정의해주는 것인데

이 빈 설정 메소드는 반드시 스태틱 메소드로 선언해야 한다.

빈 설정의 재사용과 @Enable*

빈 설정자

결론적으로 SQL 매핑 리소스는 빈 클래스 외부에서 설정할 수 있어야 한다.

굳이 위처럼 AppContext내 구현 빈을 만드는 방법이

DI를 따라 여러클래스 인터페이스를 생성하는것보다 나을수 있다.

@Enable*애노테이션

SQL 서비스가 필요한 애플리케이션은 메인 설정 클래스에서 @Import로
SqlServiceContext 빈 설정을 추가하고 SqlMapConfig을 구현해 SQL 매핑파일의 위치를 지정해 주면 됨.

@Import를 대체 할 애노테이션을 공부해보자

직접 애노테이션을 설정해 좀더 명확하게 어떤 서비스를 이용하는지
코드상에 노출 시킬 수 있다.

profile
어제의 나보다 한걸음 더

0개의 댓글