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