spring 源碼分析 五種方式加載應用上下文

spring 加載應用上下文方式:


一、 從Web應用下的一個或多個XML配置文件中加載應用上下文

此上下文在 DispatchServlet 創建上下文時使用, 通過xml 啓動時創建web上下文.

ApplicationContext ac1 = new XmlWebApplicationContext();

FrameworkServlet.java

	/**
	 * xml啓動的 web應用上下文
	 */
	public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
	/**
	 * 默認 XmlWebApplicationContext.class
	 */
	private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;

	public Class<?> getContextClass() {
		return this.contextClass;
	}

	/**
	 * 創建web應用上下文,創建 XmlWebApplicationContext.class
	 */
	protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
		Class<?> contextClass = getContextClass();
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("error");
		}
		ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		wac.setEnvironment(getEnvironment());
		wac.setParent(parent);
		String configLocation = getContextConfigLocation();
		if (configLocation != null) {
			wac.setConfigLocation(configLocation);
		}
		//配置與刷新web應用上下文
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}
二、 從類路徑下的一個或多個XML配置文件中加載上下文定義,把應用上下文的定義文件作爲類資源

通過主動配置 xml 資源路徑, 創建應用上下文.

ApplicationContext ac2 = new ClassPathXmlApplicationContext();

ClassPathXmlApplicationContext


	// demo
	ApplicationContext context = new ClassPathXmlApplicationContext("/org/springframework/web/context/WEB-INF/applicationContext.xml");
	
	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();  // 在第二步:解析資源路徑
		}
	}

三、 從文件系統下的一個或多個XML配置中加載上下文定義

ClassPathXmlApplicationContext 相似, 在於 FileSystemXmlApplicationContext 初始化時, 可以直接url轉換 FileSystemResource 對象.

ApplicationContext ac3 = new FileSystemXmlApplicationContext();

	protected Resource getResourceByPath(String path) {
		if (path.startsWith("/")) {
			path = path.substring(1);
		}
		return new FileSystemResource(path);
	}
四、 從一個或多個基於Java的配置類中加載 應用上下文

註解配置上下文, 可通過註冊 @Configurable 註解配置的類來創建上下文,或者可通過配置掃描 package 路徑來創建上下文.

ApplicationContext ac4 = new AnnotationConfigApplicationContext();

AnnotationConfigApplicationContext

	// 註解讀取器
	private final AnnotatedBeanDefinitionReader reader;
	// 路徑掃描器
	private final ClassPathBeanDefinitionScanner scanner;
	
	/**
	 * 註冊單個或者多個Bean
	 */
	public void register(Class<?>... annotatedClasses) {
		Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
		this.reader.register(annotatedClasses);
	}

	/**
	 * 掃描給定的路徑
	 */
	public void scan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		this.scanner.scan(basePackages);
	}
五、 從一個或多個基於Java的配置類中加載 Web應用上下文

註解配置web應用上下文, 可通過註冊 @Configurable 註解配置的類來創建web上下文,或者可通過配置掃描 package 路徑來創建web上下文. 重寫 loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 方法. 實現加載操作。

ApplicationContext ac5 = new AnnotationConfigWebApplicationContext();

	/**
	 * 註冊一個或多個要處理的帶註釋的類
	 */
	public void register(Class<?>... annotatedClasses) {
		Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
		Collections.addAll(this.annotatedClasses, annotatedClasses);
	}

	/**
	 * 在指定的基本包中執行掃描
	 */
	public void scan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Collections.addAll(this.basePackages, basePackages);
	}

	/**
	 * 註冊一個{@link org.springframework.beans.factory.config.BeanDefinition}爲{@link #register(Class[])}指定的任何類,
	 * 掃描{@link #scan(String...)}指定的任何包
	 */
	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
		AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
		ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);

		BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
		if (beanNameGenerator != null) {
			reader.setBeanNameGenerator(beanNameGenerator);
			scanner.setBeanNameGenerator(beanNameGenerator);
			beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
		}

		ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
		if (scopeMetadataResolver != null) {
			reader.setScopeMetadataResolver(scopeMetadataResolver);
			scanner.setScopeMetadataResolver(scopeMetadataResolver);
		}

		if (!this.annotatedClasses.isEmpty()) {
			if (logger.isDebugEnabled()) {
				logger.debug("Registering annotated classes: [" +
						StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
			}
			reader.register(ClassUtils.toClassArray(this.annotatedClasses));
		}

		if (!this.basePackages.isEmpty()) {
			if (logger.isDebugEnabled()) {
				logger.debug("Scanning base packages: [" +
						StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
			}
			scanner.scan(StringUtils.toStringArray(this.basePackages));
		}

		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			for (String configLocation : configLocations) {
				try {
					Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
					if (logger.isTraceEnabled()) {
						logger.trace("Registering [" + configLocation + "]");
					}
					reader.register(clazz);
				}
				catch (ClassNotFoundException ex) {
					if (logger.isTraceEnabled()) {
						logger.trace("Could not load class for config location [" + configLocation +
								"] - trying package scan. " + ex);
					}
					int count = scanner.scan(configLocation);
					if (count == 0 && logger.isDebugEnabled()) {
						logger.debug("No annotated classes found for specified class/package [" + configLocation + "]");
					}
				}
			}
		}
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章