詳解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的機制。
以上就是本文的全體內容,願望對年夜家的進修有所贊助,也願望年夜家多多支撐。