Spring原码解析—ContextLoaderListener

 在开始讲ContextLoaderListener之前先看看SpringMVC官方文档提供的一张上下文关系图。从图中可以看出,DispatcherServlet创建的WebApplicationContext会有一个父容器Root WebApplicationContext,而MVC层的容器一般是用来装载Controllers ViewResolver以及Web层的一组件的,Root容器是SpringIOC容器,一般是用来装载Services和Repositories等,父容器中的内容可共享给子容器而子容器中的组建不能被父容器共享。

这两个ApplicationContext都是通过ServletContext的setAttribute方法放到ServletContext中的。从web.xml的配置可知ContextLoaderListener会先于DispatcherServlet创建ApplicationContext,DispatcherServlet在创建ApplicationContext时会先找到由ContextLoaderListener所创建的ApplicationContext,再将后者的ApplicationContext作为参数传给DispatcherServlet的ApplicationContext的setParent()方法,作为它的父上下文。


首先在web.xml中配置:

接着我们来看一下ContextLoaderListener的原码:

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

	public ContextLoaderListener() {
	}

	public ContextLoaderListener(WebApplicationContext context) {
		super(context);
	}

	@Override
	public void contextInitialized(ServletContextEvent event) {
		initWebApplicationContext(event.getServletContext());
	}

	@Override
	public void contextDestroyed(ServletContextEvent event) {
		closeWebApplicationContext(event.getServletContext());
		ContextCleanupListener.cleanupAttributes(event.getServletContext());
	}
}

ContextLoaderListener实现了一个接口和继承了一个父类,并且重写了父类的contextInitialized并调用父类的initWebApplicationContext(event.getServletContext());方法。

我们继续跟进initWebApplicationContext(event.getServletContext())方法:

可以看到主要逻辑还是在createWebApplicationContext这个方法中,我们继续进去看看:

	protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
	//拿到初始化参数 配置文件
		Class<?> contextClass = determineContextClass(sc);
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
					"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
		}
		//通过类名 反射创建bean 放入bean工厂 强转为ConfigurableWebApplicationContext 创建IOC容器
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

Spring管理bean的机制:通过反射创建bean放入bean工厂,将id作为key存入hashMap中,获取时,如果是单实例bean则从map中获取,如果没有,SpringIOC容器创建。

父子容器所带来的问题:父子容器中,子容器不共享给父容器,而父容器可以共享给子容器,因此,开发中的全局配置,应放入父容器中,否则会有问题。包扫描时要区别开,如果两个容器都扫描了某给注解,那可能会出现错误。

猜你喜欢

转载自blog.csdn.net/qq_41750725/article/details/87793727