一、从容器初始化分析

一、从容器初始化分析

1.实例代码

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml));

2.XmlBeanFactory初始化时序图

bf BeanFactoryTest classPathResource xmlBeanFactory reader 1 new ClassPathResource("beanFactoryTest.xml") 2 resource Resource 3 new XmlBeanFactory(resource) 3.1 loadBeanDefinitions(resource) 3.2 loadBeanDefinitionNum int 4 bf BeanFactory bf BeanFactoryTest classPathResource xmlBeanFactory reader processBeanDefinition方法逻辑

3.XmlBeanFactory的构造方法

public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);//reader-->XmlBeanDefinitionReader
	}

可以看到加载bean的逻辑都交给了XmlBeanDefinitionReader的loadBeanDefinitions方法。

4.加载Bean的时序图

XmlBeanFactory XmlBeanDefi EncodedResource InputSource 1. loadBeanDefinitions(resource) 1.1 newEncodedResource(resource) 1.2 EncodedResource 1.3 loadBeanDefinitions(encodedResource) 1.3.1 getResource() 1.3.2 resource 1.3.3 getInputStream() 1.3.4 inputStream 1.3.5 new InputSource(inputStream) 1.3.6 inputSource doLoadBeanDefinitions(inputSource,encodedResource.geResource()) XmlBeanFactory XmlBeanDefi EncodedResource InputSource processBeanDefinition方法逻辑

为什么用EncodedResource包装:允许指定用于解析文件的编码

4.1doLoadBeanDefinitions

doLoadBeanDefinitions方法中部分核心逻辑代码

Document doc = doLoadDocument(inputSource, resource);//加载xml文件并得到对应的Document
return registerBeanDefinitions(doc, resource);
4.2解析及注册BeanDefinitions
XmlBeanDefi BeanDefinition 1. createBeanDefinitionDocumentReader 2. registerBeanDefinitions(doc,createReaderContext(resource)) 2.1 this.readerContext = readerContext 2.2 Element root = doc.getDocumentElement() 2.3 doRegisterBeanDefinitions(root) XmlBeanDefi BeanDefinition processBeanDefinition方法逻辑

之前是XML加载解析的准备阶段,doRegisterBeanDefinitions(root)方法开始真正的解析

(类DefaultBeanDefinitionDocumentReader)

​ 1.先处理profile属性,通常在配置文件中部署两套配置来适用于生产环境和开发环境,通过指定profile属性来 切换配置环境。

​ 2.获取到用于解析XML bean定义的委托类BeanDefinitionParserDelegate

		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

​ 3.开始解析

		preProcessXml(root);//解析前处理,留给子类扩展实现
		parseBeanDefinitions(root, this.delegate);//进行解析
		postProcessXml(root);//解析后处理,留给子类扩展实现
4.3判断是默认标签还是自定义标签分别采用不用解析逻辑

方法parseBeanDefinitions(root,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);
		}
	}

通过代码可知如果是默认标签则调用自己的parseDefaultElement方法,如果是自定义标签则调用代理类的parseCustomElement方法。判断标砖为命名空间是否为http://www.springframework.org/schema/beans。

5.默认标签的解析

		//parseDefaultElement方法内部逻辑
		//对于import标签的处理
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		//对于alias标签的处理
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		//对于bean标签的处理
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		//对于beans标签的处理
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
5.1bean标签的解析及注册
DefaultBeanDefini BeanDefinition BeanDefiniti 1.1 deelegate.parseBeanDefinitionElement(ele) 1.2 BeanDefinitionHolder bdHolder 1.3 decorateBeanDefinitionIfRequired(ele,bdHolder) 1.4 bdHolder 1.5 registerBeanDefinition(bdHolder,getReaderContext().getRegistry()) 1.6 getReaderContext().fireComponmentRegistered(new BeanComponentDefinition(bdHolder)) DefaultBeanDefini BeanDefinition BeanDefiniti processBeanDefinition方法逻辑

1.1首先委托delegate类进行元素解析;

1.2返回BeanDefinitionHolder实例,此时bdHolder已经包含了配置文件中配置的各种属性例如class、name、id、alias之类的属性;

1.3当返回bdHolder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析;

1.4返回装饰后的bdHolder;

1.5委托BeanDefinitionUtils向Register容器中注册

1.6最后发出响应事件,通知相关监听器。

5.2用于属性承载的BeanDefinition

​ BeanDefinition是配置文件中<bean元素标签在容器中的内部表现形式,属性也是一一对应,然后spring将这些BeanDefinition注册到BeanDefinitionRegistry中,就像是Spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接从该Registry中读取配置信息。

6.自定义标签的解析

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
		String namespaceUri = getNamespaceURI(ele);
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

1.获取自定义标签的名称空间

2.根据命名空间找到对应的NamespaceHandler

3.根据标签名找到handler中对应解析器调用parse方法

类DefaultNamespaceHandlerResolver的resolve方法 (去掉了异常处理的代码)

public NamespaceHandler resolve(String namespaceUri) {
		Map<String, Object> handlerMappings = getHandlerMappings();
		Object handlerOrClassName = handlerMappings.get(namespaceUri);
		if (handlerOrClassName == null) {
			return null;
		}
		else if (handlerOrClassName instanceof NamespaceHandler) {
			return (NamespaceHandler) handlerOrClassName;
		}
		else {
			String className = (String) handlerOrClassName;
							Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
			NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
			namespaceHandler.init();
			handlerMappings.put(namespaceUri, namespaceHandler);
			return namespaceHandler;
		}
	}
private Map<String, Object> getHandlerMappings() {
		if (this.handlerMappings == null) {
			synchronized (this) {
				if (this.handlerMappings == null) {
                    Properties mappings =
             PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
					Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
					CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
					this.handlerMappings = handlerMappings;
				}
			}
		}
		return this.handlerMappings;
	}

1.getHandlerMappings方法将读取路径下所有META-INF/spring.handlers文件,里面有关于handler的映射关系。

2.在resolve方法中,根据标签的命名空间获取到对应的handler信息,可能是类名也可能是实例,如果是实例就直接返回,如果是类名则先实例化handler,并且调用init方法向该handler注册对应的标签解析器,并且更新映射关系,类名替换为实例。

3.获取到handler后调用parse方法,找到对应的标签解析器并调用解析器的parse方法。

举例:spring-context

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler

1.在spring-context包下有META-INF/spring.handlers文件如上

2.在spring的xml配置文件中引入如下标签 对应名称空间:http://www.springframework.org/schema/context

	<context:component-scan base-package="com.fjeport"
		annotation-config="true">
		<context:exclude-filter type="annotation"
			expression="org.springframework.stereotype.Controller" />
	</context:component-scan>

3.解析自定义标签时候根据名称空间映射找到了对应的ContextNamespaceHandler类

//ContextNamespaceHandler的init方法	
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());
	}

4.可以看到init方法中注册了好多个解析器,由于我们这里用的context:component-scan标签,所以选择ComponentScanBeanDefinitionParser这个解析器来调用parse方法。

5.ComponentScanBeanDefinitionParser逻辑:扫描指定包下的所有class文件,如果该class符合条件则解析出对应BeanDefition并向容器注册,判断条件excludeFilters,includeFilters。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值