본 포스팅은 사내에서 진행하는 '자바웹프로그래밍 nextStep 7장' 스터디 내용을 정리한 내용입니다.
어플리케이션 구동시, DB 초기화하는법 (228p)
- 서블릿컨테이너는 @WebListener 어노테이션이 있는 클래스를 찾는다.
이 어노테이션이 있으면 ServeletContextListener를 구현했다는 뜻이기 때문이다. - 구현체내 contextInitalized는 웹 어플리케이션 전체에 필요한 초기화 작업을 한다. (예. DB 생성)
이는 서블릿 초기화 보다 이전에 이루어진다.
@WebListener
public class ContextLoaderListener implements ServletContextListener {
private static final Logger logger = LoggerFactory.getLogger(ContextLoaderListener.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.addScript(new ClassPathResource("jwp.sql"));
DatabasePopulatorUtils.execute(populator, ConnectionManager.getDataSource());
logger.info("Completed Load ServletContext!");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
DAO(Data Access Object) 패턴
DB 접근 로직과 비즈니스 로직을 구분.
DB 접근 객체(=DAO 객체)는 별도로 존재.
예. 전자정부의 Dao 구현법.
@Repository("studyDao")
public class StudyDao extends EgovAbstractMapper
DAO 리팩토링 방법
1. 중복코드를 없애자.
: 변화가 발생하는 부분 (개발자가 매번 구현해줘야 하는 부분)과 변화가 없는 부분(공통 라이브러리) 부분 분리 (234p)
2. SQL Exception을 RuntimeException으로 바꾸자.
: DAO를 호출하는 메소드에서 예외발생을 반드시 알아야하는 것이 아니라면 RuntimeException으로 바꾸자. (235~236p)
템플릿 메소드 패턴
정의
변하지 않는 기능은 슈퍼 클래스에 만든다.
자주 변경되며 확장할 기능은 서브 클래스에서 만들도록 한다.
한계
템플릿 내 abstract 메소드가 많을 경우, 서브클래스에서는 불필요한 메소드도 override를 해야만 한다.
(뒤에 소개될 콜백 인터페이스로 이를 보완할 수 있다)
책 코드에서 템플릿 메소드 패턴을 사용한 예제 (249~251p)
익명 객체
정의
- 이름이 없는 객체 . 클래스 상속or인터페이스 구현을 통해 사용이 가능함.
- 재사용 목적이 아니라 1번만 사용하려고 할 때 쓴다.
책의 예제에서 userDao를 위해 익명 객체가 아닌, jdbcTemplate 구현체를 만들경우,
dao객체가 늘어날 때마다 구현체를 계속 만들어야하는 불편함이 존재한다.
책의 예제 코드 (250p)
책의 예제에서 userDao를 위해 익명 객체가 아닌, jdbcTemplate 구현체를 만들경우, dao객체가 늘어날 때마다 구현체를 계속 만들어야하는 불편함이 존재한다.
-> 익명클래스를 쓰자.
public class UserDao {
public void insert(User user) throws SQLException {
JdbcTemplate template = new JdbcTemplate() {
@Override
void setValues(PreparedStatement pstmt) throws SQLException {
pstmt.setString(1, user.getUserId());
pstmt.setString(2, user.getPassword());
pstmt.setString(3, user.getName());
pstmt.setString(4, user.getEmail());
}
};
template.update("INSERT INTO USERS VALUES (?, ?, ?, ?)");
}
public void update(User user) throws SQLException {
JdbcTemplate template = new JdbcTemplate() {
@Override
void setValues(PreparedStatement pstmt) throws SQLException {
pstmt.setString(1, user.getPassword());
pstmt.setString(2, user.getName());
pstmt.setString(3, user.getEmail());
pstmt.setString(4, user.getUserId());
}
};
template.update("UPDATE USERS SET password=?,name=?,email=? WHERE userId=?");
}
// 이하 생략
콜백 인터페이스
콜백이란?
- 실행되는 것을 목적으로 다른 오브젝트의 메소드에 전달되는 오브젝트
(자바에서는 메소드 자체를 파라메터로 전달할 수 없기때문에, 메소드가 담긴 오브젝트를 전달한다)
구조 (책 예제)
위 구조에서는 클라이언트 (UserDao), 템플릿(JdbcTemplate), 콜백인터페이스(PreparedStatementSetter, RowMapper) 가 있다.
클라이언트-템플릿-콜백인터페이스의 동작 방식
1. 콜백 인터페이스 선언
@FunctionalInterface
public interface PreparedStatementSetter {
void setValues(PreparedStatement pstmt) throws SQLException;
}
2. 클라이언트
- 콜백오브젝트의 로직을 기술. (예. sql문의 파라메터 세팅)
- 템플릿의 메소드(예. update)를 호출시 파라메터로 전달
public class UserDao {
public void insert(User user) throws SQLException {
JdbcTemplate template = new JdbcTemplate() {};
template.update("INSERT INTO USERS VALUES (?, ?, ?, ?)", pstmt -> {
pstmt.setString(1, user.getUserId());
pstmt.setString(2, user.getPassword());
pstmt.setString(3, user.getName());
pstmt.setString(4, user.getEmail());
});
}
3. 템플릿
- 클라이언트에 의해 호출된 템플릿 내부의 함수 (예. update)는 로직을 따라 일을 처리.
- 콜백인스턴스(pss)는 템플릿 내부 정보(예.pstmt)+클라이언트메소드의 함수를 따라 작업 수행. 그 결과를 템플릿에 반환
- 템플릿은 콜백의 결과값을 클라이언트에 반환
public class JdbcTemplate {
public void update(String sql, PreparedStatementSetter pss) throws SQLException {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = ConnectionManager.getConnection();
pstmt = con.prepareStatement(sql);
pss.setValues(pstmt);
pstmt.executeUpdate();
} finally {
if (pstmt != null) {
pstmt.close();
}
if (con != null) {
con.close();
}
}
}
에러 처리
책에서 언급된 SQL Exception은 자바 애플리케이션에서 복구할 수 없는 경우가 대부분이다. (266p)
따라서 상위 메소드에서 exception을 계속 throw하기보다는 RunTimeException으로 받고 끝내는 것이 좋다.
에러, 예외의 개념
예외 클래스의 구조
Error vs Exception
에러 (Errpr) | 시스템에 심각한 영향. 애플리케이션 catch에서 해결 불가 (예. stackoverflow) |
예외 (Exception) | 개발자가 로직 추가하여 해결 가능 |
Checked Exception
- 컴파일 타임 익셉션으로도 불린다.
- Exccetpion을 상속하는 클래스중, RunTimeException의 서브클래스가 아니라면 모두 여기에 해당한다.
- 예) SQLException, FileNotFoundException
Unchecked Exception = RuntimeException
- 프로그램을 실행하기 전에는 발생 여부를 알 수 없는 exception.
- 예) IndexOutOfBoundsException, NullPointerException
예외 처리 방법
예외 회피, 예외 전환
Try-with-resources 구문
Java8 이후부터 AutoClosable을 상속한 클래스는 try내에서 인스턴스를 생성하면, try를 벗어날 경우 자동으로 자원 반환이 이루어진다. =>finally에서 자원 반환할 필요가 없다.
예) Connection 클래스
public void update(String sql, PreparedStatementSetter pss) throws DataAccessException {
try {
Connection con = ConnectionManager.getConnection();
PreparedStatement pstmt = con.prepareStatement(sql);
pss.setValues(pstmt);
pstmt.executeUpdate();
} catch (SQLException e) {
throw new DataAccessException(e);
}
}
Generic을 활용한 개선 (269p)
Object로 리턴할 경우 문제점
- 데이터를 조회할 때 매번 캐스팅을 해야하는 불편함.
- 잘못된 타입을 리턴할 경우를 컴파일 타임에 알 수 없다.
가변인자 (271p)
람다(272p)
정의
- 자바 8버전에서 추가
- 익명 클래스를 짧게 만듦.
함수형 인터페이스(람다 표현식으로 사용할 인터페이스)를 만드는 법
Ineterface 내부에 메소드 하나만 존재하면 됨.
** @FunctionalInterface라는 애노테이션을 붙이면, 메소드가 2개 이상이 될 경우 컴파일 에러가 나므로, 프로그래밍에 편하다.
단 이 애노테이션이 없어도, 메소드가 하나라면 JVM에서는 함수형인터페이스로 인지한다.
레퍼런스
1. 템플릿 메소드 패턴 https://yaboong.github.io/design-pattern/2018/09/27/template-method-pattern/
2. 템플릿과 콜백 https://haviyj.tistory.com/19
3. RuntimeException https://docs.oracle.com/javase/8/docs/api/?java/lang/Error.html
4. StackOverflowError https://docs.oracle.com/javase/7/docs/api/java/lang/StackOverflowError.html
5. Checked and Unchecked Exceptions in Java https://www.baeldung.com/java-checked-unchecked-exceptions
'개발 > 자바' 카테고리의 다른 글
gradle의 세팅, project structure을 왜 안 따라갈까. (0) | 2021.09.05 |
---|---|
객체를 정렬할 때-> comparable을 사용하자. (작성필요) (0) | 2021.08.26 |
9주차: 예외처리 (0) | 2021.07.04 |
6주차 과제: 상속 (0) | 2021.07.03 |
1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가 (0) | 2021.06.03 |