스프링 프로젝트 시작 상세 과정(소결)

10007 단어 Spring시작 항목
1.Spring 프로젝트 를 웹 프로젝트 용기 에 넣는다(Tomcat,Jetty,JBoss)
본문 은 통용 되 는 Tomcat 를 예 로 들 었 다.

2.프로젝트 용기 가 시 작 될 때 읽 기 웹.xml 프로필 을 불 러 와 야 합 니 다.
다음 그림:

3.용 기 는 먼저 웹.xml 프로필 의 두 노드 를 읽 습 니 다.
설명:
tomcat 는 웹 용 기 를 시작 할 때 ServletContextListener 라 는 감청 기 를 시작 합 니 다.웹 용기 에 ServletContextListener 라 는 인터페이스 가 실례 화 될 때마다 웹 용 기 는 ServletContextListener 가 실례 된 대상 에 게 context Initialized()를 실행 하 는 방법 을 알려 줍 니 다.
한편,spring 프레임 워 크 는 디자인 과정 에서 ContextLoadListener 라 는 종 류 는 ServletContextListener 라 는 인 터 페 이 스 를 실현 하기 때문에 ContextLoadListener 라 는 종 류 를 예화 할 때마다 웹 용 기 는 Spring 에 contextInitialized()라 는 방법 을 실행 하 라 고 알 리 고 spring 용기 의 시작 과 생 성 과정 에 들 어 갑 니 다.
4.ContextLoaderListener 의 contextInitialized()는 spring 용기 의 시작 설정 을 실 시 했 고 initWebapplicationContext 를 호출 하여 spring 용 기 를 초기 화 합 니 다.

@Override
public void contextInitialized(ServletContextEvent event) {
  initWebApplicationContext(event.getServletContext());
}

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
  //Spring      ,spring          
  if(servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
    throw new IllegalStateException("Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!");
  } else {
    Log logger = LogFactory.getLog(ContextLoader.class);
    servletContext.log("Initializing Spring root WebApplicationContext");
    if(logger.isInfoEnabled()) {
      logger.info("Root WebApplicationContext: initialization started");
    }
 
    long startTime = System.currentTimeMillis();
 
    try {
      //  spring        (       spring   bean)
      if(this.context == null) {
        this.context = this.createWebApplicationContext(servletContext);
      }
 
      if(this.context instanceof ConfigurableWebApplicationContext) {
        ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;
        if(!cwac.isActive()) {
          if(cwac.getParent() == null) {
            ApplicationContext parent = this.loadParentContext(servletContext);
            cwac.setParent(parent);
          }
 
          //Spring       ,  spring       
          this.configureAndRefreshWebApplicationContext(cwac, servletContext);
        }
      }
 
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
      ClassLoader ccl = Thread.currentThread().getContextClassLoader();
      if(ccl == ContextLoader.class.getClassLoader()) {
        currentContext = this.context;
      } else if(ccl != null) {
        currentContextPerThread.put(ccl, this.context);
      }
 
      if(logger.isDebugEnabled()) {
        logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
      }
 
      if(logger.isInfoEnabled()) {
        long elapsedTime = System.currentTimeMillis() - startTime;
        logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
      }
 
      return this.context;
    } catch (RuntimeException var8) {
      logger.error("Context initialization failed", var8);
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8);
      throw var8;
    } catch (Error var9) {
      logger.error("Context initialization failed", var9);
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var9);
      throw var9;
    }
  }
}
5.spring 용기 생 성 이 완료 되면 bean 을 정례 화 할 준 비 를 합 니 다.Spring 용기 생 성 이 완료 되면 spring 용기 에 bean 을 불 러 올 준 비 를 합 니 다.configureAndrRefreshWebapplicationContext(cwac,servletContext)를 사용 합 니 다.bean 로드 완료 하기;

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// The application context id is still set to its original default value
			// -> assign a more useful id based on available information
			String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
			if (idParam != null) {
				wac.setId(idParam);
			}
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(sc.getContextPath()));
			}
		}
 
		wac.setServletContext(sc);
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			wac.setConfigLocation(configLocationParam);
		}
 
		// The wac environment's #initPropertySources will be called in any case when the context
		// is refreshed; do it eagerly here to ensure servlet property sources are in place for
		// use in any post-processing or initialization that occurs below prior to #refresh
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}
 
		customizeContext(sc, wac);
		wac.refresh();
	}
설명:
configureAndRefreshWebapplicationContext 에서 spring 의 프로필 을 불 러 옵 니 다.즉,웹.xml 에서에서 Spring 에 불 러 온 프로필 을 읽 습 니 다.즉,classpath:/config/applicationContext.xml;
혹시
다음 코드 를 통 해 spring 설정 을 불 러 옵 니 다.

public class Application{
 public static void main(String[] args) {
  ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/context.xml");
  ctx.start();
 }
}
기본 리 소스 로 더 를 어떻게 호출 하 는 지 생략 합 니 다.
최상 위 인터페이스 ResourceLoader 는 하나의 getResource(String location)방법 만 제공 합 니 다.자원 주소 에 따라 자원 파일 을 불 러 올 수 있 습 니 다.자원 주소 표현 식 은 다음 과 같 습 니 다.
--1.classpath:접두사 로 시작 하 는 표현 식,예 를 들 어 classpath:smart-context.xml
--2."/"로 시작 하 는 표현 식,예 를 들 어/WEB-INF/classes/smart-context.xml
--3."/"로 시작 하지 않 는 표현,예 를 들 어 WEB-INF/classes/smart-context.xml
--4.url 프로 토 콜,예:file:/D:/ANWANG-AIA/Horse-workspace/chapter 3/target/classes/smart-content.xml


Spring 은 구현 클래스 DefaultResourceLoader 를 제공 합 니 다.DefaultResourceLoader 는 상기 열거 한 기능 을 바탕 으로 개발 자 에 게 사용자 정의 확장 인터페이스 ProtocolResolver 를 제공 합 니 다.개발 자 는 이 인터페이스의 맞 춤 형 자원 표현 식 을 실현 할 수 있 습 니 다.코드 는 다음 과 같 습 니 다.

@Override
	public Resource getResource(String location) {
		Assert.notNull(location, "Location must not be null");
		for (ProtocolResolver protocolResolver : this.protocolResolvers) {    // 1
			Resource resource = protocolResolver.resolve(location, this);
			if (resource != null) {return resource;}
		}
 
		if (location.startsWith("/")) {return getResourceByPath(location);}    //2
		else if (location.startsWith(CLASSPATH_URL_PREFIX)) {           //3
			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
		}
		else {
			try {
				// Try to parse the location as a URL...
				URL url = new URL(location);               //4
				return new UrlResource(url);
			}
			catch (MalformedURLException ex) {
				// No URL -> resolve as resource path.
				return getResourceByPath(location);           //5
			}
		}
	}
단계 1,우선 확장 프로 토 콜 해상도 기로 자원 주 소 를 분석 하고 되 돌려 줍 니 다.예 를 들 어 접두사'classpath:'의 해석 을 위해 자원 해석 기 를 사용자 정의 할 수 있 습 니 다.
우선 ProtocolResolver 인터페이스 구현:

class ClasspathPreProtocolResolver implements ProtocolResolver{
           private static String CLASS_PATH_PRE="classpath:";        
        public Resource resolve(String location, ResourceLoader resourceLoader) {
           if( location.startsWith(CLASS_PATH_PRE)) {
                return new ClassPathResource(location.substring(CLASS_PATH_PRE.length()));
           }       
           return null;
        }        
    }
단계 2.location 이 슬 래 쉬 로 시작한다 고 가정 하면 이 클래스 의 getResourceByPath(String path)방법 을 호출 합 니 다.코드 는 다음 과 같 습 니 다.

protected Resource getResourceByPath(String path) {
		return new ClassPathContextResource(path, getClassLoader());
	}
절차 3.자원 표현 식 이 classpath 로 시작 하면 접두사 calsspath:의 경 로 를 차단 하고 ClassPathResource 의 구조 적 매개 변수 로 서 ClassPathResource 인 스 턴 스 를 생 성 한 후 돌아 갑 니 다.우 리 는 웹.xml 에서 다음 과 같은 설정 을 할 수 있 습 니 다.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:/config/applicationContext.xml</param-value>
</context-param>
6refresh()내부 의 실현 을 통 해 우 리 는 대체적으로 전체refresh()방법 은 전체 Spring 용기 의 초기 화 와 로드 의 모든 논 리 를 맡 았 다.이 는 Bean 공장 의 초기 화,post-processor 의 등록 과 호출,bean 의 정례 화,사건 발표 등 을 포함한다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기