웹 프로그래밍을 진행하면서 Factory와 싱글톤, Beans 클래스가 이해가 잘 안 가서 이번 기회에 정리를 해보고자 마음먹었다.


일단 먼저 Beans클래스(Servlet 서블릿)에 대해서 주석과  약간의 설명을 붙여보고자 한다.


Beans 클래스는 특정 방법으로 자주 사용되는 클래스를 담아 재사용성을 높이는 방법을 말한다.


때문에 몇가지 규칙이 있는데 아래와 같다.


1. 클래스를 직렬화 시켜 클래스의 상태를 지속적으로 저장 혹은 복원해야 한다.

2. 클래스는 기본 생성자를 가지고 있어야 한다.

3. 클래스의 속성들은 get, set 혹은 표준 명명법을 따르는 메서드들을 사용해 접근할 수 있어야 한다.

4. 클래스는 필요한 이벤트 처리 메서드들을 포함하고 있어야 한다.


위키피디아 / 자바 빈즈

-https://ko.wikipedia.org/wiki/%EC%9E%90%EB%B0%94%EB%B9%88%EC%A6%88


위의 말이 어려운데 그냥 쉽게 설명하자면 


자주 사용되는 문자열을 String manyUseString = "many many using";등으로 저장하여 여기저기 쓰는 것, 

DTO, VO 등을 getter setter로 만들어 사용하는 것이 Beans를 사용하는 예시라고 보면 된다.


일단 command.properties 문서는 나중에 서블릿과 함께 다루도록 하고 

여기서는 service 클래스를 담는 Beans 클래스의 흐름을 살펴보는 것을 목표로 하자.




먼저 클래스의 흐름을 살펴보자. 


1. 재사용할 클래스를 HashMap에 담아 특정 key로 계속 불러올 수 있도록 한다.

2. Beans로 forward, redirect를 할 수 있도록 메서드를 만든다.

3. web.xml에 load-on-startup을 1로 설정하여 init-param으로 Beans클래스를 제일 먼저 생성하게 만들어 모든 서비스가 등록되게 만든다.



사실 이렇게 말로 설명하는 것보다 코드로 보는 게 한결 이해하기 쉬울 것이다.

 



import java.io.FileReader;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.Properties;

 

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

 

import com.webjjang.board.dao.BoardDAO;

 

/**

 * Servlet implementation class Beans

 */

public class Beans extends HttpServlet {

private static final long serialVersionUID = 1L;

 

// 실행해야 할 모든 서비스 객체를 저장해 놓는 Map

public static Map<String, ServiceInterface> beans = new HashMap<>();

 

// 실행해야 할 모든 DAO객체를 저장해 놓는 Map

public static Map<String, Object> daoBeans = new HashMap<>();

 

// 실행 할 서비스를 받아가는 메서드

public static ServiceInterface getService(String uri) {

return beans.get(uri); // get메서드는 HashMap 안에 있는 메서드

}// end of getService()

 

// 실행 할 DAO를 받아가는 메서드

public static Object getDAO(String uri) {

return daoBeans.get(uri);

}// end of getDAO()

 

// request받아서 URI를 리턴하는 프로그램 작성. uri를 정제하는 역할을 한다.

// 모든 Controller에서는 따로 작성하지 않고 받아가서 처리한다.

public static String getURI(HttpServletRequest request) {

// request에서 uri를 받아서 servletPath에서부터 잘라낸 값을 리턴한다.

// 여기서 /board/list, /notice/view 등의 형태로 바뀐다.

String uri = request.getRequestURI();

return uri.substring(uri.indexOf(request.getServletPath()));

}// end of getURI()

 

// 패스 설정을 위해서 기본 설정값을 선언해놓는다.

 // 설정한 패스에 모든 jsp파일이 들어가야 한다.

public static String pre = "/WEB-INF/views/";

public static String suf = ".jsp";

 

// 정제한 문자열을 forward로 연결할 jsp로 만들어주는 메서드. 패스는 /WEB-INF/views/board/list.jsp 등으로 설정된다.

public static String getJsp(String uri) {

return pre + uri.substring(0, uri.lastIndexOf(".")) + suf;

}// end of getJsp()

 

/**

 * @see Servlet#init(ServletConfig) 여기가 제일 먼저 실행이 되서 모든 객체를 생성한다.

 */

public void init() throws ServletException {

// TODO Auto-generated method stub

 

// ========== dao 생성해서 저장하는 처리문. - 모든 DAO 프로그램을 다 생성해 놓는다.

daoBeans.put("boardDAO", new BoardDAO()); // 키가 boardDAO, 값이 BoardDAO()객체이다.

 

// ========== service를 생성해서 저장하는 프로그램 작성

// web.xml에 servlet 태그 안에 init-param 태그로 정의되어 있는 정보를 받는다.

String configFile = getInitParameter("configFile"); // web.xml에 정의되어 있는 command.properties의 name이다.

// configFile(command.properties 파일)컴퓨터 절대 위치를 체크한다.

String configFilePath = getServletContext().getRealPath(configFile); // 추후 파일을 읽어서 실행시킬 것이다.

// key(String) = value(String) 값을 받아올 수 있는 객체 Properties를 이용하여 문자열로 받아낸다.

// configFile(command.properties 파일)을 읽어오려는 준비

Properties prop = new Properties();

try (FileReader fis = new FileReader(configFilePath)) { // try(자원선언) 을 하면 따로 close()로 반환을 할 필요가 없다.

// properties 파일에서부터 key=value 형식으로 저장된 모든 정보를 읽어온다.

// key: String, value: String 이기 때문에 지네릭스가 필요없다.

prop.load(fis);

} catch (Exception e) {

// TODO: handle exception

System.out.println("파일 읽기 오류");

} // end of try - catch;

 

// =====prop.load(fis)로 읽어온 commnand.properties파일을 이용하여 객체를 자동생성하게 만든다.

// prop 객체에서 key -> set -> iterator : 앞의 순서로 모든 객체를 생성하게 만든다.

Iterator<Object> keyIter = prop.keySet().iterator(); // properties 객체는 map과 유사하여 순서가 없다. key&value 형태로 운영.

// prop에 키를 입력해서 생성해야 할 객체이름을 꺼낸다.

while (keyIter.hasNext()) {

// Iterator의 지네릭스가 Object이기 때문에 String으로 캐스팅한다.

String command = (String) keyIter.next();

// command.properties에서 나온 value값을 handlerClassName[]에 저장한다.

// String으로 캐스팅을 하여 Object에서 바꿔주고 내부의 값이 :로 나눠져 있으므로 split(:)을 해준다.

String[] handlerClassName = ((String) prop.get(command)).split(":");

 

try {

// handlerClass에 command.properties에서 0번째로 담은

// 데이터(com.webjjang.board.service.서비스이름)를 담아준다.

Class<?> handlerClass = Class.forName(handlerClassName[0]);

// 자동으로 객체를 생성해서 저장한다.

// 위에서 담은 데이터를 꺼내어 newInstance()로 평소에 만드는 것처럼

ServiceInterface handlerInstance = (ServiceInterface) handlerClass.newInstance();

// key : command value <- handlerInstance - key는 boardDAO, command value는 각

// service 객체가 된다.

// beans Map에 저장

beans.put(command, handlerInstance);

// 의존성 주입(Dependency Injection) - 사용하는 프로그램을 넣어준다.(setter, 생성자)

// 생성이 된 service(handlerInstance)에 필요한 DAO를 가져와서 넣는다.

// 순서가 반대가 되어도 상관이 없는 이유는 참조형 객체이기 때문.

handlerInstance.setDAO(daoBeans.get(handlerClassName[1]));

// 인덱스 1번은 "boardDAO"이다.

 

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

} // end of try-catch;

 

} // end of while;

 

} // end of init()

 

} // end of class Beans{}




코드를 읽어보면 추상적으로 설명하는 것보다 이해하기 쉽다는 것을 알 수 있을 거라고 생각한다.


만약 위의 코드가 어렵다면 


1. web.xml, command.properties 파일이 없어서

2. Factory, Singleton pattern에 대한 이해가 부족해서

3. 자바에 대한 개념이 부족해서


라는 말을 들었다.


모두 화이팅하고 열심히 이해하려고 해보자.


난 코드를 옆에 두고 똑같이 써보니 이해가 금방 되었으니 혹시 잘 모르겠다면 따라 적는 것을 해보는 것을 추천한다.

+ Recent posts