[Spring] root applicationContext | Servlet applicationContext

Jeini·2023년 5월 31일
0

🍃  Spring

목록 보기
17/33
post-thumbnail

💡 Root AC & Servlet AC


📎 root ac와 servlet ac 차이

✔️ servlet-contex.xml: 요청과 관련된 객체를 정의

  • url과 관련된 controller나, @(어노테이션), ViewResolver, Interceptor, MultipartResolver 등의 설정

  • 초기 파일을 보면,
    <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
    위와 같은 주석이 있는데 DispatcherServlet과 관련된 설정을 해야함을 알 수 있다.

✔️ root-contex.xml: view와 관련되지 않은 객체를 정의

  • Service, Repository(DAO), DB등 비즈니스 로직과 관련된 설정

⚒️ web.xml

<?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>
  • SpringMVC은 웹 ➡️ web.xml 관리
  1. 기본적으로 2개의 설정파일과 2개의 ApplicationContext을 만든다.

  2. 톰캣이 시작할 때 이벤트를 체크해서 (ContextLoaderListener) XmlWebApplicationContext() 를 생성한다.
    : 만들어 줄 때 root-context.xml 설정 파일을 이용해서 만든다.
    ➡️ root ac

  3. <Servlet>태그안에는 DispatcherServlet을 Servlet으로 등록한다.
    : 그때 초기화하면서 servlet-context.xml 설정 파일을 이용하여 XmlWebApplicationContext()를 또 만든다.
    ➡️ servlet ac

  4. 만들어진 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)이다.

📎 ApplicationContext 주요 메서드

✏️ 메서드 활용

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 을 붙인 클래스들이 객체로 변환돼서 나오는 것을 확인 해 볼 수 있다.

❗️ Application 연결 문제 찾기


✔️ 각 (root-ac & servlet-ac)ac들이 초기화가 잘 끝났는지를 잘 봐야 한다.

  • 빨간 네모에 문구가 뜨지 않는다면 servlet-context.xml에 문제가 있는 것이다.

  • servletContext가 초기화를 완료하면 배포에 성공했다는 문구가 뜬다.
    : deplyed: (개발 용어)배포하다.

  • 그 뒤에 HomeController 가 실행이 된다.


Reference
: https://thiago6.tistory.com/70
: https://fastcampus.co.kr/dev_academy_nks

profile
Fill in my own colorful colors🎨

0개의 댓글