从ApplicationContext bf = new ClassPathXmlApplicationContext("applicationContextxml");说开来2
1.为刷新做上下文的环境准备prepareRefresh()方法protected void prepareRefresh() {this.startupDate = System.currentTimeMillis();//使spring容器关闭的标识置成falsethis.closed.set(false);//使spring容器成活的标识置成truethis....
解析的方法有:
prepareRefresh()
obtainFreshBeanFactory()
1.为刷新做上下文的环境准备prepareRefresh()方法
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
//使spring容器关闭的标识置成false
this.closed.set(false);
//使spring容器成活的标识置成true
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
//初始化系统环境变量
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
//检查环境变量是否为空
getEnvironment().validateRequiredProperties();
}
总结功能:
1.使spring容器关闭的标识置成false
2.使spring容器成活的标识置成true
3.初始化系统环境变量
4.检查环境变量是否为空
但默认情况下initPropertySources();方法为空,只供子类进行功能扩展,所以getEnvironment().validateRequiredProperties();方法也就没有运行重要逻辑。
2.初始化beanFactory,读取applicationContext.xml文件,使具有bean操作的所有功能
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//初始化bean工厂
refreshBeanFactory();
//获取bean工厂
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
功能:1.初始化bean工厂
2.获取bean工厂
2.1 初始化bean工厂
从abstractApplicationContext的继承关系可以看到它有俩个子类,那么是调用哪个子类中的refreshBeanFactory中的方法呢。此时我们就得回来看ClassPathXmlApplicationContext继承关系了:
可以看出ClassPathXmlApplicationContext继承于AbstractRefreshableApplicationContext。所以此时应该是调用AbstractRefreshableApplicationContext中的refreshBeanFactory方法:
protected final void refreshBeanFactory() throws BeansException {
//判断beanFactory是否创建,如果已经创建则销毁并关闭
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建beanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
//为beanFactory设置id标识
beanFactory.setSerializationId(getId());
//设置beanFactory的属性,bean是否允许重写和是否允许循环依赖
customizeBeanFactory(beanFactory);
//从applicationContext.xml文件中读取bean,并初始化基本信息。
loadBeanDefinitions(beanFactory);
//设置beanFactory ,与第一步的判断beanFactory是否已创建做呼应
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
refreshBeanFactory() 方法的功能总结如下:
1.判断beanFactory是否创建,如果已经创建则销毁并关闭
2.创建beanFactory
3.为beanFactory设置id标识
4.设置beanFactory的属性,bean是否允许重写和是否允许循环依赖
5.从applicationContext.xml文件中读取bean,并初始化基本信息。
6.设置beanFactory ,用以第一步判断beanFactory是否已创建
2.1.1判断beanFactory是否创建,如果已经创建则销毁并关闭
protected final boolean hasBeanFactory() {
//beanFactoryMonitor是对象锁,主要跟第六步形成阻塞
synchronized (this.beanFactoryMonitor) {
return (this.beanFactory != null);
}
}
销毁已创建的bean:
protected void destroyBeans() {
getBeanFactory().destroySingletons();
}
public void destroySingletons() {
super.destroySingletons();
this.manualSingletonNames.clear();
clearByTypeCache();
}
public void destroySingletons() {
if (logger.isDebugEnabled()) {
logger.debug("Destroying singletons in " + this);
}
synchronized (this.singletonObjects) {
this.singletonsCurrentlyInDestruction = true;
}
String[] disposableBeanNames;
synchronized (this.disposableBeans) {
disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
}
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
destroySingleton(disposableBeanNames[i]);
}
this.containedBeanMap.clear();
this.dependentBeanMap.clear();
this.dependenciesForBeanMap.clear();
synchronized (this.singletonObjects) {
this.singletonObjects.clear();
this.singletonFactories.clear();
this.earlySingletonObjects.clear();
this.registeredSingletons.clear();
this.singletonsCurrentlyInDestruction = false;
}
}
可以看到bean销毁实际上就是把DefaultSingletonBeanRegistry中保存bean的各容器中的元素删除了。
beanFactory关闭比较简单,就不多说了
2.1.2 创建beanFactory
实际上是创建了DefaultListableBeanFactory对象,那么为什么要创建这个beanFactory呢,我们来看看这个类的继承关系:
可以看出DefaultListableBeanFactory是XmlBeanFactory的父类,而是用来解析xml文件的。
所以在第五步使用了DefaultListableBeanFactory作为方法的参数。
2.1.3.为beanFactory设置id标识
逻辑简单,不多说了
2.1.4.设置beanFactory的属性,bean是否允许重写和是否允许循环依赖
逻辑简单,不多说了
2.1.5.从applicationContext.xml文件中读取bean,并初始化基本信息。
此时也会有多个类实现了loadBeanDefinitions方法,所以也可以从ClassPathXmlApplicationContext的继承关系判断出是AbstractXmlApplicationContext中的实现:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
//创建XmlBeanDefinitionReader,用来解析xml文件
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
//为XmlBeanDefinitionReader 设置环境,资源加载器,实体解析器
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
//初始化xmlreader,可由子类覆盖
initBeanDefinitionReader(beanDefinitionReader);
//加载bean定义
loadBeanDefinitions(beanDefinitionReader);
}
完成功能有:
1.创建XmlBeanDefinitionReader,用来解析xml文件
2.为XmlBeanDefinitionReader 设置环境,资源加载器,实体解析器
3.初始化xmlreader,可由子类覆盖
4.加载bean定义
可以看出加载bean定义是有复杂逻辑的:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
从前面分析可知,此时运行的是reader.loadBeanDefinitions(configLocations);
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (String location : locations) {
counter += loadBeanDefinitions(location);
}
return counter;
}
再是loadBeanDefinitions方法:
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//获取资源加载器
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
//通过判断资源加载器的类型来走不同的逻辑
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
//通过文件路径获取文件并封装成Resource对象
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//加载bean定义资源
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
//通过文件路径获取文件并封装成Resource对象
Resource resource = resourceLoader.getResource(location);
//加载bean定义资源
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
主要功能:
1.获取资源加载器
2.通过判断资源加载器的类型来走不同的逻辑
3.通过文件路径获取文件并封装成Resource对象
4.加载bean定义资源
获取资源加载器,逻辑简单,主要是第二步的资源加载器的类型的判断,我们先看一下资源加载接口ResourceLoader的继承关系:
可以看出具有俩个子类,这俩个子类又有非常多的实现类,那么此时是哪个呢,我们回头看一下设置属性时:beanDefinitionReader.setResourceLoader(this);那么这个this是谁呢:
显然走的是第二块else逻辑:int loadCount = loadBeanDefinitions(resource);
中间方法不写了,最后进入这个方法:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
//先从缓存中拿保存EncodedResource的set集合,没有则新建一个初始容量为4的set集合放入缓存中
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
//校验encodedResource是否有重复,重复则报错
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//拿出applicationContext.xml的流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//解析xml文件,加载bean定义
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
//encodedResource解析完后从缓存集合中删除
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
//缓存集合为空时,从threadLocal中删除缓存集合
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
此方法完成的功能:
1.先从缓存中拿保存EncodedResource的set集合,没有则新建一个初始容量为4的set集合放入缓存中
2.校验encodedResource是否有重复,重复则报错
3.拿出applicationContext.xml的流
4.解析xml文件,加载bean定义
5.encodedResource解析完后从缓存集合中删除
6.缓存集合为空时,从threadLocal中删除缓存集合
直接分析第四步:.解析xml文件,加载bean定义:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//解析xml资源封装成Document对象
Document doc = doLoadDocument(inputSource, resource);
//把document注册成bean定义
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
此方法完成的功能:
1.解析xml资源封装成Document对象
2.把document注册成bean定义
直接分析第二步:把document注册成bean定义:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//生成bean定义文件阅读器
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
//用文件阅读器注册bean定义
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
此方法完成的功能:
1.生成bean定义文件阅读器
2.用文件阅读器注册bean定义
直接分析第二步,.用文件阅读器注册bean定义:
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
此方法没干什么事,直接主要调用了doRegisterBeanDefinitions(root)方法:
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
主要功能是parseBeanDefinitions(root, this.delegate);方法:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//是不是默认的命名空间
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
//元素是不是默认的命名空间
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
此方法主要功能:
1.先判断根元素是不是默认的命名空间,走不同的分支
2.判断元素是不是默认的命名空间,走不同的分支
显然我们现在走的是默认的,非默认的是spring供大家做功能扩展的,如dubbo的各标签。我们接着分析parseDefaultElement(ele, delegate);方法:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
可以看出此时是根据不同的标签类型进行不同的解析,我们主要看解析bean的方法:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//bean定义持有对象的创建
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//装饰bean
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//注册bean
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
//发送注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
此方法的功能有:
1.bean定义持有对象的创建
2.装饰bean
3.注册bean
4.发送注册事件
2.2.1bean定义持有对象的创建
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
拿取元素的id属性
String id = ele.getAttribute(ID_ATTRIBUTE);
//拿取元素的name属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<String>();
//name属性不为空时,把用“,; ”分隔符分隔的name属性拆分放入aliases集合中
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
//如果元素即具有name属性又有id属性,那么beanName取name,否则取id
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
//没有bean定义的时候,检验beanName的唯一性
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//解析元素中关于bean定义的各种标签,如class,scope,abstract等
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
//重新生成beanName
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
//返回bean定义持有对象
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
主要功能:
1.拿取元素的id属性
2.拿取元素的name属性
3.name属性不为空时,把用“,; ”分隔符分隔的name属性拆分放入aliases集合中
4.如果元素即具有name属性又有id属性,那么beanName取name,否则取id
5.没有bean定义的时候,检验beanName的唯一性
6.解析元素中关于bean定义的各种标签,如class,scope,abstract等
7.重新生成beanName
8.返回bean定义持有对象
2.2.6解析元素中关于bean定义的各种标签,如class,scope,abstract等
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
//取出class标签的内容
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//用class和parent创建AbstractBeanDefinition,实际上是GenericBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//解析各种属性,如scope,abstract,lazy-init等
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//设置description标签的内容
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析meta元素
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析constructor-arg标签
parseConstructorArgElements(ele, bd);
//解析property标签
parsePropertyElements(ele, bd);
//解析qualifier标签
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
主要功能:
1.取出class标签的内容
2.用class和parent创建AbstractBeanDefinition,实际上是GenericBeanDefinition
3.解析各种属性,如scope,abstract,lazy-init等
4.设置description标签的内容
5.解析meta元素
6.解析constructor-arg标签
7.解析property标签
8.解析qualifier标签
至此,xml就解析完了,可以看出,每一个独立的标签都是一个类,如meta标签对应BeanMetadataAttribute,property标签对应着PropertyValue类,而且property标签中的ref也是类TypedStringValue。
更多推荐
所有评论(0)