<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    走自己的路

    路漫漫其修遠兮,吾將上下而求索

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      50 隨筆 :: 4 文章 :: 118 評論 :: 0 Trackbacks

     

    最近在完成一個小小的framework項目,由于項目中不使用spring,guice,自己實現(xiàn)了一個簡易的依賴注入框架。

     

    1. 寫一個xml文件作為配置的實際例子

     

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.ldd600.com/beanIoc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ldd600.com/beanIoc beanIoc.xsd">
        
    <bean id="ftpSend" class="com.ldd600.bean.ioc.beans.impl.FTPTransporter">
            
    <params>
                
    <param value="/ldd600" key="uploadFolder"></param>
                
    <param value="com.ldd600.bean.ioc.beans.impl.JugUUIDGenerator" key="generator" converter="com.ldd600.bean.ioc.converters.UUIDGeneratorConverter"></param>
            
    </params>
        
    </bean>
            
    <bean id="jmsSend" class="com.ldd600.bean.ioc.beans.impl.JMSTransporter">
            
    <params>
                
    <param value="Ldd600Queue" key="destName"></param>
            
    </params>
        
    </bean>
    </beans>


    2.根據(jù)這個xml文件,定義一個schema文件,驗證配置文件
    <?xml version="1.0" encoding="UTF-8"?>
    <xsd:schema xmlns:sample="http://www.ldd600.com/beanIoc" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.ldd600.com/beanIoc" elementFormDefault="qualified" attributeFormDefault="unqualified">
        
    <xsd:complexType name="paramsType">
            
    <xsd:annotation>
                
    <xsd:documentation> of java class</xsd:documentation>
            
    </xsd:annotation>
            
    <xsd:sequence maxOccurs="unbounded">
                
    <xsd:element name="param">
                    
    <xsd:complexType>
                        
    <xsd:annotation>
                            
    <xsd:documentation>key is property name, value is property value</xsd:documentation>
                        
    </xsd:annotation>
                        
    <xsd:simpleContent>
                            
    <xsd:extension base="sample:leafType">
                                
    <xsd:attribute name="key" type="sample:notEmptyToken" use="required"/>
                                
    <xsd:attribute name="value" type="sample:notEmptyToken" use="required"/>
                                
    <xsd:attribute name="converter" type="sample:classAttributeType" use="optional"/>
                            
    </xsd:extension>
                        
    </xsd:simpleContent>
                    
    </xsd:complexType>
                
    </xsd:element>
            
    </xsd:sequence>
        
    </xsd:complexType>
            
    <xsd:complexType name="idClassType">
            
    <xsd:all minOccurs="0">
                
    <xsd:element name="params" type="sample:paramsType">
                    
    <xsd:key name="outerParamsKey">
                        
    <xsd:selector xpath="sample:param"/>
                        
    <xsd:field xpath="@key"/>
                    
    </xsd:key>
                
    </xsd:element>
            
    </xsd:all>
            
    <xsd:attribute name="id" type="sample:notEmptyToken" use="required"/>
            
    <xsd:attribute name="class" type="sample:classAttributeType">
                
    <xsd:annotation>
                    
    <xsd:documentation>class name</xsd:documentation>
                
    </xsd:annotation>
            
    </xsd:attribute>
        
    </xsd:complexType>
        
    <xsd:simpleType name="leafType">
            
    <xsd:restriction base="xsd:string">
                
    <xsd:pattern value="(\s)*"/>
            
    </xsd:restriction>
        
    </xsd:simpleType>
        
    <xsd:simpleType name="classAttributeType">
            
    <xsd:restriction base="sample:notEmptyToken">
                
    <xsd:pattern value="([a-z|0-9|_]+\.)*[A-Z]([A-Z|a-z|0-9|_])*"/>
            
    </xsd:restriction>
        
    </xsd:simpleType>
        
    <xsd:simpleType name="notEmptyToken">
            
    <xsd:restriction base="xsd:token">
                
    <xsd:pattern value="(\S+\s*)+"/>
            
    </xsd:restriction>
        
    </xsd:simpleType>
        
    <xsd:element name="beans">
            
    <xsd:complexType>
                
    <xsd:sequence maxOccurs="unbounded">
                    
    <xsd:element name="bean" type="sample:idClassType"/>
                
    </xsd:sequence>
            
    </xsd:complexType>
            
    <xsd:key name="beanIdkey">
                
    <xsd:selector xpath="./sample:bean"></xsd:selector>
                
    <xsd:field xpath="@id"></xsd:field>
            
    </xsd:key>
        
    </xsd:element>
    </xsd:schema>


     

    類型

    解釋

    paramType

    表示類的字段,key是字段名,value字段值,converter如果有用來將String轉(zhuǎn)換為所需要的實例。

    idClassType

    用來表示bean實例,并且該實例有唯一的id

    notEmptyToken

    非空token

    leafType

    葉子類型比如<a> </a>,中間允許有space,比如空格、換行符等,但是不能出現(xiàn)其他任何字符。

    classAttributeType

    負責(zé)javaclass全名的string類型,比如com.ldd600.BeanClass



     

     

    1. 解析這個文件,并marshalljava對象,用xmlbeans實現(xiàn)

    使用xmlbeans生成schema對應(yīng)的java類和xmlbeans jaxb需要的元數(shù)據(jù)。

    ·         創(chuàng)建xsdConfig文件,內(nèi)容主要是生成的java類的package名,類simple name的前綴和后綴

    <xb:config
     
    xmlns:xb=
     "http://xml.apache.org/xmlbeans/2004/02/xbean/config"
    >
     
    <xb:namespace uri="http://www.ldd600.com/beanIoc">
      
    <xb:package>com.ldd600.bean.ioc.config.jaxb</xb:package>
    </xb:namespace>
      
    <xb:namespace uriprefix="http://www.ldd600.com/beanIoc">
        
    <xb:prefix>Xml</xb:prefix>
      
    </xb:namespace>
      
    <xb:namespace uriprefix="http://www.ldd600.com/beanIoc">
        
    <xb:suffix>Bean</xb:suffix>
        
    </xb:namespace>
    </xb:config>

     

    ·         創(chuàng)建一個bat可執(zhí)行文件,不用每次跑都去cmd下敲一堆命令,累啊。bat文件的內(nèi)容:

    scomp -d classes\beanIoc -src src\beanIoc -out beanIoc.jar beanIoc.xsd beanIoc.xsdconfig

    ·         雙擊bat,所需要的java類的.java文件,class文件和xmlbeans jaxb需要的元數(shù)據(jù)都橫空出世了,這些元數(shù)據(jù)xmlbeans會用來對xml文件進行驗證,檢查是否符合schema定義的語義規(guī)則。

    ·         java文件和元數(shù)據(jù)信息都拷貝到eclipse中吧,或者直接把生成的jar包發(fā)布到maven repository中,然后再pomdependency它。


     
    1. 解析的過程中,需要生成被依賴注入的對象,并完成屬性的動態(tài)設(shè)定。

    4.1   生成依賴注入的對象

    生成依賴注入的對象是通過反射直接生成類的實例,在這里要求有public的參數(shù)為空的構(gòu)造函數(shù)。

        

      Class clazz = Class.forName(sNamclassNamee);

                
    return clazz.newInstance();

     

     

    4.2  屬性的動態(tài)設(shè)定

    Commons-BeanUtils就是專門免費做這件事的好同志,我們可以利用它來完成,基本類型和一些經(jīng)常使用的類型,Commons-BeanUtils責(zé)無旁貸的提供了自動轉(zhuǎn)換的功能,beanutils不需要我們提供參數(shù)的類型,它可以自動完成轉(zhuǎn)換,它是根據(jù)getset方法的類型來決定類型的,可參見PropertyDescriptor.getPropertyType()方法。使用方法如下:


    if (!PropertyUtils.isWriteable(object, key)) {
                            
    throw new ConfigParseException(object.getClass()
                                    
    + " doesn't have the property " + key
                                    
    + "'s setter method!");
                        }

                String paramVal 
    = paramBean.getValue();
                BeanUtils.setProperty(object, key, paramVal);


     

    isWriteable方法判斷是否有可用的set方法,如果有就完成屬性的動態(tài)設(shè)置。paramBean就是xml文件中定義的那個param

     

     

    但是Beanutils默認幫我們轉(zhuǎn)換的類型為基本類型和所有它已經(jīng)提供了Converterclass類型,如果我們有特殊的類需要進行動態(tài)設(shè)定,必須自己提供converter,注冊到它的converters map中。這樣beanutils兄弟在動態(tài)設(shè)定屬性值的時候,就會根據(jù)屬性的類型去converter map中把取出該屬性類型對應(yīng)的自定義converter來轉(zhuǎn)換。因為在這里配置文件中配置的都是String 所以我們對Converter接口做了修改:



    public abstract class BeanConverter implements Converter {
        
    public abstract Object convert(Class type, String value) throws ConfigParseException;

        
    public Object convert(Class type, Object value) {
            
    return this.convert(type, (String)value);
        }

    }



     

    我們強制規(guī)定了convert方法的參數(shù)必須是String,自己提供的converter必須繼承BeanConverter抽象類。

    String key = paramBean.getKey();
                        String converterClsName 
    = paramBean.getConverter();
                        
    if (StringUtils.isNotEmpty(converterClsName)) {
                            Class converterClazz 
    = Class.forName(converterClsName);
                            
    if (!BeanConverter.class
                                    .isAssignableFrom(converterClazz)) 
    {
                                
    throw new ConfigParseException(
                                        
    "converter must extend BeanConverter!");
                            }

                            
                            
    if(!this.converters.containsKey(converterClsName)) {
                                
    this.converters.put(converterClsName, converterClazz);
                                
    // get property type
                                Class propertyClazz = PropertyUtils.getPropertyType(
                                        object, key);
                                
    // register converter
                                ConvertUtils.register((Converter) converterClazz
                                        .newInstance(), propertyClazz);
                            }

                        }
     }


    4.3屬性邏輯規(guī)則的檢查

    在設(shè)置好屬性以后,這個屬性的值并不一定配置的正確,也不一定滿足邏輯規(guī)則,比如希望int值在35之間,比如希望String 不要為空等等。為了在動態(tài)設(shè)定完屬性后進行邏輯規(guī)則的校驗,提供了InitializingBean接口



    public interface InitializingBean {
        
    void afterPropertiesSet() throws Exception;
    }



     

    實現(xiàn)該接口的類,它們的邏輯規(guī)則需要在afterProperties提供,不符合規(guī)則的請拋異常,并會在屬性設(shè)定完后檢查


        public void afterPropertiesSet() throws Exception {
            
    if (StringUtils.isEmpty(uploadFolder)) {
                
    throw new IllegalArgumentException(
                        
    "upload folder is an empty string!");
            }

            
    if (null == generator) {
                
    throw new IllegalArgumentException("generator is null!");
            }

        }




    if (object instanceof InitializingBean) {
                ((InitializingBean) object).afterPropertiesSet();
            }



      4.4bean注冊到BeanContext

    String id = idClassTypeBean.getId();
    BeanContextFactory.getBeanContext().setBean(id, object);


     

        4.5清理環(huán)境

    完成屬性的動態(tài)注入后,還需要清理環(huán)境


    private void cleanConfig() {
            ConvertUtils.deregister();
            
    this.converters = null;
        }

     

     

    5.如何做到基于接口設(shè)計

    ·         Converter提供了基于接口設(shè)計的功能:我們可以動態(tài)的設(shè)置不同的實現(xiàn)。

    ·         用了該框架,本身就基于接口,我們可以在配置文件中修改bean的實現(xiàn)類。應(yīng)用程序代碼它不關(guān)心具體的實現(xiàn)類,它只關(guān)心id

     

    Transporter transporter =  (Transporter) BeanContextFactory.getBeanContext().getBean(TransporterParser.getTransportName());

     

    不過,這里沒有象springjuice那么強大的bean factory功能。因為這個東東只是一個小項目的一小部分,所以功能上滿足小項目的需求就足夠了。

     

    6. Test

     就簡單的測了一下,可以看源代碼。

     

    7.總結(jié)

    主要是項目是基于接口設(shè)計的,所以一些類的實現(xiàn)需要在配置文件里設(shè)定,實現(xiàn)類的實例屬性也要是可以擴展的,并且提供屬性值的邏輯校驗,所以就有了這么一個東東。

    beanIoc源代碼



    posted on 2008-09-25 19:16 叱咤紅人 閱讀(2613) 評論(4)  編輯  收藏

    評論

    # re: 利用commons-BeanUtils實現(xiàn)簡易的依賴注入框架 2008-09-26 09:10 Jarod Liu
    既然是在仿spring,個人覺得沒必要“不使用spring",只使用spring的ioc就OK了。
    自己做一個框架,多人項目里別人的學(xué)習(xí)成本更高  回復(fù)  更多評論
      

    # re: 利用commons-BeanUtils實現(xiàn)簡易的依賴注入框架 2008-09-26 09:36 叱咤紅人
    @Jarod Liu
    已有的framework經(jīng)過評估,如果可以用,減少開發(fā)成本,我覺得也應(yīng)該利用。
    在這里遇到了一些情況,其實本來應(yīng)用的環(huán)境并不象文章中的那樣子,配置文件并不是bean什么的,因為想總結(jié)一下,就改成了bean。原來的配置文件是有自己語義的,下面是截取的一部分,

    <receiver:app receiverId="gps">
    <receiver:decorators>
    <receiver:decorator class="com.ldd600.frm.mif.receiver.decorator.impl.mf.JAXBXmlBeansMFReceiverDecorator">
    <receiver:params>
    <receiver:param key="xmlDocClassName" value="com.ldd600.frm.mif.test.jaxb.tms.jo.XmlJobOrderDocumentBean"/>
    </receiver:params>
    </receiver:decorator>
    </receiver:decorators>
    <receiver:converter class="com.ldd600.frm.mif.test.receiver.converter.GPSJOVer2_0Converter">
    </receiver:converter>
    <receiver:processor class="com.ldd600.frm.mif.test.receiver.processor.GPSJOProcessor">
    </receiver:processor>
    </receiver:app>

    這個配置文件是有自己語義的,并不需要bean什么的。雖然spring提供了namespacehandler,但namespacehandler用起來也有成本的,而且還要自己注冊到spring的context中。這里只是為了增強一些基于接口的擴展功能怕麻煩就簡單的用了一下beanutils,用spring beans module肯定是可以的。
    而且,項目本來就有自己的配置文件,所以也不想再增加額外的配置文件。也不可能完全的就把這個配置整合到spring的applicationContext.xml中。  回復(fù)  更多評論
      

    # re: 利用commons-BeanUtils實現(xiàn)簡易的依賴注入框架 2008-09-28 08:49 隔葉黃鶯
    都做這么復(fù)雜了,為何不用 spring,用 spring 無疑可以減少學(xué)習(xí)和維護成本。  回復(fù)  更多評論
      

    # re: 利用commons-BeanUtils實現(xiàn)簡易的依賴注入框架[未登錄] 2008-10-27 13:29 attend
    支持做一些小輪子,自己寫的自己清楚,還好維護點。  回復(fù)  更多評論
      


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 久草免费福利视频| 两个人看的www免费视频| 亚洲精品国产福利一二区| 久久精品视频免费看| 亚洲欧美国产日韩av野草社区| 亚洲一区二区三区自拍公司| 噜噜嘿在线视频免费观看| 久久九九全国免费| 国产成人无码区免费内射一片色欲 | 亚洲乱码一二三四五六区| 不卡一卡二卡三亚洲| 白白国产永久免费视频| 每天更新的免费av片在线观看| 一本久久A久久免费精品不卡| 亚洲日韩国产二区无码| 亚洲人成网站在线在线观看| 伊人久久五月丁香综合中文亚洲 | 最近免费中文字幕大全高清大全1| 青青草97国产精品免费观看| 亚洲Av高清一区二区三区| 亚洲A∨无码无在线观看| 亚洲中文字幕无码日韩| 亚洲成aⅴ人片久青草影院| 国产麻豆视频免费观看| 免费播放一区二区三区| 99久久免费国产特黄| 免费观看91视频| 91热久久免费精品99| 毛片免费在线播放| 99久久免费国产精品特黄| 大香人蕉免费视频75| 亚洲美女在线国产| 亚洲成a人片在线观看无码| 亚洲精品成人片在线观看精品字幕| 亚洲成a人无码av波多野按摩| 亚洲美女高清一区二区三区| 午夜影视日本亚洲欧洲精品一区| 亚洲国产美女精品久久| 亚洲精品美女视频| 亚洲欧洲日产韩国在线| 亚洲乱理伦片在线观看中字|