✔️ servlet-contex.xml: 요청과 관련된 객체를 정의
url과 관련된 controller나, @(어노테이션), ViewResolver, Interceptor, MultipartResolver 등의 설정
초기 파일을 보면,
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
위와 같은 주석이 있는데 DispatcherServlet과 관련된 설정을 해야함을 알 수 있다.
✔️ root-contex.xml: view와 관련되지 않은 객체를 정의
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
기본적으로 2개의 설정파일과 2개의 ApplicationContext을 만든다.
톰캣이 시작할 때 이벤트를 체크해서 (ContextLoaderListener
) XmlWebApplicationContext()
를 생성한다.
: 만들어 줄 때 root-context.xml 설정 파일을 이용해서 만든다.
➡️ root ac
<Servlet>태그안에는 DispatcherServlet을 Servlet으로 등록한다.
: 그때 초기화하면서 servlet-context.xml 설정 파일을 이용하여 XmlWebApplicationContext()
를 또 만든다.
➡️ servlet ac
만들어진 2개의 XmlWebApplicationContext()
을 연결한다.
: 👩root ac가 부모 👶Servlet ac가 자식이 된다.
: 자식을 먼저 찾고 그 다음 부모를 찾게 되어 있다.
: 우리가 원하면 모듈별로 자식을 여러 개 둘 수 있다. 그러면 부모는 공통으로 쓰이는 빈을 넣어놓고 자식들에게는 개별적인 빈을 넣을 수 있다. 그래서 부모는 웹이랑은 관련없는 non-Web
빈을 넣는다. 자식은 각 모듈에서 사용하는 빈을 넣는다.
❗️ non-Web
: 데이터 베이스 관련 빈
ContextLoaderListener안에 initWebApplicationContext가 있는데 여기 안에 Servlet의 ac를 생성하는 코드이 있다.
servletContext는 JSP 기본 객체인 application과 동일
servletContext = ApplicationContext가 Facade패턴으로 만들어 진 것
: Facade패턴 : 복잡한 구조를 단순하게 map으로 저장 시킨 것
: 원래 context인데 캐시까지 같이 묶어서 servletContext라고 이름 지음
➡️ 실제 applicationContext는 context 밑을 보면 된다.
context 하위의 context는 다른 것이다. 상위 context는 ApplicationContext이고 하위 context는 StandardContext이다.
: 모듈과 하위 설정까지 다 합친 것이 ApplicationContext이다.
StandardContext의 Context를 의미
: 모듈 즉 프로젝트를 의미: /ch3
StandardContext(Map 형식)를 까보면 children(각각의 서블릿을 의미)이 있다.
: 그 중에 하나가 dispatcherServlet(= appServlet)이다.
package kr.ac.jipark09;
import org.springframework.beans.factory.annotation.*;
import org.springframework.context.*;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.*;
import org.springframework.stereotype.*;
import javax.inject.*;
import java.util.*;
@Component
@Scope("prototype")
class Door {}
@Component class Engine {}
@Component class TurboEngine extends Engine {}
@Component class SuperEngine extends Engine {}
@Component
class Car {
@Value("red") String color;
@Value("100") int oil;
@Autowired Engine engine;
@Autowired Door[] doors;
@Override
public String toString() {
return "Car{" +
"color='" + color + '\'' +
", oil=" + oil +
", engine=" + engine +
", doors=" + Arrays.toString(doors) +
'}';
}
}
public class ApplicationContextTest {
public static void main(String[] args) {
ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
// Car car = ac.getBean("car", Car.class); // 타입을 지정하면 형변환 안해도됨. 아래의 문장과 동일
Car car = (Car) ac.getBean("car"); // 이름으로 빈 검색
Car car2 = (Car) ac.getBean(Car.class); // 타입으로 빈 검색
System.out.println("car = " + car);
System.out.println("car2 = " + car2);
System.out.println("ac.getBeanDefinitionNames() = " + Arrays.toString(ac.getBeanDefinitionNames())); // 정의된 빈의 이름을 배열로 반환
System.out.println("ac.getBeanDefinitionCount() = " + ac.getBeanDefinitionCount()); // 정의된 빈의 개수를 반환
System.out.println("ac.containsBeanDefinition(\"car\") = " + ac.containsBeanDefinition("car")); // true 빈의 정의가 포함되어 있는지 확인
System.out.println("ac.containsBean(\"car\") = " + ac.containsBean("car")); // true 빈이 포함되어 있는지 확인
System.out.println("ac.getType(\"car\") = " + ac.getType("car")); // 빈의 이름으로 타입을 알아낼 수 있음.
System.out.println("ac.isSingleton(\"car\") = " + ac.isSingleton("car")); // true 빈이 싱글톤인지 확인
System.out.println("ac.isPrototype(\"car\") = " + ac.isPrototype("car")); // false 빈이 프로토타입인지 확인
System.out.println("ac.isPrototype(\"door\") = " + ac.isPrototype("door")); // true
System.out.println("ac.isTypeMatch(\"car\", Car.class) = " + ac.isTypeMatch("car", Car.class)); // "car"라는 이름의 빈의 타입이 Car인지 확인
System.out.println("ac.findAnnotationOnBean(\"car\", Component.class) = " + ac.findAnnotationOnBean("car", Component.class)); // 빈 car에 @Component가 붙어있으면 반환
System.out.println("ac.getBeanNamesForAnnotation(Component.class) = " + Arrays.toString(ac.getBeanNamesForAnnotation(Component.class))); // @Component가 붙은 빈의 이름을 배열로 반환
System.out.println("ac.getBeanNamesForType(Engine.class) = " + Arrays.toString(ac.getBeanNamesForType(Engine.class))); // Engine 또는 그 자손 타입인 빈의 이름을 배열로 반환
}
}
/* [src/main/resources/config.xml]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.fastcampus.ch3"/>
</beans>
[실행결과]
car = Car{color='red', oil=100, engine=kr.ac.jipark09.Engine@38ba6ce3, doors=[kr.ac.jipark09.Door@352ff4da]}
car2 = Car{color='red', oil=100, engine=kr.ac.jipark09.Engine@38ba6ce3, doors=[kr.ac.jipark09.Door@352ff4da]}
ac.getBeanDefinitionNames() = [car, door, engine, homeController, house, room, superEngine, turboEngine, window, org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalRequiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory]
ac.getBeanDefinitionCount() = 15
ac.containsBeanDefinition("car") = true
ac.containsBean("car") = true
ac.getType("car") = class kr.ac.jipark09.Car
ac.isSingleton("car") = true
ac.isPrototype("car") = false
ac.isPrototype("door") = true
ac.isTypeMatch("car", Car.class) = true
ac.findAnnotationOnBean("car", Component.class) = @org.springframework.stereotype.Component(value="")
ac.getBeanNamesForAnnotation(Component.class) = [car, door, engine, homeController, house, room, superEngine, turboEngine, window]
ac.getBeanNamesForType(Engine.class) = [engine, superEngine, turboEngine]
ac.getBeanDefinitionNames()
의 결과로 나온 window 뒤 값은, config.xml
에 나와 있는 <context:component-scan> 과 <context:annotation-config> 가 등록한 빈이다.@Component
을 붙인 클래스들이 객체로 변환돼서 나오는 것을 확인 해 볼 수 있다.✔️ 각 (root-ac & servlet-ac)ac들이 초기화가 잘 끝났는지를 잘 봐야 한다.
빨간 네모에 문구가 뜨지 않는다면 servlet-context.xml에 문제가 있는 것이다.
servletContext가 초기화를 완료하면 배포에 성공했다는 문구가 뜬다.
: deplyed: (개발 용어)배포하다.
그 뒤에 HomeController
가 실행이 된다.
Reference
: https://thiago6.tistory.com/70
: https://fastcampus.co.kr/dev_academy_nks