Spring学習06-II OC実現原理及びIOC容器初期化プロセス
一、IOCの原理Spring機能はこんなに強いですが、どれほど強力な機能でもjavaコードで書かれています.IOCの実現原理を見てみます.前の章では、beanにおけるlazy-nit属性の存在によって、私達は全てのbeanを一度に全部実際化することができず、Mapに置くことができなかったと述べました.
ここで、IOC容器の原理ははっきりしています.配置ファイルの中のbeanタグを規則に従って読み取って、nameをkeyとして、BenDefinitionの対象をvalue値としてこのmapに預けて、私達がgetBenをする時、実際にこのmapから一つの対象を取る過程です.IOC容器の原理はまとめられます.Fileオブジェクトが私たちのxmlプロファイルを指している必要があります.つまり、xmlファイルの具体的な位置とリソースポジショニングというものを探しています.2、Readerが私達のxmlファイルを読み、beanタグを一つ一つ読みだします.DOM解析とも言います.3、読み取ったbeanタグをMapの中に置いて、本当のことを言います.ここを見たら、Springは私の心の中で神秘的で偉大なイメージが一気に崩れました.これは高級とは限りません.振り返ってみても、牛に迫る技術は簡単なものを組み合わせて実現されました.話を続ける
すでにIOCの原理を知っている以上、私達は自分でbeanを獲得する過程を作ることができます.まずテストクラスをください.
二、IOC容器初期化過程を見に来ました.Class PathXMlapplicationContectという方法の中に一体どんな猫がいますか?四歩の実現を一歩にしました.この方法に入ってみます.
三、loadBeanDefinitions方法の詳細は私達のソースコードに沿ってずっと探しています.org.springframe ebook.beans.factory.xml.Xml BeanDefinitionReaderのこの種類の中で、loadBenDefinitions方法の実現を見つけました.
BenDefinitionParsserDelegate類におけるこの方法は、ここではコードの一部しか貼っていません.多すぎます.beanタグの詳細な解析過程です.戻り値を見てください.AbstractBenDefinitionの例です.つまり、解析してみるとBenDefinitionオブジェクトです.
propertyを解析する例を挙げて、BeanDefinition全体のロード過程の分析を完成しますか?それともBeanDefinitionParsserDelegateのコードの中でBeanDefinitionの定義を一層解析します.たとえば、属性要素の集合からデバイスの各属性要素まで、そして具体的な属性値の処理です.解析結果によると、これらの属性値の処理は、PropertyValueオブジェクトとしてパッケージ化され、BeanDefinitionオブジェクトに設定されます.以下のコードリストのように.
このような層の解析を経て、XMLファイルで定義されているBeanDefinitionはIoC容器全体にロードされ、容器内にデータマッピングを確立しました.IoC容器には対応するデータ構造が構築されており、あるいはIoC容器中のPOJOオブジェクトのイメージとして見られ、これらのデータ構造はAbstractBenDefinitionを入り口として、IoC容器にインデックス、クエリ、操作を実行させることができる.
上の部分を貼りました.BenDefinitionParsserDelegate類コードの先頭に、beanの属性を定義しています.実は下の部分には属性に対応する解析方法があります.上に貼ってあるのはProperty属性に対する解析過程だけです.
Default BeanDefinitionDocmentReaderのparseBenDefinitionsでは、上記のいくつかのデフォルトの属性に対して、BeanDefinitionParsserDelegateのParseCutematElementを呼び出します.デフォルトのラベルではない場合は、カスタム、注釈、AOPのような別の方法で使用されます.後の内容については、ここではしばらく解析をしないで、後で追加します.
IOCの原理をまとめます.1、IOCの核心は容器の初期化です.まず私達は一つの容器を定義します.全部ビーンファクトリーインターフェースの実現類2、容器を初期化し、呼び出したrefshBenFactory()方法を初期化します.3、初期化の過程は主にxmlのプロファイルを読み、各beanタグをBenDefinitionParsdelegateのparseDefaultElementまたはparseCustomolement方法で読みだし、AbstractBenDefinitionオブジェクトに預けて、AbstractBeabinDefinitionオブジェクトをHoabiction 6、BeanDefinitionオブジェクトに保存します.
package org.springframework.beans.factory.support;
import java.io.NotSerializableException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Provider;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/** * @author Rod Johnson * @author Juergen Hoeller * @author Sam Brannen * @author Costin Leau * @since 16 April 2001 */
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
private static Class javaxInjectProviderClass = null;
static {
ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
try {
javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - Provider interface simply not supported then.
}
}
/** Map from serialized id to factory instance */
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>();
/** Optional id for this factory, for serialization purposes */
private String serializationId;
/** Whether to allow re-registration of a different definition with the same name */
private boolean allowBeanDefinitionOverriding = true;
/** Whether to allow eager class loading even for lazy-init beans */
private boolean allowEagerClassLoading = true;
/** Resolver to use for checking if a bean definition is an autowire candidate */
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
/** Map from dependency type to corresponding autowired value */
private final Map<Class, Object> resolvableDependencies = new HashMap<Class, Object>();
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
/** List of bean definition names, in registration order */
private final List<String> beanDefinitionNames = new ArrayList<String>();
/** Whether bean definition metadata may be cached for all beans */
private boolean configurationFrozen = false;
/** Cached array of bean definition names in case of frozen configuration */
private String[] frozenBeanDefinitionNames;
}
やっぱり、それはそれです./** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
私達が考えているのと同じです.この実現類にはこのようなMapが定義されています.注釈を見て、beanのname値はこのMapのkey値としています.だから、私達はどのbeanが必要ですか?このmapの中から探せばいいです.ここで、IOC容器の原理ははっきりしています.配置ファイルの中のbeanタグを規則に従って読み取って、nameをkeyとして、BenDefinitionの対象をvalue値としてこのmapに預けて、私達がgetBenをする時、実際にこのmapから一つの対象を取る過程です.IOC容器の原理はまとめられます.Fileオブジェクトが私たちのxmlプロファイルを指している必要があります.つまり、xmlファイルの具体的な位置とリソースポジショニングというものを探しています.2、Readerが私達のxmlファイルを読み、beanタグを一つ一つ読みだします.DOM解析とも言います.3、読み取ったbeanタグをMapの中に置いて、本当のことを言います.ここを見たら、Springは私の心の中で神秘的で偉大なイメージが一気に崩れました.これは高級とは限りません.振り返ってみても、牛に迫る技術は簡単なものを組み合わせて実現されました.話を続ける
すでにIOCの原理を知っている以上、私達は自分でbeanを獲得する過程を作ることができます.まずテストクラスをください.
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
設定ファイル:<bean id="user" class="com.errol.dao.User">
<property name="name">
<value> </value>
</property>
</bean>
テストクラス:public class Client {
@Test
public void testFactory(){
/* * Spring */
//
ClassPathResource cr = new ClassPathResource("applicationContext.xml");
//bean
DefaultListableBeanFactory db = new DefaultListableBeanFactory();
// xml
XmlBeanDefinitionReader xd = new XmlBeanDefinitionReader(db);
// xml map
xd.loadBeanDefinitions(cr);
System.out.println("bean :"+db.getBeanDefinitionCount());
User user = (User)db.getBean("user");
System.out.println(user);
}
}
出力結果:log4j:WARN No appenders could be found for logger (org.springframework.core.CollectionFactory).
log4j:WARN Please initialize the log4j system properly.
bean :1
com.errol.dao.User@900bac2
成功です次に、普段私達が使っているアプリConteetの対象がbeanを取得する時の使い方を連想します.ApplicationContext applicationContext = new ClassPathXMLApplicationContext("applicationContext");
User user = new applicationContext .getBean("user");
私達が4歩で仕上げたことは、上のステップで解決しました.new Class PathXMlapplicationContect(「application Contect」);この言葉の中には何がありますか?二、IOC容器初期化過程を見に来ました.Class PathXMlapplicationContectという方法の中に一体どんな猫がいますか?四歩の実現を一歩にしました.この方法に入ってみます.
public ClassPathXmlApplicationContext(String[] configLocations, ApplicationContext parent)
throws BeansException {
super(parent);
this.configLocations = configLocations;
refresh();
}
中にはrefresh方法を呼び出しました.中に入ってみてください.AbstractaplicationContectの抽象類の中に入ると、Class PathXml Apple Compection Contectはこの抽象類から継承されます.中にはまだ二階しかありません.public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
this.startupTime = System.currentTimeMillis();
synchronized (this.activeMonitor) {
this.active = true;
}
// Tell subclass to refresh the internal bean factory.
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// Tell the internal bean factory to use the context's class loader.
beanFactory.setBeanClassLoader(getClassLoader());
// Populate the bean factory with context-specific resource editors.
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this));
// Configure the bean factory with context semantics.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered with the context instance.
for (Iterator it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) {
BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next();
factoryProcessor.postProcessBeanFactory(beanFactory);
}
if (logger.isInfoEnabled()) {
if (getBeanDefinitionCount() == 0) {
logger.info("No beans defined in application context [" + getDisplayName() + "]");
}
else {
logger.info(getBeanDefinitionCount() + " beans defined in application context [" + getDisplayName() + "]");
}
}
try {
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors();
// Register bean processors that intercept bean creation.
registerBeanPostProcessors();
// 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 singletons this late to allow them to access the message source.
beanFactory.preInstantiateSingletons();
// Last step: publish corresponding event.
publishEvent(new ContextRefreshedEvent(this));
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
beanFactory.destroySingletons();
throw ex;
}
}
}
この中は主にrefreshBenFactoryの方法を見ますが、この抽象類の中では実現していません.そのサブクラスを探しに来ました.上に述べたいくつかは、一つ一つ見に行きます.Abstractreshable Appleication Comptext抽象類の中で、この方法の実現があります.見てみてください.protected final void refreshBeanFactory() throws BeansException {
// Shut down previous bean factory, if any.
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory != null) {
this.beanFactory.destroySingletons();
this.beanFactory = null;
}
}
// Initialize fresh bean factory.
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
if (logger.isInfoEnabled()) {
logger.info("Bean factory for application context [" + getDisplayName() + "]: " + beanFactory);
}
}
catch (IOException ex) {
throw new ApplicationContextException(
"I/O error parsing XML document for application context [" + getDisplayName() + "]", ex);
}
}
上記の実装では、私たちがよく知っているものが現れました.DefaultListable BeanFactory beanFactoryというのは上記の4ステップの中のステップではないですか?このDefault Listable BenFactoryのオブジェクトを作成して、その後はDOMを解析して、beanタグをBenDefinitionオブジェクトに解析して、Mapに置いて、ここでこのように実現されているかどうか見てください.loadBeanDefinitionsに入る方法はここでも実現されていないことを発見しました.サブクラスに探して、AbstractXmlAppliationComptextの中でこの方法に対して実現しました.中に入ってみてください.protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
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.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
よく知っているものXmlBenDefinitionReaderは、リソースファイルの中のbean定義を読み取り、initBenDefinitionReader方法はこのクラスでは実現されていません.字面の意味では、私たちのbeanDefinitionReaderを初期化します.鍵は後の方法のloadBeanDefinitionReaderです.これは私達の書く4歩の中の1歩ではないですか?ただそれは幾重ものパッケージを通して、1歩で私達のすることを解決できます.XmlBenDefinitionReaderの中のこの方法のloadBenDefinitionsはどのように実現したのですか?IOCの初期化の過程をよく理解しました..の半分です三、loadBeanDefinitions方法の詳細は私達のソースコードに沿ってずっと探しています.org.springframe ebook.beans.factory.xml.Xml BeanDefinitionReaderのこの種類の中で、loadBenDefinitions方法の実現を見つけました.
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());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected recursive loading of " + encodedResource + " - check your import definitions!");
}
// XML , IO InputSource 。
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.set(null);
}
}
}
中は主にdoLoadBenDefinitionsの方法に注目しています.この方法は具体的にbeanを読む詳しい過程です.protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource);
// XML Document , documentLoader , documentLoader DefaultDocumentLoader, documentLoader
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
// BeanDefinition , Spring 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);
}
}
もう一つの方法に位置づけられました.この方法は詳細な解析過程です.この方法に沿って、インターフェースのBenDefinitionDcument Readerを見つけました.インターフェースの中では実現していません.サブタイプのDefault BeanDefinitionDcumentReaderを見てください.この方法の実現があります. /** * Parses bean definitions according to the "spring-beans" DTD. * <p>Opens a DOM Document; then initializes the default settings * specified at <code><beans></code> level; then parses * the contained bean definitions. */
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
preProcessXml(root);
parseBeanDefinitions(root, delegate);
postProcessXml(root);
}
再び一つの方法のパーサービーンDefinitionsに位置してから入ります./** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document */
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)) {
// import, alias, beans
parseDefaultElement(ele, delegate);
}
else {
// aop, mvc, dubbo ,
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
ここで説明したいのは、具体的なSpring BenDefinitionについての解析は、BenDefinitionParDelegateで行われていることです.このクラスには様々なSpring Bean定義規則の処理が含まれています.興味のある学生は詳しく研究してもいいです.この処理過程を例を挙げて分析します.例えば、私たちが一番よく知っているビーン要素に対する処理はどのように完成されていますか?つまり、XML定義ファイルに登場するこの最も一般的な要素情報はどのように処理されていますか?ここでは、id、name、aliaseなど、おなじみのBeanDefinitionによって定義された処理が見られます.これらの要素の値をXMLファイルの該当する要素の属性から読み取ったら、生成したBeanDefinitionHolderに設定されます.これらの属性の解析は比較的簡単である.他の要素構成の解析については、例えば、各種のBeanの属性構成は、より複雑な解析プロセスを通じて、このプロセスはパーサージアンDefinitionElementによって達成される.解析が完了すると、解析結果をBenDefinitionオブジェクトに入れてBenDefinitionHolderにセットします.BenDefinitionParsserDelegate類におけるこの方法は、ここではコードの一部しか貼っていません.多すぎます.beanタグの詳細な解析過程です.戻り値を見てください.AbstractBenDefinitionの例です.つまり、解析してみるとBenDefinitionオブジェクトです.
/** * Parse the bean definition itself, without regard to name or aliases. May return * <code>null</code> if problems occured during the parse of the bean definition. */
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE);
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
ここでもう一度整理します.1、BenDefinitionParsDelegate解析beanタグを生成し、AbstractBeabin Definitionオブジェクト2、生成したAbstract BeanDefinitionオブジェクトをBenDefinitionオブジェクトの中に入れました.BenDefinitionHolderのAbstractBenDefinitionオブジェクトを***Mapに登録します.これは上のロジックとつながっています.propertyを解析する例を挙げて、BeanDefinition全体のロード過程の分析を完成しますか?それともBeanDefinitionParsserDelegateのコードの中でBeanDefinitionの定義を一層解析します.たとえば、属性要素の集合からデバイスの各属性要素まで、そして具体的な属性値の処理です.解析結果によると、これらの属性値の処理は、PropertyValueオブジェクトとしてパッケージ化され、BeanDefinitionオブジェクトに設定されます.以下のコードリストのように.
/** * bean property 。 */
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
// bean property
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element && DomUtils.nodeNameEquals(node, PROPERTY_ELEMENT)) {
// property property
parsePropertyElement((Element) node, bd);
}
}
}
public void parsePropertyElement(Element ele, BeanDefinition bd) {
// property
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
// bean , , 。 , bean property , 。
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
// property , Bean property , PropertyValue , BeanDefinitionHolder 。
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
/** * property , list 。 */
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
String elementName = (propertyName != null) ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element";
// Should only have one child element: ref, value, list, etc.
NodeList nl = ele.getChildNodes();
Element subElement = null;
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element && !DomUtils.nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
!DomUtils.nodeNameEquals(node, META_ELEMENT)) {
// Child element is what we're looking for.
if (subElement != null) {
error(elementName + " must not contain more than one sub-element", ele);
}
else {
subElement = (Element) node;
}
}
}
// property , ref value, ref value。
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
if ((hasRefAttribute && hasValueAttribute) ||
((hasRefAttribute || hasValueAttribute) && subElement != null)) {
error(elementName +
" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
}
// ref, ref RuntimeBeanReference, ref 。
if (hasRefAttribute) {
String refName = ele.getAttribute(REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(ele));
return ref;
} // value, value TypedStringValue , value 。
else if (hasValueAttribute) {
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
return valueHolder;
} // ,
else if (subElement != null) {
return parsePropertySubElement(subElement, bd);
}
else {
// Neither child element nor "ref" or "value" attribute found.
error(elementName + " must specify a ref or value", ele);
return null;
}
}
上記では、ref属性の解析について述べましたが、RuntimeBeanReferenceのようなクラスに言及しました.このようなBeanReferenceから実現しています.このインターフェースはとても簡単で、一つの方法でString getBenName()です.このインターフェースはbeanとbeanの依存関係を格納しています.例えば、refタグは、propertyオブジェクトの中で、refはBenReferenceを指しています.この引用に対応しているのは、依存しているbeanの情報です.getBeanNameを通じてそのbeanの名前を取得できます.BenDefinitionオブジェクトを取得することができます.このような層の解析を経て、XMLファイルで定義されているBeanDefinitionはIoC容器全体にロードされ、容器内にデータマッピングを確立しました.IoC容器には対応するデータ構造が構築されており、あるいはIoC容器中のPOJOオブジェクトのイメージとして見られ、これらのデータ構造はAbstractBenDefinitionを入り口として、IoC容器にインデックス、クエリ、操作を実行させることができる.
上の部分を貼りました.BenDefinitionParsserDelegate類コードの先頭に、beanの属性を定義しています.実は下の部分には属性に対応する解析方法があります.上に貼ってあるのはProperty属性に対する解析過程だけです.
Default BeanDefinitionDocmentReaderのparseBenDefinitionsでは、上記のいくつかのデフォルトの属性に対して、BeanDefinitionParsserDelegateのParseCutematElementを呼び出します.デフォルトのラベルではない場合は、カスタム、注釈、AOPのような別の方法で使用されます.後の内容については、ここではしばらく解析をしないで、後で追加します.
IOCの原理をまとめます.1、IOCの核心は容器の初期化です.まず私達は一つの容器を定義します.全部ビーンファクトリーインターフェースの実現類2、容器を初期化し、呼び出したrefshBenFactory()方法を初期化します.3、初期化の過程は主にxmlのプロファイルを読み、各beanタグをBenDefinitionParsdelegateのparseDefaultElementまたはparseCustomolement方法で読みだし、AbstractBenDefinitionオブジェクトに預けて、AbstractBeabinDefinitionオブジェクトをHoabiction 6、BeanDefinitionオブジェクトに保存します.