본문 바로가기
카테고리 없음

URL 경로에 따라 동적 Class 및 동적 Method 호출하기

by 철이아부지 2016. 3. 8.
요청한 URL에 따라 첫번째 Path로 Class를 로딩하여 객체를 생성한 후 두번째 path에 지정된 method를 자동 호출하는 방법이다.

web.xml 에 다음과 같이 servlet 지정
<?xml version= "1.0" encoding= "UTF-8" ?>
<! DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >
< web-app>
  < servlet>
  < servlet-name> Dynamic Servlet </ servlet-name>
  < servlet-class> com.example.DynamicServlet </servlet-class >
  < init-param>
  < param-name> controllerPackage </param-name >
  < param-value> com.example.controller </param-value >
  </ init-param>
  < load-on-startup> 1</ load-on-startup >
  </ servlet>

  < servlet-mapping>
  < servlet-name> Dynamic Servlet </ servlet-name>
  < url-pattern> /api/* </ url-pattern>
  </ servlet-mapping>

  < session-config>
  < session-timeout> 1</ session-timeout >
  </ session-config>
</ web-app>

DynamicServlet 클래스 제작
package com.example;

import java.io.IOException;
import java.lang.reflect.Method;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.text.WordUtils;

public class DynamicServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private String controllerPackage = "";

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doAction(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doAction(req, resp);
    }

    @Override
    public void destroy() {
        super.destroy();
    }

    @Override
    public void init() throws ServletException {
        controllerPackage = getServletConfig().getInitParameter("controllerPackage");
        super.init();
    }

    protected void doAction(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String[] path = req.getPathInfo().split("/");

        if( path.length <= 1 ) {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }

        Class<?> controllerClass = null;
        Method method = null;

        try {
            controllerClass = Class.forName(controllerPackage + "." + WordUtils.capitalize(path[1]) );
            method = controllerClass.getMethod(path[2], new Class[] {HttpServletRequest.class, HttpServletResponse.class});
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
            return;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
            return;
        } catch (SecurityException e) {
            e.printStackTrace();
            resp.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
            return;
        }

        Object controller = null;

        try {
            controller = controllerClass.newInstance();
            method.invoke(controller, req, resp);
        } catch (Exception e) {
            e.printStackTrace();
            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
        }
    }
}

com.example.controller.TestController 클래스를 생성하고, 인자로 (HttpServletRequest, HttpServletResponse)를 받는 testMethod 함수를 작성한다.
/dyn/testController/testMethod URL을 호출하면 com.example.controller.TestController 클래스에 대한 object를 생성한 후 testMethod 함수를 자동으로 호출한다.

동적 호출이므로 실행 시간 클래스 교체가 가능하다.