国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

(spring-第10回【IoC基礎篇】)InstantiationStrategy--實例化Bean的第三大利器

2019-11-14 15:01:06
字體:
供稿:網(wǎng)友

Bean的實例化整個過程如下圖:

其中,BeanDefinition加入到注冊表中,并由BeanFactoryPostPRocessor的實現(xiàn)類處理后,需要由InstantiationStrategy負責實例化。實例化僅僅是調(diào)用構(gòu)造函數(shù),相當于new了一個對象而已,bean的具體的屬性在此時并未賦值(當然,一開始在xml中配置了Bean屬性的值,或者在構(gòu)造函數(shù)中有賦值語句的話,相關屬性才會在實例化的時候便有了值。)。InstantiationStrategy負責由Bean類的默認構(gòu)造函數(shù)、帶參構(gòu)造函數(shù)或者工廠方法等來實例化Bean。下面是Instantiation

Strategy的繼承結(jié)構(gòu)(注意下面是父類,上面是子類,實線是繼承,虛線是實現(xiàn)):

InstantiationStrategy只是一個策略性的接口。

SimpleInstantiationStrategy是InstantiationStrategy的實現(xiàn)類,該類是一個簡單的用于Bean實例化的類,比如,由Bean類的默認構(gòu)造函數(shù)、帶參構(gòu)造函數(shù)或者工廠方法等來實例化Bean。從上圖中可以看出,該類有一個instantiationWithMethodInjection方法,但是實際上這只是個鉤子(hook),并非真正支持方法注入功能。

方法注入:在大部分情況下,容器中的bean都是singleton類型的(默認),單例類型是指spring只會實例化一次bean,并將bean放到緩沖池中,把bean的引用(地址)返回給調(diào)用者。如果一個singleton bean要引用另外一個singleton bean,或者一個prototype的bean引用另外一個prototype的bean時,通常情況下將一個bean定義為另一個bean的property值就可以了。就像下面這樣:

<bean id="boss" class="com.baobaotao.attr.Boss">        <property name="car">            <ref parent="car" />        </property>    </bean>

 

不過對于具有不同生命周期的bean來說這樣做就會有問題了,比如在調(diào)用一個singleton類型bean A的某個方法時,需要引用另一個prototype類型(每次調(diào)用都會重新實例化bean)的bean B,對于bean A來說,容器只會創(chuàng)建一次,這樣就沒法在需要的時候每次讓容器為bean A提供一個新的的bean B實例。也就是說,每次調(diào)用A時,我需要一個重新實例化的B。而由于A只會實例化一次,并且B是隨著A的實例化而實例化的,導致我得到的B也是沒有再次實例化的。這個時候就要使用方法注入。舉個簡單例子:

1 <bean id="car" class="com.baobaotao.injectfun.Car" 2         p:brand="紅旗CA72" p:price="2000" scope="prototype"/>3 4   <bean id="magicBoss" class="com.baobaotao.injectfun.MagicBoss" >5     <lookup-method name="getCar" bean="car"/>6   </bean>

使用lookup-method標簽,這樣,每次實例化magicBoss時就會加載它的getCar方法,如下:

public interface MagicBoss {   Car getCar(); }

由于lookup-method里面定義了bean="car",spring會自動實例化car。相當于在getCar()里面寫了一個實例化car的方法。

 

真正支持方法注入功能的是SimpleInstantiationStrategy的繼承類:CglibSubclassingInstantiationStrategy。它繼承了SimpleInstantiationStrategy并覆蓋了instantiationWithMethodInjection方法。不過使用這個方法必須用到cglib 類庫。它利用cglib為bean動態(tài)生成子類,這個類叫代理類,在子類中生成方法注入的邏輯,然后使用這個動態(tài)生成的子類創(chuàng)建bean的實例。(具體了解該技術(shù),請學習spring的AOP,面向切面編程。后面章節(jié)我會詳細講到)。

 

下面大概看一下默認調(diào)用的SimpleInstantiationStrategy的instantiate方法:

 1 public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) { 2         // Don't override the class with CGLIB if no overrides. 3         if (beanDefinition.getMethodOverrides().isEmpty()) { 4             Constructor<?> constructorToUse; 5             synchronized (beanDefinition.constructorArgumentLock) { 6                 constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod; 7                 if (constructorToUse == null) { 8                     final Class clazz = beanDefinition.getBeanClass(); 9                     if (clazz.isInterface()) {10                         throw new BeanInstantiationException(clazz, "Specified class is an interface");11                     }12                     try {13                         if (System.getSecurityManager() != null) {14                             constructorToUse = accessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {15                                 public Constructor run() throws Exception {16                                     return clazz.getDeclaredConstructor((Class[]) null);17                                 }18                             });19                         }20                         else {21                             constructorToUse =    clazz.getDeclaredConstructor((Class[]) null);22                         }23                         beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;24                     }25                     catch (Exception ex) {26                         throw new BeanInstantiationException(clazz, "No default constructor found", ex);27                     }28                 }29             }30             return BeanUtils.instantiateClass(constructorToUse);31         }32         else {33             // Must generate CGLIB subclass.34             return instantiateWithMethodInjection(beanDefinition, beanName, owner);35         }36     }

由于前期帖不會過多去講源碼,所以只是大概了解一下,從第7行和第21行可以看出:如果bean沒有自己的構(gòu)造函數(shù),那么使用反射機制調(diào)用默認的無參構(gòu)造函數(shù)去實例化bean。最后,30行,拿到這個構(gòu)造函數(shù),執(zhí)行BeanUtils.instantiateClass方法。下面是該方法:

 1 public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { 2         Assert.notNull(ctor, "Constructor must not be null"); 3         try { 4             ReflectionUtils.makeAccessible(ctor); 5             return ctor.newInstance(args); 6         } 7         catch (InstantiationException ex) { 8             throw new BeanInstantiationException(ctor.getDeclaringClass(), 9                     "Is it an abstract class?", ex);10         }11         catch (IllegalAccessException ex) {12             throw new BeanInstantiationException(ctor.getDeclaringClass(),13                     "Is the constructor accessible?", ex);14         }15         catch (IllegalArgumentException ex) {16             throw new BeanInstantiationException(ctor.getDeclaringClass(),17                     "Illegal arguments for constructor", ex);18         }19         catch (InvocationTargetException ex) {20             throw new BeanInstantiationException(ctor.getDeclaringClass(),21                     "Constructor threw exception", ex.getTargetException());22         }23     }

第四行和第五行就是創(chuàng)建實例了(首先需要把得到的構(gòu)造函數(shù)強設為可訪問)。

 

由InstantiationStrategy實例化的bean只是相當于生成了一個新對象,具體的屬性賦值工作還要由BeanWrapper結(jié)合屬性編輯器來完成。BeanWrapper和屬性編輯器將會在接下來的博文中詳細介紹。

 

 

          學而不知道,與不學同;知而不能行,與不知同。

                                ——黃睎


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 应城市| 宜阳县| 金堂县| 白银市| 大悟县| 于都县| 顺平县| 桑植县| 嘉善县| 炉霍县| 鹿泉市| 濮阳县| 改则县| 商河县| 中牟县| 南昌市| 葫芦岛市| 岚皋县| 靖远县| 石城县| 溆浦县| 博爱县| 桐庐县| 汉沽区| 长宁区| 陇西县| 南靖县| 岫岩| 海盐县| 济南市| 长丰县| 鄂尔多斯市| 卢龙县| 福海县| 大城县| 财经| 盐源县| 江油市| 蛟河市| 咸丰县| 寻甸|