カスタムラベルの解析

14844 ワード

1.カスタムラベルの解析
Springのラベルは標準ラベルとカスタムラベルの2種類に分けられています。以前は標準ラベルの解析を分析しました。Doccumentに設定ファイルを変換し、対応するrootを抽出した後、すべての要素の解析を開始しました。ここで解析すると、デフォルトのラベルとカスタムラベルの2つの区分が始まります。ソースは以下の通りです。
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)) {
                       //    
                        this.parseDefaultElement(ele, delegate);
                    } else {
                        //     
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            //     
            delegate.parseCustomElement(root);
        }
    }

上記のソースから分かります。Springが元素を手に入れた時、まず名前空間の解析を行いました。もしデフォルトの名前空間であれば、Parse DefaultElementを使って解析を行います。
カスタムラベル解析パーrseCustoomelement方法:
 public BeanDefinition parseCustomElement(Element ele) {
        return this.parseCustomElement(ele, (BeanDefinition)null);
    }

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

1.1タグの名前空間を取得する
ラベルの解析は名前空間の提起から始まります。Springではデフォルトのラベルとカスタムラベルはラベルによって提供される名前空間に基づいています。org.w 3 c.dom.Nodeではすでに方法が提供されています。
public String getNameSpaceURI(Node node){
      return node.getNameSpaceURI();
}
1.2カスタムラベルプロセッサを抽出する
名前空間があれば、Namespace Handlerの抽出ができます。Namespace Handler handler=this.reader Conttext.get Namespace HandlerResoliver()ここでDefault Namespace HandlerResolaverのresove方法を呼び出しました。
public NamespaceHandler resolve(String namespaceUri) {
        //           handler  
        Map handlerMappings = this.getHandlerMappings();
        //             
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        } else if (handlerOrClassName instanceof NamespaceHandler) {
            //       ,        
            return (NamespaceHandler)handlerOrClassName;
        } else {
            String className = (String)handlerOrClassName;

            try {
                //         
                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");
                } else {
                    //    
                    NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass);
                    //    NamespaceHandler     
                    namespaceHandler.init();
                    //      。
                    handlerMappings.put(namespaceUri, namespaceHandler);
                    return namespaceHandler;
                }
            } catch (ClassNotFoundException var7) {
                throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", var7);
            } catch (LinkageError var8) {
                throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", var8);
            }
        }
}

get Handler Mappings()方法:
private Map getHandlerMappings() {
        if (this.handlerMappings == null) {
            //       
            synchronized(this) {
                if (this.handlerMappings == null) {
                    try {
                    //location        META-INF
                        Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                        if (this.logger.isDebugEnabled()) {
                            this.logger.debug("Loaded NamespaceHandler mappings: " + mappings);
                        }
          // properties     Map   handMapping
                        Map handlerMappings = new ConcurrentHashMap(mappings.size());
                        CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                        this.handlerMappings = handlerMappings;
                    } catch (IOException var5) {
                        throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", var5);
                    }
                }
            }
        }

        return this.handlerMappings;
    }

1.3ラベル解析:
解析器と分析する元素を得ました。Springは解析作業をカスタム解像器に委託して、return handle.parse(ele,new PaserContext)を解析します。Namespace Handler Support.javaにおけるparse方法:
 public BeanDefinition parse(Element element, ParserContext parserContext) {
        //        
        return this.findParserForElement(element, parserContext).parse(element, parserContext);
}
    private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
        //       ,   
操作の方法this.findParserForElement.parserContt.).parse
public final BeanDefinition parse(Element element, ParserContext parserContext) {
        //  AbstractBeanDefinition  
        AbstractBeanDefinition definition = this.parseInternal(element, parserContext);
        if (definition != null && !parserContext.isNested()) {
            try {
               //id,alias 
 String id = this.resolveId(element, definition, parserContext);
                if (!StringUtils.hasText(id)) {
                    parserContext.getReaderContext().error("Id is required for element '" + parserContext.getDelegate().getLocalName(element) + "' when used as a top-level tag", element);
                }

                String[] aliases = null;
                if (this.shouldParseNameAsAliases()) {
                    String name = element.getAttribute("name");
                    if (StringUtils.hasLength(name)) {
                        aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
                    }
                }
             // AbstractBeanDefinition   BeanDefinitionHolder
                BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
                this.registerBeanDefinition(holder, parserContext.getRegistry());
                if (this.shouldFireEvents()) {
                 //         
                    BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
                    this.postProcessComponentDefinition(componentDefinition);
                    parserContext.registerComponent(componentDefinition);
                }
            } catch (BeanDefinitionStoreException var8) {
                parserContext.getReaderContext().error(var8.getMessage(), element);
                return null;
            }
        }

        return definition;
    }
上記のパース方法では、最初の文のパーサーInternalは主にカスタムメソッドへの呼び出しです。
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
        String parentName = this.getParentName(element);
        if (parentName != null) {
            builder.getRawBeanDefinition().setParentName(parentName);
        }

        //        class,           eg:UserBeanDefinitionParse  getBeanClass   
  Class> beanClass = this.getBeanClass(element);
        if (beanClass != null) {
            builder.getRawBeanDefinition().setBeanClass(beanClass);
        } else {
          //       getBeanClass  ,           getBeanClassName  
            String beanClassName = this.getBeanClassName(element);
            if (beanClassName != null) {
                builder.getRawBeanDefinition().setBeanClassName(beanClassName);
            }
        }

        builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
        if (parserContext.isNested()) {
           //            scope  
            builder.setScope(parserContext.getContainingBeanDefinition().getScope());
        }

        if (parserContext.isDefaultLazyInit()) {
           //      
            builder.setLazyInit(true);
        }
       //       doParse      
        this.doParse(element, parserContext, builder);
        return builder.getBeanDefinition();
    }

以上はSpringがどのようにカスタムラベルを解析する過程ですか?Springが設定ファイルからメモリをロードするまでの全過程を勉強しました。
2.カスタムラベルの使用
多くの場合、開発にはシステムの構成化サポートが必要であり、最も簡単なのはSpringの標準beanに基づいて配置されていますが、配置が複雑で、またはより多くの豊富な制御が必要な場合、不器用に見えます。実現するのは比較的に煩わしい。Springは、拡張可能なSchemaのサポートを提供しています。Springを拡張するカスタムタグは、ステップ(Springのcoreパッケージが必要です)を設定する必要があります。1.拡張が必要なコンポーネントを作成します。2.XSDファイル記述コンポーネントの内容を定義します。3.ファイルを作成し、BenDefinitionParterインターフェースを実現して、XSDファイルの定義とコンポーネント定義を解析します。4.Handlerファイルを作成します。Namespace Handler Supportから拡張して、目的はコンポーネントをSpring容器5に拡張することです。Spring.handersとSpring.schemasファイルを作成します。
2.1通常のpojoオブジェクトを作成する:
package pojo;

public class User {
    private String userName;
    private String email;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

2.2 XSDファイルを定義し、コンポーネントの内容を説明する


	
			 
				 
				 
				 
			 
	


2.3 UserBeanDefinitionParaserを作成する
クラスを作成して、XSDファイルの定義とコンポーネントの定義を解析するために、BeanDefinitionParsserインターフェースを実現します。
package com.SpringBean.test;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import pojo.User;

public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    /**
     * Element    
     */
    @Override
    protected Class> getBeanClass(Element element) {
        return User.class;
    }

    /**
     *  element        
     * @param element
     * @param builder
     */
    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String userName=element.getAttribute("userName");
        String email=element.getAttribute("email");
        if(StringUtils.hasText(userName)){
            builder.addPropertyValue("userName",userName);
        }
        if(StringUtils.hasText(email)){
            builder.addPropertyValue("email",email);
        }
    }
}

2.4 Handlerファイルを作成する
Handlerファイルを作成し、Namespace Handler Supportから拡張します。目的は、Spring容器にコンポーネントを登録するためです。
package com.SpringBean.test;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class MyNameSpaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("user",new UserBeanDefinitionParser());
    }
}

2.5 Spring.handersとSpring.schemasファイルを作成する
Spring.handers:
http\://www.test.com/sehema/user=com.SpringBean.test.MyNameSpaceHandler
Spring.schemas:
http\://www.test.com/sehema/user.xsd=META-INF/userschema.xsd
上のソースコードの解析では、この2つのファイルを通してデフォルトのlocationはMETA-INFパスですので、ファイルをclasassipath:META-INFパッケージに入れたり、ソースを修正したりすればいいです。beans.xml:


     


test:
package com.SpringBean.test;

import bean.GetBeanTest;
import bean.TestChangeMethod;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import pojo.User;

@SuppressWarnings("deprecation")
public class SpringTest {

    public static void main(String[] args) throws Exception {
     //   Resource resource = new ClassPathResource("beans.xml");
        BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beans.xml"));
/*        GetBeanTest test=(GetBeanTest) bf.getBean("getBeanTest");
        TestChangeMethod me=(TestChangeMethod) bf.getBean("testChangeMethod");
        me.changeMe();*/
        User user=(User) bf.getBean("testBean");
        System.out.println(user.getUserName()+" "+user.getEmail());
      //  test.showMain();
    }



}

運転結果:[email protected]