web环境下的ioc容器的创建(1)

在前面的spring ioc源码分析中,我们从配置文件以及注解两方面简单分析了beanDefinition的创建以及bean的实例化过程。而目前企业开发中大都是基于web环境的。那么在web环境下,spring的ioc是在什么时候创建的?它又在什么地方起作用了?

1、从简单的ssm环境来看web环境下ioc容器的创建流程

这里环境搭建过程就省略了 将项目部署在tomcat下,然后启动tomcat

首先我们需要知道,springmvc也是基于servlet来进行web开发的。我们在web.xml中配置的DispatcherServlet就是我们请求的入口。

而对于一个servlet来说,必然会涉及他的生命周期。
init() service() destory()

很显然,springmvc肯定是在init的时候,去来初始化的ioc容器。所以我们就从init入手去看他的一个简单的流程

先来看一下DispatcherServlet的继承关系
在这里插入图片描述
直接父类就是FeameworkServlet了

DospatcherServlet的初始化

HttpServletBean  48 line

public final void init() throws ServletException {
      
        try {
            //一些配置的设置  略过
            PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
            this.initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        } catch (BeansException var4) {
            if (this.logger.isErrorEnabled()) {
                this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
            }

            throw var4;
        }

		//初始化ioc容器
        this.initServletBean();
    }

初始化ioc容器 这里只是很简单的分析下 因为重点是springmvc,并且ioc在前面spring着重分析过了 这里大概走一遍就ok 具体的细节也不会去打断点去调试的

FrameworkServlet  186 line

protected final void initServletBean() throws ServletException {
       //这里面都是打的日志  关键代码就是下面一行
        try {
         	//初始化webApplicationContext
            this.webApplicationContext = this.initWebApplicationContext();
            //空方法
            this.initFrameworkServlet();
        }
        ......
    }

上面只有一行代码是关键代码 我们先看一下WebApplicationContext的接口定义

继承ApplicationContext  多了一个获取ServletContext的方法的定义
public interface WebApplicationContext extends ApplicationContext {
    String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
    String SCOPE_REQUEST = "request";
    String SCOPE_SESSION = "session";
    String SCOPE_GLOBAL_SESSION = "globalSession";
    String SCOPE_APPLICATION = "application";
    String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
    String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
    String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
    ServletContext getServletContext();
}

继续往下走,初始化webApplicationContext

FrameworkServlet  212 line

protected WebApplicationContext initWebApplicationContext() {
		//首先根据servletContext去获取一下WebApplicationContext
		//可以看到这里用了rootContext  也就说明可能会有父子容器
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        WebApplicationContext wac = null;
        if (this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }
					//初始化ioc容器
                    this.configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
		//如果WebApplicationContext为null,在这里会根据servletContext的一些属性去获取  略过吧
        if (wac == null) {
            wac = this.findWebApplicationContext();
        }
		//如果还没有WebApplicationContext  那么就去初始化一个
        if (wac == null) {
        	//创建一个WebApplicationContext
            wac = this.createWebApplicationContext(rootContext);
        }
        ......
        return wac;
    }

创建WebApplicationContext

FrameworkServlet  266 line

protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
        Class<?> contextClass = this.getContextClass();

        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");
        } else {
        	//创建一个ConfigurableWebApplicationContext
            ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
            wac.setEnvironment(this.getEnvironment());
            wac.setParent(parent);
            //如果设置了springmvc.xml文件位置,则会在这里设置 没设置后面就用默认的
            wac.setConfigLocation(this.getContextConfigLocation());
            //初始化ioc容器
            this.configureAndRefreshWebApplicationContext(wac);
            return wac;
        }
    }

初始化ioc容器

FrameworkServlet  284 line

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
		//设置容器的id 全类名+dispatcherServlet
		//org.springframework.web.context.WebApplicationContext:/dispatcherServlet
        if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
            if (this.contextId != null) {
                wac.setId(this.contextId);
            } else {
                wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(this.getServletContext().getContextPath()) + '/' + this.getServletName());
            }
        }
		//ioc持有servletContext   那么这个web资源都可以从这里获取
        wac.setServletContext(this.getServletContext());
        wac.setServletConfig(this.getServletConfig());
        //dispatcherServlet-servlet  这个就是默认springmvc.xml的名字
        wac.setNamespace(this.getNamespace());
        //添加了一个监听器
        wac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener()));
        ConfigurableEnvironment env = wac.getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment)env).initPropertySources(this.getServletContext(), this.getServletConfig());
        }
        this.postProcessWebApplicationContext(wac);
        this.applyInitializers(wac);
        //初始化ioc容器    可以不用往下看了  这一块就是springioc的refresh方法了
        wac.refresh();
    }

简单说一下配置文件是怎么获取的

我们可以看到上面设置了wac.setNamespace(this.getNamespace()); 如果我们自己有在web.xml里面设置springmvc.xml文件的位置,就用我们自己设置的 如果没有,那么就会使用默认的
获取加载bd的xml文件的路径

this.getConfigLocations();

使用默认的路径 观察下面代码可以看到
默认的为 /WEB-INF/dispatcherServlet-servlet.xml

protected String[] getDefaultConfigLocations() {
        return this.getNamespace() != null ? new String[]{"/WEB-INF/" + this.getNamespace() + ".xml"} : new String[]{"/WEB-INF/applicationContext.xml"};
    }

那么如果nameSpace也为null,就是取/WEB-INF/applicationContext.xml

那么什么时候设置的namespace呢,通过查看源码,我们发现 其实他会取默认的servletName再拼接-servlet

FrameworkServlet   129 line

public String getNamespace() {
        return this.namespace != null ? this.namespace : this.getServletName() + "-servlet";
    }

到了这里,我们的基于springmvc的一部分bean已经加载完了,并且我们也得知了springmvc.xml需要放置的位置,以及他的命名的一些要求

还有一部分bean的加载是在哪里呢? 别忘记我们还有一个applicationContext.xml文件,那么他又是如何被加载的呢?

附带一下项目结构吧
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值