SpringBoot 원리 3)서블릿 컨테이너 구성
1. 서블릿 등록 & 매핑
public class HellobootApplication {
public static void main(String[] args) {
TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory(8081);
// onStartup
WebServer webServer = serverFactory.getWebServer(servletContext -> {
// interface 가 구현해야할 클래스를 람다식 형태로 넣어줌
// servletContext : ServletContextInitializer - 서블릿을 서블릿 컨테이너에 추가해주는 클래스 (서블릿을 등록하는데 필요하는 작업을 수행)
servletContext.addServlet("hello", new HttpServlet() { // 서블릿 등록
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(200); // 응답 구성 - 응답 코드
resp.setHeader("CONTENT_TYPE", "text/plain");
String name = req.getParameter("name") ;
resp.getWriter().println("Hello Servlet"+name);
// Writer : Object를 문자열 응답으로 만들어냄
}
}).addMapping("/hello"); // 서블릿 매핑
}) ;
webServer.start();
}
}
2. Front Controller 사용
public class HellobootApplication {
public static void main(String[] args) {
TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory(8081);
// onStartup
WebServer webServer = serverFactory.getWebServer(servletContext -> {
servletContext.addServlet("frontController", new HttpServlet() {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 인증, 보안, 다국어처리 ...
// 매핑
if (req.getRequestURI().equals("/hello")&&req.getMethod().equals(HttpMethod.GET.name())) {
String name = req.getParameter("name");
resp.setStatus(HttpStatus.OK.value()); // 응답 구성 - 응답 코드
resp.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE);
resp.getWriter().println("Hello Servlet" + name);
// Writer : Object를 문자열 응답으로 만들어냄
} else if (req.getRequestURI().equals("/user")) {
//
}else {
resp.setStatus(HttpStatus.NOT_FOUND.value()); // 404
}
}
}).addMapping("/*"); // 이때부터 frontController 역할을 맡게 됨
}) ;
webServer.start();
} // main
}
3. Handler 코딩 분리
FrontController 안에 모든 핸들러 코딩 구현할 순 없음)
=> 기존에 있던 HelloController 사용
public class HellobootApplication {
public static void main(String[] args) {
TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory(8081);
// onStartup
WebServer webServer = serverFactory.getWebServer(servletContext -> {
// interface 가 구현해야할 클래스를 람다식 형태로 넣어줌
// ServletContextInitializer : 서블릿을 서블릿 컨테이너에 추가해주는 클래스 (서블릿을 등록하는데 필요하는 작업을 수행)
// ㄴ servletContext
servletContext.addServlet("frontController", new HttpServlet() {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 인증, 보안, 다국어처리 ...
/* 공통기능 코딩~ */
// 매핑 : 어떤 로직을 수행하는 코드를 호출할 것인가
if (req.getRequestURI().equals("/hello")&&req.getMethod().equals(HttpMethod.GET.name())) {
// 바인딩 : 직접적으로 웹 요청과 응답을 처리하는 코드는 핸들러에 넣지 않고 (요청, 응답을 직접적으로 핸들러에 넣지않고)
// 웹 요청을 가지고 이걸 처리하는 로직 코드에서 사용할 수 있도록 새로운 자바 데이터 타입으로 웹 요청 정보를 변환해서 넣어주는것
// ex) form을 통해 다양한 정보들 -> dto로 만들어서 넘겨주는 것 !
String name = req.getParameter("name");
HelloController helloController = new HelloController();
String ret = helloController.hello(name); // HelloController안의 hello()를 실행해 문자열을 리턴받은거임
resp.setStatus(HttpStatus.OK.value()); // 응답 구성 - 응답 코드
resp.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE);
resp.getWriter().println(ret);
// Writer : Object를 문자열 응답으로 만들어냄
} else if (req.getRequestURI().equals("/user")) {
//
}else {
resp.setStatus(HttpStatus.NOT_FOUND.value()); // 404
}
}
}).addMapping("/*"); // 이때부터 frontController 역할을 맡게 됨
}) ;
webServer.start();
} // main
} // HellobootApplication
4. Dispatcher Servlet 사용
WebServer webServer = serverFactory
.getWebServer(servletContext -> {
/*servlet container 구성 시작 ~ */
// application context -> Spring container
GenericWebApplicationContext applicationContext = new GenericWebApplicationContext();
// object를 직접 만들어서 넣어줬던 servlet context와 다르게 이것도 가능하지만!
// 스프링은 일반적으로 어떤 클래스로 bean 객체를 만들건지 클래스 정보를 등록해줌 (설정 정보 등록)
applicationContext.registerBean(HelloController.class);
applicationContext.registerBean(SimpleHelloService.class);
// 자기한테 등록된 설정정보를 반영해 spring container 구성 (빈 객체 생성)
applicationContext.refresh();
/*
servletContext.addServlet("frontController"
, new HttpServlet() {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 공통기능 코딩~ : 인증, 보안, 다국어처리 ..
if (req.getRequestURI().equals("/hello")&&req.getMethod().equals(HttpMethod.GET.name())) {
String name = req.getParameter("name");
HelloController helloController = applicationContext.getBean(HelloController.class) ;
// 스프링 컨테이너 안에 HelloController 클래스 타입의 빈 객체가 하나뿐이라면 자료형만 지정해주는것만으로도 해당 빈 객체 호출
// servlet container는 helloController에 helloController 를 생성하던 뭐하던 신경쓰지 않고 그냥 스프링 컨테이너에서 갖다 씀
String ret = helloController.hello(name); // HelloController안의 hello()를 실행해 문자열을 리턴받은거임
resp.setContentType(MediaType.TEXT_PLAIN_VALUE);
resp.getWriter().println(ret); // 응답 body 에 작성
} else {
resp.setStatus(HttpStatus.NOT_FOUND.value()); // 404
}
} // service
}).addMapping("/*"); // addServlet // 이때부터 frontController 역할을 맡게 됨
*/
servletContext.addServlet("dispatcherServlet"
, new DispatcherServlet(applicationContext) {
}).addMapping("/*"); // addServlet
// 이때부터 frontController 역할을 맡게 됨
}) ; // getWebServer
5. 초기화 시점 지정
두번째 작업인 Servlet Container 를 만들고 초기화 하는 과정을 Spring Container 초기화 과정 중 일어나도록 수정 : Spring boot의 방식
GenericWebApplicationContext applicationContext = new GenericWebApplicationContext(){
// 익명 클래스
@Override
protected void onRefresh() {
super.onRefresh();
// 두번째 작업인 Servlet Container 를 만들고 초기화 하는 과정을 Spring Container 초기화 과정 중 일어나도록 수정 : Spring boot의 방식
TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory(8081);
WebServer webServer = serverFactory
.getWebServer(servletContext -> {
servletContext.addServlet("dispatcherServlet", new DispatcherServlet(this)).addMapping("/*");
// 매핑(요청 넘기기), 응답 body 작성 등 직접 코드 안해줘도 알아서 해줌 (매핑 정보만 빈객체에 작성해주면 됨)
}) ; // getWebServer
webServer.start();
} // onRefresh
};
applicationContext.registerBean(HelloController.class);
applicationContext.registerBean(SimpleHelloService.class);
applicationContext.refresh(); // 템플릿 메서드 => 훅 메서드: onRefresh
댓글남기기