程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 詳解spring注解設置裝備擺設啟動進程

詳解spring注解設置裝備擺設啟動進程

編輯:關於JAVA

詳解spring注解設置裝備擺設啟動進程。本站提示廣大學習愛好者:(詳解spring注解設置裝備擺設啟動進程)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解spring注解設置裝備擺設啟動進程正文


       比來看起spring源碼,忽然想曉得沒有web.xml的設置裝備擺設,spring是怎樣經由過程一個繼續於AbstractAnnotationConfigDispatcherServletInitializer的類來啟動本身的。鑒於才能無限和第一次看源碼和發博客,不到的地方請望諒~

  我用的IDE是IntelliJ IDEA,這個比myEclipse看源碼便利一點,並且黑色配景挺愛好。然後項目是在maven下的tomcat7插件運轉。spring版本是4.3.2.RELEASE。 

  假如寫過純注解設置裝備擺設的spring web,應當曉得須要繼續一個初始化類來裝載bean,然後從這個類開端就會加載我們自界說的功效和bean了,上面是我的一個WebInitializer

@Order(1)
public class WebMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {
 protected Class<?>[] getRootConfigClasses() {
  return new Class[]{RootConfig.class,WebSecurityConfig.class};
 }

 protected Class<?>[] getServletConfigClasses() {
  return new Class[]{WebConfig.class};
 }

 protected String[] getServletMappings() {
  return new String[]{"/"};
 }

 @Override
 protected Filter[] getServletFilters() {
  return new Filter[]{new HiddenHttpMethodFilter()};
 }

}

  起首看下AbstractAnnotationConfigDispatcherServletInitializer類的構造,這個也是IDEA的一個uml功效,在類那邊右鍵Diagrams->show Diagrams就有啦

  然後我們直接點進AbstractAnnotationConfigDispatcherServletInitializer,可以看到這個類很簡略,只要四個辦法,然後我們存眷下createRootApplicationContext()

@Override
 protected WebApplicationContext createRootApplicationContext() {
  Class<?>[] configClasses = getRootConfigClasses();
  if (!ObjectUtils.isEmpty(configClasses)) {
   AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
   rootAppContext.register(configClasses);
   return rootAppContext;
  }
  else {
   return null;
  }
 } 

  這個辦法年夜概意思是獲得用戶(法式員)傳過去的RootClasses,然後注冊外面的bean,這些都不是我們存眷的,不外這個辦法應當是要在啟動後履行的,所以我們可以從這個辦法往上找

  IDEA下Ctrl+G可以找挪用某個辦法或類,然後設置尋覓規模為project and library

  我們找到,AbstractContextLoaderInitializer下registerContextLoaderListener(ServletContext servletContext)辦法挪用子類的createRootApplicationContext()獲得WebApplicationContext,持續找registerContextLoaderListener(ServletContext servletContext)辦法的挪用者,成果發明就是該類下的onStartup(ServletContext servletContext),上面貼下AbstractContextLoaderInitializer類

public abstract class AbstractContextLoaderInitializer implements WebApplicationInitializer {

 /** Logger available to subclasses */
 protected final Log logger = LogFactory.getLog(getClass());


 @Override
 public void onStartup(ServletContext servletContext) throws ServletException {
  registerContextLoaderListener(servletContext);
 }

 /**
  * Register a {@link ContextLoaderListener} against the given servlet context. The
  * {@code ContextLoaderListener} is initialized with the application context returned
  * from the {@link #createRootApplicationContext()} template method.
  * @param servletContext the servlet context to register the listener against
  */
 protected void registerContextLoaderListener(ServletContext servletContext) {
  WebApplicationContext rootAppContext = createRootApplicationContext();
  if (rootAppContext != null) {
   ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
   listener.setContextInitializers(getRootApplicationContextInitializers());
   servletContext.addListener(listener);
  }
  else {
   logger.debug("No ContextLoaderListener registered, as " +
     "createRootApplicationContext() did not return an application context");
  }
 }

 /**
  * Create the "<strong>root</strong>" application context to be provided to the
  * {@code ContextLoaderListener}.
  * <p>The returned context is delegated to
  * {@link ContextLoaderListener#ContextLoaderListener(WebApplicationContext)} and will
  * be established as the parent context for any {@code DispatcherServlet} application
  * contexts. As such, it typically contains middle-tier services, data sources, etc.
  * @return the root application context, or {@code null} if a root context is not
  * desired
  * @see org.springframework.web.servlet.support.AbstractDispatcherServletInitializer
  */
 protected abstract WebApplicationContext createRootApplicationContext();

 /**
  * Specify application context initializers to be applied to the root application
  * context that the {@code ContextLoaderListener} is being created with.
  * @since 4.2
  * @see #createRootApplicationContext()
  * @see ContextLoaderListener#setContextInitializers
  */
 protected ApplicationContextInitializer<?>[] getRootApplicationContextInitializers() {
  return null;
 }

}

  留意的是這裡我們跳過了AbstractDispatcherServletInitializer籠統類(看uml圖),這個類重要設置裝備擺設DispatcherServlet,這裡就是spring mvc等功效的完成了。 

  那誰來加載AbstractContextLoaderInitializer?WebApplicationInitializer曾經是接口,不會再有一個籠統類來挪用了,因而我測驗考試性地搜WebApplicationInitializer接口,由於spring這類年夜項目確定是面向接口的,所以挪用的處所普通是寫接口,然後我們找到了SpringServletContainerInitializer類,它完成了ServletContainerInitializer接口,這個類年夜概是說把一切WebApplicationInitializer都startUp一遍,可以說這個類很接近我們的目的了。上面貼下SpringServletContainerInitializer

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
 @Override
 public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
   throws ServletException {

  List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();

  if (webAppInitializerClasses != null) {
   for (Class<?> waiClass : webAppInitializerClasses) {
    // Be defensive: Some servlet containers provide us with invalid classes,
    // no matter what @HandlesTypes says...
    if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
      WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
     try {
      initializers.add((WebApplicationInitializer) waiClass.newInstance());
     }
     catch (Throwable ex) {
      throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
     }
    }
   }
  }

  if (initializers.isEmpty()) {
   servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
   return;
  }

  servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
  AnnotationAwareOrderComparator.sort(initializers);
  for (WebApplicationInitializer initializer : initializers) {
   initializer.onStartup(servletContext);
  }
 }

}
  

         在最初的foreach把一切的WebApplicationInitializer都啟動一遍。那末成績來了,誰來啟動SpringServletContainerInitializer,spring確定不克不及本身就可以啟動的,在

         web情況下,就只要web容器了。我們可以在下面某一個處所打個斷點,然後Debug一下(現實上,完整可以全程Debug = =,如許精確又快捷,不外如許少了點尋覓的意味,沿路景致照樣挺不錯的) 

  可以看到包org.apache.catalina.core下的StandardContext類的startInternal辦法,這個曾經是tomcat的規模了,所以我們的目的算是到達了。留意的是ServletContainerInitializer接口其實不是spring包下的,而是javax.servlet

  我猜想,tomcat經由過程javax.servlet的ServletContainerInitializer接口來找容器下完成這個接口的類,然後挪用它們的OnStartUp,然後spring的SpringServletContainerInitializer便可以把一切WebApplicationInitializer都啟動一遍,個中就有我們本身寫的WebInitializer,別的spring security用注解設置裝備擺設也是完成WebApplicationInitializer啟動的,所以如許spring的擴大性很強。這幾天再看下tomcat源碼,懂得下tomcat的機制。

以上就是本文的全體內容,願望對年夜家的進修有所贊助,也願望年夜家多多支撐。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved