Spring源码及其原理简析(未完成待续)

Spring源码及其原理简析(未完成待续)

因为要开发新游戏问题,源码看了一半被迫中止。但是断了也一直没有动力再去续着看,所以就只好未完待续,看什么时候有动力接着看。

Spring的初始化(以ClassPathXmlApplicationContext为例)

在使用ClassPathXmlApplicationContext的时候,ClassPathXmlApplicationContext最终调用的构建方法如下:

public ClassPathXmlApplicationContext(
		String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
		throws BeansException {
	super(parent);
	setConfigLocations(configLocations);
	if (refresh) {
		refresh();
	}
}

在super(parent)里面,调用的是父类AbstractApplicationContext的构造方法,如下:

/**
 * Create a new AbstractApplicationContext with no parent.
 */
public AbstractApplicationContext() {
	this.resourcePatternResolver = getResourcePatternResolver();
}

这里面简单构建了一个资源路径的解析器,用于解析资源的具体路径,默认的解析器为PathMatchingResourcePatternResolver。之后设置了资源的路径,以及刷新上下文。refresh()具体内容如下:

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
        // 刷新前准备
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
        // 获取BeanFactory,其中包括bean的定位加载和注册
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
        // BeanFactory初始化
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
            // 资源的定位加载
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
            // bean注册
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			initMessageSource();

			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// Check for listener beans and register them.
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			finishRefresh();
		}

		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}

		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

这里面的源码,包括了BeanFactory的初始化、资源的定位加载和注册、bean的初始化以及注入等spring的基础功能,各部分的具体实现,下面介绍。

资源的定位、加载和注册

定位

加载

加载分两种加载,一种是直接定义在xml里面的标签,如果是这种bean定义的话直接调用相关的解析器进行加载,时序图如下:

另外一种是除之外的标签,例如这种自动扫描标签,如果是这个标签的话,那就调用其对应的ComponentScanBeanDefinitionParser进行解析。ComponentScanBeanDefinitionParser的初始化,是在解析xml的时候,遇到标签对应的NamespaceHandler,在其init方法里面初始化的,代码如下:

public class ContextNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
		registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
		registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
		registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
		registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
	}
}

而ContextNamespaceHandler本身的实例化,是在DefaultNamespaceHandlerResolver.resolve里面,根据spring.handlers的定义获取当前namespace对应的handler(例如http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler,这里的意思是标签对应的handler为ContextNamespaceHandler),获取到对应的handler名字,通过反射创建的,代码如下(代码有省略):

public NamespaceHandler resolve(String namespaceUri) {
	// spring.handlers对应的key和value键值对
	Map<String, Object> handlerMappings = getHandlerMappings();
	Object handlerOrClassName = handlerMappings.get(namespaceUri);
	else if (handlerOrClassName instanceof NamespaceHandler) {
		return (NamespaceHandler) handlerOrClassName;
	}
	else {
		String className = (String) handlerOrClassName;
		try {
			// 通过反射实例化handler
			Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
			if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
				throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
						"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
			}
			NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
            // 注册context里面具体的标签对应的parser
			namespaceHandler.init();
			handlerMappings.put(namespaceUri, namespaceHandler);
			return namespaceHandler;
		}
		catch (ClassNotFoundException ex) {
			...
		}
	}
}

如果是以扫描项目路径下的类的话,则是调用ComponentScanBeanDefinitionParser.parse方法进行Beandefination的加载,时序图如下:

这里插个题外话,通过自定义NamespaceHandler和BeanDefinitionParser,可以实现自定义的标签和功能并且在spring初始化的时候调用,例如我参与的第一个游戏战国之怒,平时开发的项目为业务项目,而其对应的common-resource、common-socket、ramcache等游戏基础模块,都是通过自定义namespace及其对应的handler来集成到游戏里面的,而不需要在业务服调用相关的启动模块。基础模块通过spring解析对应的标签,实例化bean之后调用,达到解耦的目的。换句话来说,只需要在spring中定义对应的xml标签,即可启动相关模块的功能,而不需要在业务项目显示调用基础模块相关代码来启动。

这是一个很好的模块化思想,xml中配置有就有,没有就没有,干干净净,增加模块化功能无须添加代码,而删除现有功能无须删除代码,只需要删除对应xml即可,功能更新的时候更是简单,把对应的xml标签内容更改了即可。

### 注册

bean的实例化及其注入

bean的销毁

bean生命周期分析

声明式事务管理

其他

你可能感兴趣的:(源码分析)