스프링 부트로 개발을 시작했으며 지금까지 당연하게 그냥 써왔다. 이번 기회에 스프링부트에 조금더 깊게 파악해보자
=> 기존 스프링만 사용할때는 버전, 설정 등등 해결해줌
JAR
예전에는 톰캣을 따로 깔아줘야 했다. 그리고 톰캣(WAS)에서 동작하도록 서블릿 스펙에 맞춰 코드를 짜고 WAR형식으로 빌드해서 WAS에 배포함
-> 서블릿 만들고 WAR로 빌드해 WAS에 배포해야함
지금은 톰캣이 라이브러리로 내장되 있음. JAR로 빌드한다음 실행 하기만 하면 WAS도 자동실행
JAR
- JVM 위에서 직접 실행되거나 또는 다른 곳에서 사용하는 라이브러리로 제공
- 클래스와 관련 리소스를 압축한 단순한 파일
- 파일을 직접 실행할 수도 있고, 다른 곳에서 라이브러리로 사용할 수도 있다.
WAR
- WAR 파일은 웹 WAS 에 배포할 때 사용하는 파일
- 웹 애플리케이션 서버 위에서 실행되고, HTML 같은 정적 리소스와 클래스 파일을 모두 함께 포함하기 때문에 JAR와 비교해서 구조가 더 복잡하다
- WAR 구조를 지켜야 한다.
WAS 사용시 필요한것들
서블릿은 ServletContainerInitializer 라는 인터페이스 제공, 사용시 onStartup() 을 호출해 서블릿 컨테이너 초기화 진행
Set<Class<?>> c : 조금더 유연한 초기화 기능 제공
ServletContext ctx : 서블릿 컨테이너 자체의 기능 제공, 이것을 통해 서블릿 등록 가능
초기화시 WAS에게 알려줘야함
->resources/META-INF/services/jakarta.servlet.ServletContainerInitializer 라는 파일에 ServletContainerInitializer를 구현한 클래스 위치를 적어줘야함
= 서블릿 컨테이너를 통한 서블릿 등록
- 서블릿 등록 방법
- 프로그래밍 방법
- @WebServlet 방법
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("HelloServlet.service");
resp.getWriter().println("hello servlet!");
}
public interface AppInit {
void onStartup(ServletContext servletContext);
}
/**
* http://localhost:8080/hello-servlet
*/
public class AppInitV1Servlet implements AppInit {
@Override
public void onStartup(ServletContext servletContext) {
System.out.println("AppInitV1Servlet.onStartup");
//순수 서블릿 코드 등록 ServletRegistration.Dynamic helloServlet =
servletContext.addServlet("helloServlet", new HelloServlet());
helloServlet.addMapping("/hello-servlet");
} }
@WebServlet(urlPatterns = "/test")
public class TestServlet extends HttpServlet {}
@HandlesTypes(AppInit.class)
public class MyContainerInitV2 implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws
ServletException {
System.out.println("MyContainerInitV2.onStartup");
System.out.println("MyContainerInitV2 c = " + c);
System.out.println("MyContainerInitV2 container = " + ctx);
for (Class<?> appInitClass : c) {
try {
//new AppInitV1Servlet()과 같은 코드
AppInit appInit = (AppInit)
appInitClass.getDeclaredConstructor().newInstance();
appInit.onStartup(ctx);
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
}
@HandlesType로 애플리케이션 초기화 인터페이스를 정한다. 이 인터페이스 구현체들이 Set<Class<?>> c 로 들어온다
리플렉션을 사용해서 객체 생성
애플리케이션 초기화를 하면서 서블릿 컨테이너 정보가 담긴 ctx도 함께 보냄
resources/META-INF/services/jakarta.servlet.ServletContainerInitializer
->이것 또한 서블릿 WAS 에게 알려줘야함
= 서블릿을 직접 서블릿 컨테이너에 등록하고 초기화시 사용 과정
-> 서블릿 컨테이너 초기화시 인터페이스도 구현해야하고 서블릿 컨테이너에게 알려줘야 하지만 애플리케이션 초기화 같은 경우 특정 인터페이스만 구현 하면 된다.
필요사항
@Configuration
public class HelloConfig {
@Bean
public HelloController helloController() {
return new HelloController();
}
}
/**
* http://localhost:8080/spring/hello-spring
*/
public class AppInitV2Spring implements AppInit {
@Override
public void onStartup(ServletContext servletContext) {
System.out.println("AppInitV2Spring.onStartup");
//스프링 컨테이너 생성
AnnotationConfigWebApplicationContext appContext = newAnnotationConfigWebApplicationContext();
appContext.register(HelloConfig.class);
//스프링 MVC 디스패처 서블릿 생성, 스프링 컨테이너 연결
DispatcherServlet dispatcher = new DispatcherServlet(appContext);
//디스패처 서블릿을 서블릿 컨테이너에 등록 (이름 주의! dispatcherV2) ServletRegistration.Dynamic servlet =
servletContext.addServlet("dispatcherV2", dispatcher);
// /spring/* 요청이 디스패처 서블릿을 통하도록 설정
servlet.addMapping("/spring/*");
}
}
서블릿 컨테이너 > 디스패쳐 서블릿> 스프링 컨테이너 > 빈으로 등록한 컨트룰러 Config
마지막은 해당경로로 오는 요청은 DispatcherServlet을 통하도록 함
이제 요청이 오면 DispatcherServlet에서 요청에 해당하는 스프링 컨트룰러 실행
public interface WebApplicationInitializer {
void onStartup(ServletContext servletContext) throws ServletException;
}
서블릿 컨테이너 초기화, 스프링 컨테이너 초기화 및 연결 작업은 위에서 해왔던 작업으로 알수 있듯이 매우 복잡하다
스프링 MVC에서는 이미 다 처리해 놨다.
public class AppInitV3SpringMvc implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws
ServletException {
System.out.println("AppInitV3SpringMvc.onStartup");
//스프링 컨테이너 생성
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(HelloConfig.class);
//스프링 MVC 디스패처 서블릿 생성, 스프링 컨테이너 연결
DispatcherServlet dispatcher = new DispatcherServlet(appContext);
//디스패처 서블릿을 서블릿 컨테이너에 등록 (이름 주의! dispatcherV3)
ServletRegistration.Dynamic servlet =servletContext.addServlet("dispatcherV3", dispatcher);
//모든 요청이 디스패처 서블릿을 통하도록 설정
servlet.addMapping("/");
}
}