(spring-第10回【IoC基礎篇】)InstantiationStrategy--執行個體化Bean的第三大利器,instantiation

來源:互聯網
上載者:User

(spring-第10回【IoC基礎篇】)InstantiationStrategy--執行個體化Bean的第三大利器,instantiation

Bean的執行個體化整個過程如:

其中,BeanDefinition加入到註冊表中,並由BeanFactoryPostProcessor的實作類別處理後,需要由InstantiationStrategy負責執行個體化。執行個體化僅僅是調用建構函式,相當於new了一個對象而已,bean的具體的屬性在此時並未賦值(當然,一開始在XML中配置了Bean屬性的值,或者在建構函式中有指派陳述式的話,相關屬性才會在執行個體化的時候便有了值。)。InstantiationStrategy負責由Bean類的預設建構函式、帶參建構函式或者Factory 方法等來執行個體化Bean。下面是Instantiation

Strategy的繼承結構(注意下面是父類,上面是子類,實線是繼承,虛線是實現):

InstantiationStrategy只是一個策略性的介面。

SimpleInstantiationStrategy是InstantiationStrategy的實作類別,該類是一個簡單的用於Bean執行個體化的類,比如,由Bean類的預設建構函式、帶參建構函式或者Factory 方法等來執行個體化Bean。從中可以看出,該類有一個instantiationWithMethodInjection方法,但是實際上這隻是個鉤子(hook),並非真正支援方法注入功能。

方法注入:在大部分情況下,容器中的bean都是singleton類型的(預設),單例類型是指spring只會執行個體化一次bean,並將bean放到緩衝池中,把bean的引用(地址)返回給調用者。如果一個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來說這樣做就會有問題了,比如在調用一個singleton類型bean A的某個方法時,需要引用另一個prototype類型(每次調用都會重新執行個體化bean)的bean B,對於bean A來說,容器只會建立一次,這樣就沒法在需要的時候每次讓容器為bean A提供一個新的的bean B執行個體。也就是說,每次調用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動態產生子類,這個類叫代理類,在子類中產生方法注入的邏輯,然後使用這個動態產生的子類建立bean的執行個體。(具體瞭解該技術,請學習spring的AOP,面向切面編程。後面章節我會詳細講到)。

 

下面大概看一下預設調用的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沒有自己的建構函式,那麼使用反射機制調用預設的無參建構函式去執行個體化bean。最後,30行,拿到這個建構函式,執行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     }

第四行和第五行就是建立執行個體了(首先需要把得到的建構函式強設為可訪問)。

 

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

 

 

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

                                ——黃睎

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.