고급자바프로그래밍 (Advanced Java Programming)
-
Upload
vladimir-dejesus -
Category
Documents
-
view
42 -
download
0
description
Transcript of 고급자바프로그래밍 (Advanced Java Programming)
1
고급자바프로그래밍(ADVANCED JAVA PROGRAMMING)
강원대학교 컴퓨터학부2012 년 가을학기담당교수 정충교
2
3 장 템플릿• 변경이 거의 일어나지 않고 일정한 패턴을
유지하는 부분• 응용에 따라 변경되는 부분
3
• 예외처리를 제대로 하지 않으면 리소스 반환이 이루어지지 않아 서버 다운 위험
• 예외처림 예• 리스트 3-2• 리스트 3-3
• 반복적으로 나타나는 예외처리 문장들을 정리해야겠다 .
4
• 리스트 3-4 UserDao 의 deleteAll 메소드
• 리스트 3-6 변하는 부분만 별로의 메소드로 추출
• 템플릿 메소드 패턴 적용
• 리스트 3-6 의 UserDao 의 makeStatement 메소드를 추상 메소드로 설정 --> UserDao 도 추상클래스가 됨
• 리스트 3-7 UserDao 의 서브클래스
3.2.2 변하는 부분과 변하지 않는 부분 분리
5
3.2.2 변하는 부분과 변하지 않는 부분 분리
템플릿 메소드 패턴을 적용한 결과
문제점• Dao 메소드마다 서브클래스를 만들어야 함• 유연성 부족 - 컴파일 시점에 이미 클래스간 관계가 고정됨
6
3.2.2 변하는 부분과 변하지 않는 부분 분리
컨텍스트에서 하는 일 - 변하지 않는 일
전략패턴의 적용
7
• StatementStategy 전략 인터페이스
• public interface StatementStrategy {• PreparedStatement makePreparedStatement(Connection c)
throws SQLException; • }
• 리스트 3-9 deleteAll 기능의 StatementStrategy 전략 클래스 DeleteAllStatement
• 리스트 3-10 deleteAll 기능의 컨텍스트
• 문제점 - 컨텍스트 내에 구체적인 전략클래스가 고정되어 있음
3.2.2 변하는 부분과 변하지 않는 부분 분리
8
DI 적용을 위한 클라이언트 / 컨텍스트 분리
그림 3-3 클라이언트가 있는 전략패턴
리스트 3-11 컨텍스트 코드 (jdbcContextWithStatementStrategy)리스트 3-12 클라이언트 역할의 deleteAll 코드
9
3.3.1 add 기능에 대해서도 동일한 패턴 적용
리스트 3-14 add 기능의 StatementStrategy 전략 클래스 AddStatement
리스트 3-15 클라이언트 역할의 add 코드
10
3.3.2 전략과 클라이언트의 동거
DeleteAllStatement, AddStatement 클래스들을 로컬클래스 혹은 익명클래스로 변환하여 클라이언트 내부에 삽입
간결하다 .
리스트 3-16리스트 3-17리스트 3-18리스트 3-19리스트 3-20
--> spring30-3.3
11
• 3.4.1 jdbcContext 의 분리• jdbcContextWithStatementStrategy 메소드를 별도의 클래스로 분리• --> 다른 Dao 에서도 사용 가능
• 리스트 3-21 별도로 분리된 JdbcContext 클래스• 리스트 3-22 클라이언트 기능만 남은 UserDao 클래스• 리스트 3-23 설정파일
• --> spring30-3.4
• UserDao 와 JdbcContext 는 서로 연관이 깊어 JdbcContext 가 다른 클래스로 대체될 가능성이 거의 없으므로 인터페이스를 통해 연결하지 않고 직접 연결함
• spring30-3.4 은 아래 두 방법 중 B 방법을 적용함A. JdbcContext 를 스프링 빈으로 등록하여 UserDao 에 DI 하는 방법B. JdbcContext 를 스프링 빈으로 등록하지 않고 UserDao 의 파라미터 setter 메소드 코드가 직접
JdbcContext 를 UserDao 에 DI 하는 방법 ( 리스트 3-24, 리스트 3-25)
3.4 컨텍스트와 DI
12
• 3.5.1 템플릿 / 콜백의 동작원리
• 프로젝트 spring30-3.4 의 기본 구조• 전략패턴 활용
• 클라이언트는 복잡하지만 일정 패턴을 갖는 작업• 전략 인터페이스를 구현한 클래스들이 익명클래스 형태로 클라이언트에게
편입됨
3.5 템플릿과 콜백
13
그림 3-7 템플릿 / 콜백 작업 흐름
14
그림 3-8 UserDao, JdbcContext, StatementStrategy 에 적용된 템플릿 / 콜백 패턴
프로젝트 spring30-3.4 코드 참고
15
• 3.5 에서 우리가 직접 만들어 사용한 템플릿• public class JdbcContext
• 스프링은 JdbcContext 와 유사한 그러나 더욱 강력한 클래스를 제공함 - JdbcTemplate
3.6 스프링의 JdbcTemplate
16
• JdbcTemplate 은 update 메소드를 지원함• (http://static.springsource.org/spring/docs/3.0.x/javadoc-api/)
• int update(PreparedStatementCreator psc) - A• int update(String sql) - B• int update(String sql, Object... args) - C
3.6 스프링의 JdbcTemplate
17
• int update(PreparedStatementCreator psc) - A• int update(String sql) - B• int update(String sql, Object... args) - C
리스트 3-46 PreparedStatementCreator 콜백을 인자로 주면서 update 호출 - A
// UserDao 의 메소드public void deleteAll( ) {
this.jdbcTemplate.update(
new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection con)
throws SQLException {
return con.prepareStatement("delete from users");
}
}
);
}
3.6 스프링의 JdbcTemplate
18
• int update(PreparedStatementCreator psc) - A• int update(String sql) - B• int update(String sql, Object... args) - C
• 리스트 3-47 sql 스트링을 인자로 주면서 update 호출 - B• JdbcTemplate 이 스스로 (sql 스트링을 참고하여 ) 콜백을 만들어 자기 자신에게
등록함
• // UserDao 의 메소드• public void deleteAll( ) {• this.jdbcTemplate.update("delete from users");• }
3.6 스프링의 JdbcTemplate
19
• add, deleteAll 의 경우 데이터베이스에 쓰기만 하면 되지만 getCount 는 데이터베이스 질의 결과를 정수로 받아와야 함
• JdbcTemplate 은 query 메소드를 지원함• (http://static.springsource.org/spring/docs/3.0.x/javadoc-api/)
• <T> T query(PreparedStatementCreator psc, ResultSetExtractor<T> rse)
• JdbcTemplate 오브젝트에게 query 메소드를 호출할 때는 두 개의 인자를 준다 . • 하나는 PreparedStatementCreator, 다른 하나는 ResultSetExtractor 이다 . • 이 두 인자들이 바로 콜백 오브젝트들이다 .
3.6.2 getCount 메소드에 JdbcTemplate 적용하기
20
• <T> T query(PreparedStatementCreator psc, ResultSetExtractor<T> rse)
• JdbcTemplate 의 query 메소드가 실행될 때 우선 PreparedStatementCreator 의 cre-atePreparedStatement 메소드가 호출 ( 콜백 ) 되고 이 호출 결과로 반환되는 Prepared-Statement 가 execute 된다 . PreparedStatement 를 execute 하면 그 결과로 ResultSet 이 반환된다 .
• query 메소드가 수행하는 두번째 작업은 ResultSetExtractor 에게 extractData 메소드를 호출 ( 콜백 ) 하는 것이다 . 이 메소드를 호출할 때 질의 결과로 얻은 ResultSet 을 인자로 준다 . 이 extractData 메소드가 반환하는 결과가 최종적으로 query 메소드의 반환값이 된다 .
3.6.2 getCount 메소드에 JdbcTemplate 적용하기
21
• <T> T query(PreparedStatementCreator psc, ResultSetExtractor<T> rse)
• <T> 는 타입 파라미터이다 . T 위치에 타입 이름이 들어갈 수 있다 . T 자리에 int 가 들어가면 query 메소드는 아래와 같은 형식으로 쓰이게 된다 .
• Integer query(PreparedStatementCreator psc, ResultSetExtractor<Integer> rse)
• 즉 , Integer 를 반환하는 ResultSetExtractor 를 사용하면 최종 query 반환 타입도 Integer 가 된다 .
3.6.2 getCount 메소드에 JdbcTemplate 적용하기
22
• <T> T query(PreparedStatementCreator psc, ResultSetExtractor<T> rse)
• PreparedStatementCreator 의 createPreparedStatement 메소드와 ResultSetEx-tractor 의 extractData 메소드가 각각 어떤 작용을 하게 할지는 익명클래스로 구현한다 .
• 리스트 3-49 JdbcTemplate 을 이용해 만든 getCount()
3.6.2 getCount 메소드에 JdbcTemplate 적용하기
23
• org.springframework.jdbc.core• Interface PreparedStatementCreator
• PreparedStatement createPreparedStatement(Connection con)• Create a statement in this connection.
• org.springframework.jdbc.core• Interface ResultSetExtractor<T>
• T extractData(ResultSet rs)• Implementations must implement this method to process the entire Result-
Set.
3.6.2 getCount 메소드에 JdbcTemplate 적용하기
24
• JdbcTemplate 는 아래 메소드를 제공한다 .• int queryForInt(String sql)
• Execute a query that results in an int value, given static SQL.
• 스스로 두 개의 콜백을 만들어 사용하고 최종 결과를 반환
• 리스트 3-50• public getCount() {• return this.jdbcTemplate.queryForInt("select count(*) from users");
25
• add, deleteAll 의 경우 데이터베이스에 쓰기만 하면 되고 , getCount 는 데이터베이스 질의 결과를 정수로 받아오면 되지만 , get 메소드는 User 객체를 반환해야 함
• JdbcTemplate 은 queryForObject 메소드를 지원함• (http://static.springsource.org/spring/docs/3.0.x/javadoc-api/)
• <T> T queryForObject(String sql, Object[] args, RowMapper<T> rowMapper)• Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the
query, mapping a single result row to a Java object via a RowMapper.
• org.springframework.jdbc.core• Interface RowMapper<T>
• T mapRow(ResultSet rs, int rowNum)• Implementations must implement this method to map each row of data in
the ResultSet.
3.6.2 get 메소드에 JdbcTemplate 적용하기
26
public User get(String id) {
return this.jdbcTemplate.queryForObject("select * from users where id = ?",
new Object[] {id}, new RowMapper<User>() {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getString("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
return user;
}
});
}
리스트 3-51 queryForObject 와 RowMapper 를 적용한 get 메소드
27
• UserDao 의 getAll 메소드는 List<User> 를 반환하도록 하면 좋을 것임
• 테스트 코드를 먼저 만든다 .• UserDaoTest 에 getAll 테스트 메소드를 구현 -- 리스트 3-52
• UserDao 의 getAll 메소드 구현 -- 리스트 3-53
• <T> List<T>• query(String sql, RowMapper<T> rowMapper)• Execute a query given static SQL, mapping each row to a Java object via a
RowMapper.
3.6.4 테이블에 있는 레코드를 모두 다 읽어오는 getAll 메소드를 UserDao 에 추가
28
• 테스트 보완• 네거티브 테스트 !
• 프로젝트 spring30-3.6.4
• 데이터베이스 드라이버 사용 , 예외처리 , 안전한 리소스 반환 등은 템플릿이 처리함• UserDao 에는 User 정보를 저장하거나 가져오는 로직만 남음• 자유로운 DataSource 선택 (DI 를 통해 ) - xml 구성설정 파일을 통해 UserDao
빈에 주입
29
• UserDao 에서는 더 이상 DataSource 를 사용하지 않으므로 UserDao 의 data-Source 프로퍼티를 없앰
• 중복제거
• 리스트 3-56 재사용 가능하도록 독립시킨 RowMapper
• 리스트 3-57 공유 userMapper 를 이용하도록 수정한 get, getAll 메소드
3.6.5 재사용 가능한 콜백의 분리
getCount {
}
UerDao
guery { ........
rs = ps.execute();
}
JdbcTemplate
createPreparedStatement() { }
PreparedStatementCreator
extractData(rs) { }
ResultSetExtractor
생성
생성
query( , )
호출(callback) PreparedStatement 반환
호출 (callback)
결과값 반환
결과값 반환
클라이언트 템플릿콜백
31
역할의 분리• UserDao
• SQL
• JdbcTemplate• JDBC API 사용• 예외처리• 리소스 반납• DB 연결 획득
32
추가적 개선1. UserMapper 를 스프링빈으로
• XML 설정 파일의 UserMapper 프로퍼티로 아래 정보 기입• User 테이블의 필드 – User 프로퍼티 매핑
• --> User 테이블이 바뀔 때 xml 파일만 수정하면 됨
2. UserDao 에 나타나는 SQL 문장을 별도의 파일로 저장하고 이를 불러 사용
• --> User 테이블이 바뀔 때 별도의 파일 수정하면 됨
33
끝