이 포스팅은 토비의 스프링을 읽고 개인적으로 정리하는 글입니다.
템플릿
이란 바뀌는 성질이 다른 코드 중에서 변경이 거의 일어나지 않으며 일정한 패턴으로 유지되는 특성을 가진 부분을 자유롭게 변경되는 성질을 가진 부분으로부터 독립시켜서 효과적으로 활용할 수 있도록 하는 방법public void deleteAll() throws SQLException {
Connection c =dataSource.getConnection();
PreparedStatement ps =c.prepareStatement("delete from users");
ps.executeUpdate();
ps.close();
c.close();
}
.close()
를 통해 자원을 반납하기 전에 예외가 발생하면 리소스가 정상적으로 반환되지 않을 수 있다. 이렇게 Pool
에 있던 모든 리소스를 다 사용하고 반납하지 못하게 되면 리소스가 모자라다는 심각한 오류를 내며 서버가 중단될 수 있음.try-catch-finally
문법을 사용하지만 현재는 <AutoCloseable> 인터페이스
의 등장으로 인해 try-with-resources
문법을 사용하는 것이 더 효율적이다)public void deleteAll() throws SQLException {
Connection c =null;
PreparedStatement ps =null;
try {
rc =dataSource.getConnection();
ps =c.prepareStatement("delete from users");
ps.executeUpdate();
} catch (SQLException e) {
throw e;
} finally {
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
}
}
if (c != null) {
try {
c.close();
} catch (SQLException e) {
}
}
}
}
public int getCount() throws SQLException {
Connection c =null;
PreparedStatement ps =null;
ResultSet rs = null;
try {
c =dataSource.getConnection();
ps = c.prepareStatement("select count(*) from users");
rs.next();
return rs.getInt(1);
} catch (SQLException e) {
throw e;
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
if (ps != null) {
try {
ps .close();
} catch (SQLException e) {
if (c != null) {
try {
c. close();
} catch (SQLException e) {
}
}
}
}
}
}
public void deleteAll() throws SQLException {
...
try {
c =dataSource.getConnection();
ps = makeStatement(c);
ps.executeUpdate();
} catch (SQLException e)
...
}
private PreparedStatement makeStatement(Connection c) throws SQLException {
PreparedStatement ps;
ps = c.prepareStatement("delete from users");
return ps;
}
public class UserDaoDeleteAll extends UserDao {
protected PreparedStatement makeStatement(Connection c) throws SQLException {
PreparedStatement ps = c.prepareStatement("delete from users");
return ps;
}
}
템플릿 메소드 패턴
보다 유연하고 확장성이 뛰어난 것이, 오브젝트를 아예 둘로 분리하고 클래스 레벨에서는 인터페이스를 통해서만 의존하도록 만드는 전략클라이언트가 전략을 생성해 전략을 실행할 컨텍스트에 주입하는 패턴
UserDao
는 이제 JdbcContext
에 의존하고 있다. 하지만 이는 인터페이스가 아닌 구현체임.DI
는 인터페이스를 두고 구현체를 여러개 만들어 바꿔 사용하는 것이 목적이었음IoC
의 개념을 포괄하고 있으므로 DI
의 기본을 따르고 있다고 볼 수 있다.JdbcContext
를 DI
구조로 만들어야 할 이유JdbcContext
가 스프링 컨테이너의 싱글톤 레지스트리에서 관리되는 싱글톤 빈이 되기 때문!JdbcContext
가 DI
를 통해 다른 빈에 의존하고 있기 때문!DI
를 위해서는 양쪽 클래스 모두 빈으로 등록되어야 한다!UserDao
와 JdbcContext
가 매우 강하게 결합되어 있음.UserDao
내부에서 직접 DI
를 적용하는 방법!JdbcContext
를 갖고 있게 해야하기 때문이다.JdbcContext
에 대한 제어권을 스프링이 아닌 사용자가 갖고 생성과 관리를 담당하는 UserDao
에게 DI
까지 맡기는 것!UserDao
와 StatementStrategy
, JDbcContext
를 이용해 만든 코드는 일종의 전략 패턴이 적용된 것!템플릿/콜백 패턴
이라고 부른다.콜백은 실행되는 것을 목적으로 다른 오브젝트의 메소드에 전달되는 오브젝트를 말한다.
전략 패턴
의 전략과 달리 템플릿 / 콜백 패턴
의 콜백은 보통 단일 메소드 인터페이스를 사용한다. 이는 템플릿의 작업 흐름 중 특정 기능을 위해 한 번 호출되는 것이 일반적이기 때문이다.템플릿 / 콜백 패턴
에서는 매번 메소드 단위로 사용할 오브젝트를 새롭게 전달받는다는 것이 특징이며 또한 콜백 오브젝트가 내부 클래스로서 자신을 생성한 클라이언트 메소드 내의 정보를 직접 참조한다는 것도 고유한 특징이다.executeSql()
메소드를 JdbcContext
내부로 옮겨 여러곳에서 사용할 수 있도록 수정한다.템플릿 / 콜백
기능을 잘 사용할 수 있어야 한다.템플릿 / 콜백 패턴
의 후보는 try/catch/finally
블록을 사용하는 코드다.템플릿/콜백은 스프링이 객체지향 설계와 프로그래밍에 얼마나 가치를 두고 있는지를 잘 보여주는 예다! 우리는 이를 잘 사용하는 것은 물론이고 필요하면 직접 만들어서 활용할 수도 있어야 한다!