国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

手寫Spring之IOC基于注解動(dòng)態(tài)創(chuàng)建對(duì)象

Andrman / 974人閱讀

摘要:上一篇博客介紹了如何基于配置文件在運(yùn)行時(shí)創(chuàng)建實(shí)例對(duì)象,這篇博客將介紹基于注解方式怎樣實(shí)現(xiàn)對(duì)象的創(chuàng)建。方便測(cè)試,該類型分別創(chuàng)建兩個(gè)單例和多例的類型。注意這種為對(duì)象注入屬性值的方式耦合度較高,可根據(jù)情況使用。

上一篇博客介紹了如何基于xml配置文件在運(yùn)行時(shí)創(chuàng)建實(shí)例對(duì)象,這篇博客將介紹基于注解方式怎樣實(shí)現(xiàn)對(duì)象的創(chuàng)建。

廢話不多說(shuō),直接上代碼。

首先還是創(chuàng)建項(xiàng)目,由于這次不需要使用第三方的API,創(chuàng)建一個(gè)簡(jiǎn)單的Java項(xiàng)目即可,依然還是JDK7的環(huán)境下。

第二步是創(chuàng)建屬于自己的注解。

MyComponent注解內(nèi)容如下:

package annotation;  
  
import java.lang.annotation.ElementType;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  
import java.lang.annotation.Target;  
/**@Target 屬性用于注明此注解用在什么位置, 
 * ElementType.TYPE表示可用在類、接口、枚舉上等*/  
@Target(ElementType.TYPE)  
/**@Retention 屬性表示所定義的注解何時(shí)有效, 
 * RetentionPolicy.RUNTIME表示在運(yùn)行時(shí)有效*/  
@Retention(RetentionPolicy.RUNTIME)  
/**@interface 表示注解類型*/  
public @interface MyComponent {  
    /**為此注解定義scope屬性*/  
    public String scope();  
} 

MyValue注解內(nèi)容如下:

package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyValue {
    /**定義value屬性*/
    public String value();
}

第三步是創(chuàng)建entity對(duì)象類型,用于在運(yùn)行時(shí)創(chuàng)建其實(shí)例對(duì)象。

方便測(cè)試,該User類型分別創(chuàng)建兩個(gè)單例singleton和多例prototype的User類型。

SingletonUser類的內(nèi)容如下:

package entity;

import annotation.MyComponent;
import annotation.MyValue;

@MyComponent(scope="singleton")
public class SingletonUser {
    @MyValue("1")
    private Integer id;
    @MyValue("zhangsan")
    private String name;
    @MyValue("zhangsan")
    private String password;
    
    public SingletonUser() {
        System.out.println("無(wú)參構(gòu)造方法執(zhí)行");
    }
    //setters和getters...
}

PrototypeUser類的內(nèi)容如下:

package entity;

import annotation.MyComponent;
import annotation.MyValue;

@MyComponent(scope="prototype")
public class PrototypeUser {
    @MyValue("2")
    private Integer id;
    @MyValue("lisi")
    private String name;
    @MyValue("lisi")
    private String password;
    public PrototypeUser() {
        System.out.println("無(wú)參構(gòu)造方法執(zhí)行");
    }
    //setters和getters...
}

主角登場(chǎng),創(chuàng)建AnnotationConfigApplicationContext工廠類

該類的內(nèi)容如下:

首先定義兩個(gè)Map容器用于存儲(chǔ)對(duì)象。

package applicationContext;  
  
import java.io.File;  
import java.io.FileFilter;  
import java.net.URL;  
import java.util.Map;  
import java.util.concurrent.ConcurrentHashMap;  
  
import annotation.MyComponent;  
  
public class AnnotationConfigApplicationContext {  
    /**此Map容器用于存儲(chǔ)類定義對(duì)象*/  
    private Map> beanDefinationFacotry=new ConcurrentHashMap<>();  
    /**此Map容器用于存儲(chǔ)單例對(duì)象*/  
    private Map singletonbeanFactory=new ConcurrentHashMap<>();  
}

定義有參構(gòu)造方法:

/**有參構(gòu)造方法,參數(shù)類型為指定要掃描加載的包名*/  
public AnnotationConfigApplicationContext(String packageName) {  
    /**掃描指定的包路徑*/  
    scanPkg(packageName);  
}  

在創(chuàng)建對(duì)象初始化時(shí),會(huì)調(diào)用scanPkg方法掃描指定路徑下的文件,所以在此定義該方法:

/** 
 * 掃描指定包,找到包中的類文件。 
 * 對(duì)于標(biāo)準(zhǔn)(類上有定義注解的)類文件反射加載創(chuàng)建類定義對(duì)象并放入容器中 
 */  
private void scanPkg(final String pkg){  
    //替換包名中的".",將包結(jié)構(gòu)轉(zhuǎn)換為目錄結(jié)構(gòu)  
    String pkgDir=pkg.replaceAll(".", "/");  
    //獲取目錄結(jié)構(gòu)在類路徑中的位置(其中url中封裝了具體資源的路徑)  
    URL url=getClass().getClassLoader().getResource(pkgDir);  
    //基于這個(gè)路徑資源(url),構(gòu)建一個(gè)文件對(duì)象  
    File file=new File(url.getFile());  
    //獲取此目錄中指定標(biāo)準(zhǔn)(以".class"結(jié)尾)的文件  
    File[] fs=file.listFiles(new FileFilter() {  
        @Override  
        public boolean accept(File file) {  
            //獲取文件名  
            String fName=file.getName();  
            //判斷該文件是否為目錄,如為目錄,遞歸進(jìn)一步掃描其內(nèi)部所有文件  
            if(file.isDirectory()){  
                scanPkg(pkg+"."+fName);  
            }else{  
                //判定文件的后綴是否為.class  
                if(fName.endsWith(".class")){  
                    return true;  
                }  
            }  
            return false;  
        }  
    });   
    //遍歷所有符合標(biāo)準(zhǔn)的File文件  
    for(File f:fs){  
        //獲取文件名  
        String fName=f.getName();  
        //獲取去除.class之后的文件名  
        fName=fName.substring(0,fName.lastIndexOf("."));  
        //將名字(類名,通常為大寫開頭)的第一個(gè)字母轉(zhuǎn)換小寫(用它作為key存儲(chǔ)工廠中)  
        String key=String.valueOf(fName.charAt(0)).toLowerCase()+fName.substring(1);  
        //構(gòu)建一個(gè)類全名(包名.類名)  
        String pkgCls=pkg+"."+fName;  
        try{  
            //通過反射構(gòu)建類對(duì)象  
            Class c=Class.forName(pkgCls);  
            //判定這個(gè)類上是否有MyComponent注解  
            if(c.isAnnotationPresent(MyComponent.class)){  
                //將類對(duì)象存儲(chǔ)到map容器中  
                beanDefinationFacotry.put(key, c);  
            }  
        }catch(Exception e){  
            throw new RuntimeException(e);   
        }  
    }  
}

以上是初始化方法,在創(chuàng)建AnnotationConfigApplicationContext對(duì)象時(shí)即會(huì)掃描指定的包路徑,并加載類定義對(duì)象到容器中。

接下來(lái)定義getBean方法,用于獲取工廠所創(chuàng)建的對(duì)象:

/**
 * 根據(jù)傳入的bean的id值獲取容器中的對(duì)象,類型為Object
 */
public Object getBean(String beanId){
    //根據(jù)傳入beanId獲取類對(duì)象
    Class cls = beanDefinationFacotry.get(beanId);
    //根據(jù)類對(duì)象獲取其定義的注解
    MyComponent annotation = cls.getAnnotation(MyComponent.class);
    //獲取注解的scope屬性值
    String scope = annotation.scope();
    try {
        //如果scope等于singleton,創(chuàng)建單例對(duì)象
        if("singleton".equals(scope)){
            //判斷容器中是否已有該對(duì)象的實(shí)例,如果沒有,創(chuàng)建一個(gè)實(shí)例對(duì)象放到容器中
            if(singletonbeanFactory.get(beanId)==null){
                Object instance = cls.newInstance();
                setFieldValues(cls,instance);
                singletonbeanFactory.put(beanId,instance);
            }
            //根據(jù)beanId獲取對(duì)象并返回
            return singletonbeanFactory.get(beanId);
        }
        //如果scope等于prototype,則創(chuàng)建并返回多例對(duì)象
        if("prototype".equals(scope)){
            Object instance = cls.newInstance();
            setFieldValues(cls,instance);
            return instance;
        }
        //目前僅支持單例和多例兩種創(chuàng)建對(duì)象的方式
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    //如果遭遇異常,返回null
    return null;
}
/**
 * 此為重載方法,根據(jù)傳入的class對(duì)象在內(nèi)部進(jìn)行強(qiáng)轉(zhuǎn),
 * 返回傳入的class對(duì)象的類型
 */
public T getBean(String beanId, Class c){
    return (T)getBean(beanId);
}

在獲取對(duì)象時(shí)需要為其成員屬性賦值,調(diào)用了setFieldValue方法,因此定義該方法:

/**
 * 此方法用于為對(duì)象的屬性賦值
 * 內(nèi)部是通過獲取成員屬性上注解的值,在轉(zhuǎn)換為類型之后,通過反射為對(duì)象賦值
 * @param cls 類定義對(duì)象
 * @param obj 要為其賦值的實(shí)例對(duì)象
 */
public void setFieldValues(Class cls,Object obj){
    //獲取類中所有的成員屬性
    Field[] fields = cls.getDeclaredFields();
    //遍歷所有屬性
    for (Field field : fields) {
        //如果此屬性有MyValue注解修飾,對(duì)其進(jìn)行操作
        if(field.isAnnotationPresent(MyValue.class)){
            //獲取屬性名
            String fieldName = field.getName();
            //獲取注解中的值
            String value = field.getAnnotation(MyValue.class).value();
            //獲取屬性所定義的類型
            String type = field.getType().getName();
            //將屬性名改為以大寫字母開頭,如:id改為ID,name改為Name
            fieldName = String.valueOf(fieldName.charAt(0)).toUpperCase()+fieldName.substring(1);
            //set方法名稱,如:setId,setName...
            String setterName = "set" + fieldName;
            try {
                //根據(jù)方法名稱和參數(shù)類型獲取對(duì)應(yīng)的set方法對(duì)象
                Method method = cls.getDeclaredMethod(setterName, field.getType());
                //判斷屬性類型,如類型不一致,則轉(zhuǎn)換類型后調(diào)用set方法為屬性賦值
                if("java.lang.Integer".equals(type) || "int".equals(type)){
                    int intValue = Integer.valueOf(value);
                    method.invoke(obj, intValue);
                } else if("java.lang.String".equals(type)){
                    method.invoke(obj, value);
                }
                //作為測(cè)試,僅判斷Integer和String類型,其它類型同理
            } catch (NoSuchMethodException | SecurityException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}

定義close銷毀方法:

/** 
 * 銷毀方法,用于釋放資源 
 */  
public void close(){  
    beanDefinationFacotry.clear();  
    beanDefinationFacotry=null;  
    singletonbeanFactory.clear();  
    singletonbeanFactory=null;  
}

至此,該工廠類的內(nèi)容全部完成。接下來(lái)寫測(cè)試類:

測(cè)試類的內(nèi)容如下:

package springTest;  
  
import applicationContext.AnnotationConfigApplicationContext;  
import entity.PrototypeUser;  
import entity.SingletonUser;  
  
public class springIocTest {  
    public static void main(String[] args) {  
        //創(chuàng)建AnnotationConfigApplicationContext對(duì)象  
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("entity");  
        //僅使用key作為參數(shù)獲取對(duì)象,需要強(qiáng)轉(zhuǎn)  
        SingletonUser singletonUser1=(SingletonUser) ctx.getBean("singletonUser");  
        System.out.println("單例User對(duì)象:"+singletonUser1);  
        //使用key和類對(duì)象作為參數(shù)獲取對(duì)象,無(wú)需強(qiáng)轉(zhuǎn)  
        SingletonUser singletonUser2=ctx.getBean("singletonUser",SingletonUser.class);  
        System.out.println("單例User對(duì)象:"+singletonUser2);  
        //僅使用key作為參數(shù)獲取對(duì)象,需要強(qiáng)轉(zhuǎn)  
        PrototypeUser prototypeUser1=(PrototypeUser) ctx.getBean("prototypeUser");  
        System.out.println("多例User對(duì)象:"+prototypeUser1);  
        //使用key和類對(duì)象作為參數(shù)獲取對(duì)象,無(wú)需強(qiáng)轉(zhuǎn)  
        PrototypeUser prototypeUser2=ctx.getBean("prototypeUser",PrototypeUser.class);  
        System.out.println("多例User對(duì)象:"+prototypeUser2);  
        //銷毀資源  
        ctx.close();  
    }  
}

運(yùn)行此測(cè)試類,控制臺(tái)輸出結(jié)果如下:

可以看到,在創(chuàng)建單例對(duì)象時(shí),無(wú)參的構(gòu)造方法只調(diào)用了一次,并且兩次調(diào)用getBean方法獲取的對(duì)象是一致的。而在創(chuàng)建多例對(duì)象時(shí),無(wú)參的構(gòu)造方法被調(diào)用了兩次,兩次調(diào)用getBean所獲取的對(duì)象是不同的。

如果需要看對(duì)象的屬性是否注入成功,可以在兩個(gè)User類中增加toSrting方法

@Override
public String toString() {
    return "SingletonUser [id=" + id + ", name=" + name + ", password=" + password + "]";
}

再次執(zhí)行程序,結(jié)果如下:

從控制臺(tái)的輸處結(jié)果中可以看到,所獲取的每個(gè)對(duì)象都已經(jīng)有值。注意:這種為對(duì)象注入屬性值的方式耦合度較高,可根據(jù)情況使用。

寫在最后:由于手寫SpringIOC只是出于對(duì)Spring框架的理解,并非要寫一個(gè)可用的框架。因此在代碼中省略了大量的對(duì)于參數(shù)的判斷和異常處理,免去代碼的冗余,方便看官理解。高手請(qǐng)勿吐槽啊,若有問題或建議,歡迎留言指正。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/68431.html

相關(guān)文章

  • 手寫SpringDI依賴注入

    摘要:如感興趣,可移步手寫之基于動(dòng)態(tài)創(chuàng)建對(duì)象手寫之基于注解動(dòng)態(tài)創(chuàng)建對(duì)象今天將詳細(xì)介紹如何手寫依賴注入,在運(yùn)行過程中如何動(dòng)態(tài)地為對(duì)象的屬性賦值。完成后在中會(huì)有相關(guān)的包出現(xiàn)進(jìn)行注入前需要?jiǎng)?chuàng)建工廠,在運(yùn)行時(shí)從工廠中取出對(duì)象為屬性賦值。 前兩篇文章介紹了關(guān)于手寫Spring IOC控制反轉(zhuǎn),由Spring工廠在運(yùn)行過程中動(dòng)態(tài)地創(chuàng)建對(duì)象的兩種方式。如感興趣,可移步: 手寫Spring之IOC基于xml...

    Cruise_Chan 評(píng)論0 收藏0
  • 慕課網(wǎng)_《Spring入門篇》學(xué)習(xí)總結(jié)

    摘要:入門篇學(xué)習(xí)總結(jié)時(shí)間年月日星期三說(shuō)明本文部分內(nèi)容均來(lái)自慕課網(wǎng)。主要的功能是日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理等等。 《Spring入門篇》學(xué)習(xí)總結(jié) 時(shí)間:2017年1月18日星期三說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)示例源碼:https://github.com/zccodere/s...個(gè)人學(xué)習(xí)源碼:https://git...

    Ververica 評(píng)論0 收藏0
  • 手寫SpringIOC基于xml動(dòng)態(tài)創(chuàng)建對(duì)象

    Spring作為Java Web最為流行的框架之一,其功能之強(qiáng)大,封裝細(xì)節(jié)之全面不用過多贅述。使用Spring的方式很簡(jiǎn)單,不需要關(guān)注細(xì)節(jié),把對(duì)象的創(chuàng)建和對(duì)象之間的關(guān)系都交給框架來(lái)管理,僅僅做好配置文件和實(shí)現(xiàn)具體的業(yè)務(wù)邏輯即可。可以說(shuō)Spring為我們?cè)诰帉慗ava Web應(yīng)用時(shí)省去了大量重復(fù)的代碼,并且可以降低對(duì)象與對(duì)象之間的耦合度。但若只是知其然,而不知其所以然,在編程時(shí)也難免會(huì)遇到各種問題,...

    monw3c 評(píng)論0 收藏0
  • 明天面試?嚇得我趕緊手寫了一個(gè)Spring

    摘要:你都是如何回答面試官的問題的我不知道,我一般會(huì)通過手寫一個(gè)來(lái)加深自己的印象。如今,已然成為了一個(gè)生態(tài)。運(yùn)行階段主要是完成容器啟動(dòng)以后,完成用戶請(qǐng)求的內(nèi)部調(diào)度,并返回響應(yīng)結(jié)果。因此,要先寫一個(gè)針對(duì)類名首字母處理的工具方法。 引言 幾乎每個(gè)面試的程序員都會(huì)碰到Spring相關(guān)的面試問題,或淺或深。你都是如何回答面試官的問題的?——我不知道,我一般會(huì)通過手寫一個(gè)Spring來(lái)加深自己的印象。...

    stefanieliang 評(píng)論0 收藏0
  • Spring入門IOC和AOP學(xué)習(xí)筆記

    摘要:入門和學(xué)習(xí)筆記概述框架的核心有兩個(gè)容器作為超級(jí)大工廠,負(fù)責(zé)管理創(chuàng)建所有的對(duì)象,這些對(duì)象被稱為。中的一些術(shù)語(yǔ)切面切面組織多個(gè),放在切面中定義。 Spring入門IOC和AOP學(xué)習(xí)筆記 概述 Spring框架的核心有兩個(gè): Spring容器作為超級(jí)大工廠,負(fù)責(zé)管理、創(chuàng)建所有的Java對(duì)象,這些Java對(duì)象被稱為Bean。 Spring容器管理容器中Bean之間的依賴關(guān)系,使用一種叫做依賴...

    wenyiweb 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<