springmvc流程分析,读取web.xml配置被扫描bean

DispatcherServlet-->FrameworkServlet-->HttpServletBean-->HttpServlet-->GenericServlet
父级递进,前三个是springmvc,后两个是标准sevlet-api
其实只有一个DispatcherServlet,但是有的方法是继承的,需要到上级去看具体实现,但是具体实现调用的方法,又可能是子类的方法,所以调用的方法,基本是从子类向上找,继承方法,或覆盖重写方法,使用idea的structure可以看到类的方法列表,上面按钮可以显示所有继承的方法,很方便

以下都是tomcat启动时springmvc初始化过程,方便查看执行流程

tomcat启动

根据web.xml, tomcat的org.apache.catalina.loader.ParallelWebappClassLoader加载jar包与类,以后类都是由这个加载器加载

org.springframework.web.servlet.DispatcherServlet 无参构造,引发父类构造FrameworkServlet,HttpServletBean,就是实例化对象,没有特别处理

开始标准servlet生命周期(Servlet.init(ServletConfig)),具体是GenericServlet.initinit(ServletConfig),

调用HttpServletBean.init(),先是设置web.xml中的initparam,然后是FrameworkServlet.initServletBean();

this.webApplicationContext = initWebApplicationContext();开始初始化applicationContext

wac = createWebApplicationContext(rootContext);开始创建,默认是XmlWebApplicationContext

protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) { 继续创建

configureAndRefreshWebApplicationContext(wac);开始读取xml配置刷新refresh()

wac.refresh();刷新是容器建立的开始,AbstractApplicationContext.refresh(),XmlWebApplicationContext的上级类

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();刷新bean工程就开始读取xml配置bean

refreshBeanFactory();

AbstractRefreshableApplicationContext.refreshBeanFactory()

loadBeanDefinitions(beanFactory);加载bean

AbstractXmlApplicationContext.loadBeanDefinitions(beanFactory)读取xmlbean

loadBeanDefinitions(beanDefinitionReader);

reader.loadBeanDefinitions(configResources);读取

AbstractBeanDefinitionReader.loadBeanDefinitions(Resource... resources)

loadBeanDefinitions(resource);

XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource)

return doLoadBeanDefinitions(inputSource, encodedResource.getResource());进入这个方法

return registerBeanDefinitions(doc, resource);//进入

documentReader.registerBeanDefinitions(doc, createReaderContext(resource));//xml读取并扫描bean  

DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext)

doRegisterBeanDefinitions(root);

parseBeanDefinitions(root, this.delegate);

delegate.parseCustomElement(ele);

eanDefinitionParserDelegate.parseCustomElement(Element ele, BeanDefinition containingBd)


return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

return findParserForElement(element, parserContext).parse(element, parserContext);//下面是这个的前部findParserForElement(element, parserContext)

NamespaceHandlerSupport.findParserForElement(Element element, ParserContext parserContext)

BeanDefinitionParser parser = this.parsers.get(localName);//这是上面方法内,源码中上一行就是取到xml的元素,比如component-scan,进入get方法

ComponentScanBeanDefinitionParser.parse(Element element, ParserContext parserContext)//这是上面的后部.parse(element, parserContext)

Set beanDefinitions = scanner.doScan(basePackages);//扫描配置的ase-package

ClassPathBeanDefinitionScanner.doScan(String... basePackages) 扫描

Set candidates = findCandidateComponents(basePackage);//就是找到有注解的类的class

ClassPathScanningCandidateComponentProvider.findCandidateComponents(String basePackage) 遍历查找被注解的类的class,Candidate是待选的意思
首先会生成一个匹配式,比如你web.xml配置的base-package是com.a 生成的匹配式就是classpath*:com/a/**/*.class, 主要是因为他会调用一些工具类

Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);这是接下来的一句,resourcePatternResolver就是XmlWebApplicationContext对象,XmlWebApplicationContext.getResources(String)就是AbstractApplicationContext.getResources

return this.resourcePatternResolver.getResources(locationPattern);resourcePatternResolver是PathMatchingResourcePatternResolver.getResources(String locationPattern),locationPattern就是生成的匹配式classpath*:com/a/**/*.class

return findPathMatchingResources(locationPattern);

Resource[] rootDirResources = getResources(rootDirPath);rootDirPath被处理为classpath*:com/a/

继续PathMatchingResourcePatternResolver.getResources(String locationPattern)

return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));

Set result = doFindAllClassPathResources(path);doFindAllClassPathResources里是调用classloader.getResources(),会遍历所有classpath去查找合适的,可以自己试试


,classloader就是ParallelWebappClassLoader,是调用XmlWebApplicationContext.getClassLoader,具体是上级DefaultResourceLoader初始化无参构造时,设置的,使用工具类
public DefaultResourceLoader() {
        this.classLoader = ClassUtils.getDefaultClassLoader();
    }
ClassUtils.getDefaultClassLoader

public static ClassLoader getDefaultClassLoader() {
        ClassLoader cl = null;
        try {
            cl = Thread.currentThread().getContextClassLoader();
        }
        catch (Throwable ex) {
            // Cannot access thread context ClassLoader - falling back...
        }
        if (cl == null) {
            // No thread context class loader -> use class loader of this class.
            cl = ClassUtils.class.getClassLoader();
            if (cl == null) {
                // getClassLoader() returning null indicates the bootstrap ClassLoader
                try {
                    cl = ClassLoader.getSystemClassLoader();
                }
                catch (Throwable ex) {
                    // Cannot access system ClassLoader - oh well, maybe the caller can live with null...
                }
            }
        }
        return cl;
    }
就是先从ThreadLocal获取,然后是ClassUtils类自己被哪个加载器加载,还没有就只能使用bootstrap系统加载器

你可能感兴趣的:(java)