Spring閱讀源碼記錄

1、Spring的容器創建監聽器ContextLoader類中initWebapplication方法

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    // 判斷容器是否已經創建
    if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}
    if (this.context == null) {
       // 沒有創建則創建
       this.context = createWebApplicationContext(servletContext);
    }
    // 設置父容器,有則設置,並刷新自己
    if (this.context instanceof ConfigurableWebApplicationContext) {
	ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
	if (!cwac.isActive()) {
	// The context has not yet been refreshed -> provide services such as
	// setting the parent context, setting the application context id, etc
	    if (cwac.getParent() == null) {
		// The context instance was injected without an explicit parent ->
		// determine parent for root web application context, if any.
		ApplicationContext parent = loadParentContext(servletContext);
		cwac.setParent(parent);
	    }
            // 配置環境刷新容器
	    configureAndRefreshWebApplicationContext(cwac, servletContext);
	}
    }
    servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
}

2、configureAndRefreshWebAplicationContext(cwac, servletContext),其中有一個

// 去除了一些非重點代碼
	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
		wac.setServletContext(sc);
		// 獲取Spring配置文件的位置
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			wac.setConfigLocation(configLocationParam);
		}
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}
		// 定製容器(擴展點)
		customizeContext(sc, wac);
		wac.refresh();
	}

3、customizeContext(sc, wac) 自定義容器(提供擴展容器的初始化)ApplicationContextInitializer<ConfigurableApplicationContext>

ApplicationContextInitalizer中只有一個方法initialize(ConfigurableApplicationContext  applicationContext)

protected List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>>
		determineContextInitializerClasses(ServletContext servletContext) {
		List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> classes =
				new ArrayList<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>>();
		// 獲取全局初始化器對象
		String globalClassNames = servletContext.getInitParameter(GLOBAL_INITIALIZER_CLASSES_PARAM);
		if (globalClassNames != null) {
			for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {
				classes.add(loadInitializerClass(className));
			}
		}
		// 獲取本容器的初始化器
		String localClassNames = servletContext.getInitParameter(CONTEXT_INITIALIZER_CLASSES_PARAM);
		if (localClassNames != null) {
			for (String className : StringUtils.tokenizeToStringArray(localClassNames, INIT_PARAM_DELIMITERS)) {
				classes.add(loadInitializerClass(className));
			}
		}
		return classes;
	}
	
	protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
		// 獲取ServletContext中的全局初始化器 和 本容器的初始化器
		List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses =
				determineContextInitializerClasses(sc);

		for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) {
			Class<?> initializerContextClass =
					GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
			if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) {
				throw new ApplicationContextException(String.format(
						"Could not apply context initializer [%s] since its generic parameter [%s] " +
						"is not assignable from the type of application context used by this " +
						"context loader: [%s]", initializerClass.getName(), initializerContextClass.getName(),
						wac.getClass().getName()));
			}
			// 實例化初始化器並放入map中
			this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));
		}
		AnnotationAwareOrderComparator.sort(this.contextInitializers);
		for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
			// 啓動初始化器
			initializer.initialize(wac);
		}
	}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章