Day92 java프로그래밍 기초(Spring web MVC)
Spring web MVC
1. Servlet 등록
1) Servlet Contatiner가 시작될 때 보고 받는 객체
1) 서블릿 컨테이너를 시작한다. 2) 서블릿 컨테이너는 /WEB-INF/lib/*.jar 파일을 뒤진다. 3) /META-INF/services/javax.servlet.SerlvetContainerInitializer 파일을 찾는다. 4) 그 파일에서 ServletContainerInitializer 구현체를 알아낸다. 5) 해당 구현체의 인스턴스를 생성한 후 onStartup()을 호출한다. 6) 만약 그 구현체가 보고 받고자 하는 타입이 있다면 해당 클래스를 찾아 onStartup()을 호출할 때 파라미터로 넘겨준다.
2) WebApplicationInitializer로 Servlet 등록하기
1) 서블릿 컨테이너(예: 톰캣 서버)를 시작한다. 2) spring-web-*.jar 파일에서 /META-INF/service/javax.servlet.SerlvetContainerInitializer
파일을 읽는다. 3) 이 파일에 등록된 클래스의 인스턴스를 생성한다. => SpringServletContainerInitializer 인스턴스 생성 4) SpringServletContainerInitializer 객체에 대해 onStartup()을 호출한다. => 호출할 때 WebApplicationInitializer를 구현한 클래스 목록을 넘겨준다. 5) SpringServletContainerInitializer는 WebApplicationInitializer 구현체의 인스턴스를 만들고, onStartup()을 호출한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class WebApplicationInitializerImpl implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println("WebApplicationInitializerImpl.onStartup()...호출됨!");
// DispatcherServlet 에서 사용할 스프링 IoC 컨테이너를 준비한다.
AnnotationConfigWebApplicationContext iocContainer =
new AnnotationConfigWebApplicationContext();
// => IoC 컨테이너의 설정 정보를 갖고 있는 Java Config 클래스를 직접 지정하기
iocContainer.register(AppConfig.class);
// => Java Config 클래스가 있는 패키지를 지정하기
// 단 이럴 경우 Java Config 클래스에는 @Configuration 애노테이션이 선언되어 있어야 한다.
// iocContainer.scan("bitcamp");
iocContainer.refresh();
// DispatcherServlet 인스턴스를 생성한다.
DispatcherServlet servlet = new DispatcherServlet(iocContainer);
// 웹 애플리케이션에 DispatcherServlet을 등록한다.
Dynamic registration = servletContext.addServlet("app", servlet);
// 웹 애플리케이션에 등록된 DispatcherServlet을 설정한다.
registration.setLoadOnStartup(1);
// DispatcherServlet에 URL 패턴을 지정한다.
registration.addMapping("/app/*");
}
}
3) AbstractContextLoaderInitializer로 Servlet 등록하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class WebInit3 extends AbstractContextLoaderInitializer {
@Override
protected WebApplicationContext createRootApplicationContext() {
// ContextLoaderListener가 사용할 IoC 컨테이너를 리턴한다.
// 만약 IoC 컨테이너를 리턴하지
// ContextLoaderListener는 생성하지 않는다.
return null;
}
@Override
public void onStartup(ServletContext ctx) throws ServletException {
System.out.println("WebInit2.onStartup() 호출됨!");
/*
// 기존의 onStartup() 메서드의 기능은 그대로 수행한다.
super.onStartup(ctx);
// DispatcherServlet의 IoC 컨테이너 생성
AnnotationConfigWebApplicationContext iocContainer =
new AnnotationConfigWebApplicationContext();
iocContainer.setServletContext(ctx);
iocContainer.register(bitcamp.AppConfig.class);
// DispatcherServlet 객체 생성
DispatcherServlet frontController = new DispatcherServlet(iocContainer);
// 서블릿 컨테이너에 등록
Dynamic options = ctx.addServlet("app", frontController);
// 서블릿 설정
options.addMapping("/app/*");
*/
}
}
4) AbstractDispatcherServletInitializer로 Servlet 등록하기
AbstractDispatcherServletInitializer 클래스에서 먼저 DispatcherServlet 객체를 생성하여 등록했다. 1) ContextLoaderListener 가 사용할 IoC 컨테이너를 설정한다. => createRootApplicationContext() 메서드 오버라이딩 2) DispatcherServlet이 사용할 IoC 컨테이너를 설정한다. => createServletApplicationContext() 메서드 오버라이딩 3) DispatcherServlet에 적용할 URL 매핑을 설정한다. => getServletMappings() 메서드 오버라이딩
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
public class WebApplicationInitializerImpl extends AbstractDispatcherServletInitializer { @Override protected WebApplicationContext createRootApplicationContext() { // ContextLoaderListener 가 사용할 IoC 컨테이너를 리턴한다. // 만약 null을 리턴한다면, // 스프링 WebMVC 프레임워크는 ContextLoaderListener를 생성하지 않을 것이다. return null; } @Override protected WebApplicationContext createServletApplicationContext() { // DispatcherServlet이 사용할 IoC 컨테이너를 리턴한다. // 스프링 WebMVC 프레임워크는 DispatcherServlet을 만들 때 // 이 메서드가 리턴한 IoC 컨테이너를 DispatcherServlet에 주입할 것이다. //1) XML 기반 IoC 컨테이너를 사용할 경우, // XmlWebApplicationContext iocContainer = new XmlWebApplicationContext(); // iocContainer.setConfigLocation("/WEB-INF/app-servlet.xml"); //2) Java Config 기반 IoC 컨테이너를 사용할 경우, AnnotationConfigWebApplicationContext iocContainer = new AnnotationConfigWebApplicationContext(); iocContainer.register(AppConfig.class); return iocContainer; } @Override protected String[] getServletMappings() { return new String[] {"/app/*"}; } @Override protected String getServletName() { return "app"; } @Override public void onStartup(ServletContext servletContext) throws ServletException { // 이 메서드가 호출될 때 간단한 메시지를 출력하기 위해 오버라이딩 하였다. // 따라서 원래의 메서드를 반드시 호출해줘야 한다. System.out.println("WebApplicationInitializerImpl.onStartup()...호출됨!"); super.onStartup(servletContext); } }
5) AbstractAnnotationConfigDispatcherServletInitializer로 Servlet 등록하기
- 인터페이스를 직접 구현하는 대신에 그 인터페이스를 미리 구현한 AbstractAnnotationConfigDispatcherServletInitializer 클래스를 상속 받기
- IoC 컨테이너를 따로 설정할 필요가 없다.
DispatcherServlet을 등록하는 코드가 이미 작성되어 있기 때문에 따로 등록할 필요가 없다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
public class WebApplicationInitializerImpl extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { System.out.println("==> getRootConfigClasses()"); // ContextLoaderListener의 IoC 컨테이너가 사용할 Java Config 클래스를 리턴한다. return null; } @Override protected Class<?>[] getServletConfigClasses() { System.out.println("==> getServletConfigClasses()"); // DispatcherServlet의 IoC 컨테이너가 사용할 Java config 클래스를 리턴한다. return new Class<?>[] {AppConfig.class}; } @Override protected String[] getServletMappings() { System.out.println("==> getServletMappings()"); // DispatcherServlet을 등록할 때 이 메서드를 호출한다. // 이 메서드의 리턴 값이 리턴 값이 URL 패턴으로 사용된다. return new String[] {"/app/*"}; } @Override protected String getServletName() { System.out.println("==> getServletName()"); // DispatcherServlet을 등록할 때 이 메서드를 호출한다. // 이 메서드의 리턴 값이 서블릿의 이름으로 사용된다. // 이 메서드를 오버라이딩 하지 않으면 기본 이름("dispatcher")이 사용된다. // => 한 개만 등록할 것이라면 오버라이딩 하지 않아도 되지만, // 여러 개의 DispatcherServlet을 등록할 것이라면 오버라이딩 하여 // 반드시 이름을 다르게 해야 한다. return "app"; } @Override public void onStartup(ServletContext servletContext) throws ServletException { // 이 메서드가 호출될 때 간단한 메시지를 출력하기 위해 오버라이딩 하였다. // 따라서 원래의 메서드를 반드시 호출해줘야 한다. System.out.println("WebApplicationInitializerImpl.onStartup()...호출됨2!"); super.onStartup(servletContext); } }
6) 1 ContextLoaderListener & 2 DispatcherServlet 설정하기
ContextLoaderListener는 Servlet Container에서 공용으로 사용하기 때문에 하나의 Servlet에서 getRootConfigClasses을 설정한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
public class AppDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { // ContextLoaderListener 의 IoC 컨테이너가 사용할 Java Config 클래스를 리턴한다. return new Class<?>[] {RootConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { // DispatcherServlet 의 IoC 컨테이너가 사용할 Java Config 클래스를 리턴한다. return new Class<?>[] {AppConfig.class}; } @Override protected String[] getServletMappings() { return new String[] {"/app/*"}; } @Override protected String getServletName() { return "app"; } } //RootConfig @ComponentScan( value="bitcamp", excludeFilters = { @Filter(type = FilterType.REGEX, pattern = "bitcamp.web.*") }) public class RootConfig { } //AppConfig @ComponentScan("bitcamp.web.app") public class AppConfig { } //Admin public class AdminDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { // ContextLoaderListener 의 IoC 컨테이너가 사용할 Java Config 클래스를 리턴한다. // AppDispatcherServletInitializer 에서 이미 설정했기 때문에 // 여기서는 null을 리턴한다. return null; } @Override protected Class<?>[] getServletConfigClasses() { // DispatcherServlet 의 IoC 컨테이너가 사용할 Java Config 클래스를 리턴한다. return new Class<?>[] {AdminConfig.class}; } @Override protected String[] getServletMappings() { return new String[] {"/admin/*"}; } @Override protected String getServletName() { return "admin"; } } //AdminConfig @ComponentScan("bitcamp.web.admin") public class AdminConfig { }