spring 소스 ------spring 언제 및 언제 웹 응용 프로그램 관련 상하문을 초기화합니까 (FrameworkServlet, DispatcherServlet)

11181 단어
@[toc]  spring의 웹 응용 프로그램의 상하문은 용기가 시작될 때 초기화되는 것이 아니라 처음 요청할 때 초기화되는 것입니다.
1. Servlet사양에서 Spring으로
1.1Servlet규범 부분 설명
 spring의 웹 응용(웹-flux 포함하지 않음)은 Servlet규범을 바탕으로 구축된 것이다. 여기서 먼저 Servlet규범의 일부 내용을 설명해야 한다. 왜냐하면spring의 웹 상하문의 초기화도 여기서부터 시작되기 때문이다. Servlet는 엄격하게 정의된 생명주기에 따라 관리된다. 이 생명주기는 Servlet가 어떻게 불러오는지, 실례화, 초기화, 클라이언트 요청을 처리하는지, 그리고 언제 서비스를 종료하는지를 규정한다.이 성명 주기는 javax.servlet.Servlet 인터페이스의 init, servicedestroy 이런 API를 통해 모든Servlet이 직접적이거나 간접적으로 실현되어야 한다GenericServlet 또는 HttpServlet 추상류를 나타낼 수 있다. servlet 대상을 실례화한 후 용기는 반드시 초기화servlet한 후에야 클라이언트의 요청을 처리할 수 있습니다.초기화의 목적은 Servlet가 지속적인 설정 데이터를 읽고 대가가 높은 자원(예를 들어 JDBC™ API 연결을 초기화하거나 일회성 동작을 수행하도록 하는 것이다.용기는 호출Servlet 실례init 방법으로 초기화되었고, init 방법은 Servlet 인터페이스에 정의되어 있으며, 유일한 ServletConfig 인터페이스로 이루어진 대상을 매개 변수로 제공하며, 이 대상은 서브렛 실례마다 하나이다.
1.2 초기화된 포털 분석
  위의 규범설명에서 알 수 있듯이 스프링은 추상적인 GenericServlet 방법을 실현하고init 관련 정보를 초기화한다. init 방법의 실현류를 보면 스프링의 모든 이 방법의 실현에서 HttpServletBean만이 수요에 부합된다는 것을 알 수 있다.그래서 우리는 이 방법에 들어갔다.
2. 컨텍스트 포털 초기화HttpServletBean 여기에 직접 들어가서 HttpServletBean 실현된 init 방법을 분석한다.
    public final void init() throws ServletException {

        // Set bean properties from init parameters.
        //  ServletConfig, servlet           ,ServletConfig servlet       
        PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
        //          ,    
        if (!pvs.isEmpty()) {
            try {
                //  HttpServletBean BeanWrapper
                BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
                // ServletContext     ResourceLoader
                ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
                //  ResourceEditor    HttpServletBean 
                bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
                //      ,      
                initBeanWrapper(bw);
                // ServletConfig        HttpServletBean
                bw.setPropertyValues(pvs, true);
            }
            catch (BeansException ex) {
                if (logger.isErrorEnabled()) {
                    logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
                }
                throw ex;
            }
        }
        //     ,              ,           
        initServletBean();
    }

 실현된 논리도 비교적 간단함을 알 수 있다. ServletConfig에서 servlet 용기에서 초기화된 파라미터를 가져오는 것이다. 속성이 비어 있지 않을 때 자신의 속성 처리 논리를 정의할 수 있고 여기에서 호출된다.용기에 있는 초기화 파라미터를 처리한 후에 초기화를 진행합니다.이 초기화 방법initServletBean은 하위 클래스에 맡겨 자유롭게 초기화 논리를 실현하는 것이다.  여기 보충 설명ServletConfigServletContext 두 종류는 모두 servlet규범 중의 인터페이스 종류이다.여기서 간단하게 설명을 해드릴게요.
클래스
설명
ServletConfig
서브렛Config은 웹 응용 프로그램 구성 정보에서 제공하는 키-값 쌍의 초기화 매개변수에 서브렛이 액세스할 수 있도록 하는 각 서브렛 인스턴스 중 하나입니다.
ServletContext
서브렛Context 인터페이스는 서브렛이 실행 중인 웹 응용 프로그램의 보기를 정의합니다. 서브렛은 서브렛Context 대상을 사용하여 이벤트를 기록하고 URL 인용 자원을 가져와 현재 상하문에 있는 다른 서브렛이 접근할 수 있는 속성을 저장할 수 있습니다.기본 서브렛Context는 비분산적이며 하나의 JVM에만 저장됩니다.
3. 웹 응용 상하문 초기화FrameworkServlet 에서 언급한 initServletBean 방법은 사실 현재 스프링에서 하나의 종류만 실현되었다. 그것이 바로 FrameworkServlet이다.이 클래스는 스프링이 스프링에 적용되는 상하문에 대한 집적 클래스입니다.역할은 다음과 같습니다.
  • 는 모든 servlet 응용 프로그램에 WebApplicationContext 대상을 관리한다.
  • 요청이 성공적으로 처리되었든 안 되었든 간에 요청 처리 시 이벤트를 발표한다
  •  류도 많은 확장을 제공했는데 그 하위 클래스는 반드시 이 클래스doService 방법을 실현해야 한다.정의 초기화에서 다시 불러올 수도 있습니다. 지금 initFrameworkServlet에서 어떻게 응용의 초기화를 진행하는지 보고 바로 FrameworkServlet에 들어가서 보십시오.
        protected final void initServletBean() throws ServletException {
            //  ServletContext,  servlet     
            getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
            if (logger.isInfoEnabled()) {
                logger.info("Initializing Servlet '" + getServletName() + "'");
            }
            //        ,          
            long startTime = System.currentTimeMillis();
    
            try {
                //   web   WebApplicationContext
                this.webApplicationContext = initWebApplicationContext();
                //        ,         ,        
                initFrameworkServlet();
            }
            catch (ServletException | RuntimeException ex) {
                logger.error("Context initialization failed", ex);
                throw ex;
            }
    
            if (logger.isDebugEnabled()) {
                String value = this.enableLoggingRequestDetails ?
                        "shown which may lead to unsafe logging of potentially sensitive data" :
                        "masked to prevent unsafe logging of potentially sensitive data";
                logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
                        "': request parameters and headers will be " + value);
            }
    
            if (logger.isInfoEnabled()) {
                logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
            }
        }
    

      여기에서 간단한 몇 가지 방법의 호출만 볼 수 있고 스프링의 웹 상하문 초기화와 다른 초기화를 각각 완성했다. 그 중에서 뒤의 초기화는 논리를 스스로 정의할 수 있고 기본값은 비어 있다.여기서는 주로 상하 문장의 초기화를 본다.
        protected WebApplicationContext initWebApplicationContext() {
            //       WebApplicationContext   , ServletContext  WebApplicationContext,         WebApplicationContext.class.getName() + ".ROOT"
            WebApplicationContext rootContext =
                    WebApplicationContextUtils.getWebApplicationContext(getServletContext());
            WebApplicationContext wac = null;
            //  webApplicationContext  null,         , spring        ,       ,       true
            if (this.webApplicationContext != null) {
            
                //          
                wac = this.webApplicationContext;
                //   ConfigurableWebApplicationContext   ,     WebApplicationContext     
                if (wac instanceof ConfigurableWebApplicationContext) {
                    ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                    //             ,     ,          
                    if (!cwac.isActive()) {
                    //                
                        if (cwac.getParent() == null) {
                        
                            cwac.setParent(rootContext);
                        }
                        //     web   
                        configureAndRefreshWebApplicationContext(cwac);
                    }
                }
            }
            //  wac null,   web    null,  servlet       web   ,          FrameworkServlet.class.getName() + ".CONTEXT."+  servlet       
            if (wac == null) {
                wac = findWebApplicationContext();
            }
            //  servlet        ,     
            if (wac == null) {
                
                wac = createWebApplicationContext(rootContext);
            }
            //  onRefresh       
            if (!this.refreshEventReceived) {
            
                synchronized (this.onRefreshMonitor) {
                    //    ,             servlet     。          
                    onRefresh(wac);
                }
            }
            //          ServletContext     ,   true
            if (this.publishContext) {
                
                //          FrameworkServlet.class.getName() + ".CONTEXT."+  servlet   
                String attrName = getServletContextAttributeName();
                //         servlet    
                getServletContext().setAttribute(attrName, wac);
            }
    
            return wac;
        }
    
    

      여기서 논리의 주요 두 가지 측면에서 사용할 수 있는 웹 응용 프로그램의 상하문을 찾은 다음에 시간의 발표와 다른 리셋 작업을 진행한다.여기서 몇 가지를 설명해야 할 것은:
  • 실례화와 초기화는 차이가 있는데 여기서 방법은 초기화가 아니라 초기화
  • 정상적인 상황에서 이 방법에 들어갔을 때spring의 용기가 초기화된 후이다. 이때 전체 서비스가 일어났기 때문에 용기 안에 대응하는 웹 응용 상하문이 포함되기 때문에 위의 방법initServletBean은null
  • 이 되지 않는다.
  • 에 대응하는 웹 서비스도 활발한 상태이기 때문에 상기 방법webApplicationContext의 판단은true이다.

  •   두 번째 점에 대해 isActive가 언제 설치되었는지 설명하자면 webApplicationContext 인터페이스가 실현되었기 때문에 FrameworkServlet 실례화 후 초기화하기 전에 실현된 ApplicationContextAware 방법을 호출할 것이다.
    
        public void setApplicationContext(ApplicationContext applicationContext) {
            if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {
                this.webApplicationContext = (WebApplicationContext) applicationContext;
                this.webApplicationContextInjected = true;
            }
        }
    

      여기 FrameworkServlet에 대응하는 앞의 스프링의 생명주기에 대한 글은 스프링 소스 - 스프링의 빈 생명주기 흐름도와 코드 해석을 볼 수 있습니다.
    4.spring 관련 웹 관련 클래스 초기화setApplicationContext4.1 서브렛의 일반적인 정책 초기화
      우리는 ApplicationContextAware 중의 DispatcherServlet 방법에서 이러한 절차가 있음을 알아차렸다. 웹 응용 프로그램의 상하문을 찾은 후에 FrameworkServlet 방법이 이미 호출되었는지 검사하는 절차가 있을 것이다. 호출되지 않으면 대응하는 initWebApplicationContext 방법을 호출하고 호출되면 처리하지 않으면 어디에서 호출되었는가.지금 분석하려면 이것과 관련이 있다. onRefresh 방법은 onRefresh에서 공 논리이고 그 주요 논리는 onRefresh이류에서 진행된다.이제 안으로 들어갑니다.
        @Override
        protected void onRefresh(ApplicationContext context) {
            initStrategies(context);
        }
    
        /**
         * Initialize the strategy objects that this servlet uses.
         * 

    May be overridden in subclasses in order to initialize further strategy objects. */ protected void initStrategies(ApplicationContext context) { // MultipartResolver, bean, initMultipartResolver(context); // LocaleResolver, bean, initLocaleResolver(context); // ThemeResolver, bean, initThemeResolver(context); // handlerMapping, HandlerMapping bean initHandlerMappings(context); // HandlerAdapter, HandlerAdapter bean initHandlerAdapters(context); // HandlerExceptionResolver, HandlerExceptionResolver bean, initHandlerExceptionResolvers(context); // (url) (url) RequestToViewNameTranslator, bean, initRequestToViewNameTranslator(context); // ViewResolver , ViewResolver bean, initViewResolvers(context); // FlashMapManager, FlashMap( url , direct ) initFlashMapManager(context); }


      익숙한 것들이 많이 나오는 것 같지 않아요? 맞아요. 이게 바로springmvc 전체가 쓸 수 있는 물건이에요. 여기에 싣고 저장하고 뒤에서 처리할 때 써요.여기까지spring의 웹 응용 프로그램이 사용할 수 있는 것은 여기에서 이미 초기화되었다.

    좋은 웹페이지 즐겨찾기