[spring源碼學習]六、IOC源碼-BeanFactory和factory-bean


一、代碼實例

  在我們分析spring的IOC源碼的時候,發現除了配置標准的bean,並且通過getBean(beanName)的方法獲取到一個bean的實例外,似乎還有這不少其他獲取的方法,例如在第四節,我們發現得到bean實例后,在第26節,會判斷是否繼承了FactoryBean,然后調用它的方法獲取真實的bean,在配置文件中我們發現一個factory-bean方法,這些都說明,我們應該可以使用一個beanFactory獲取一個bean,此節重點討論這部分的實現。

  代碼如下:

  1、car類

package com.zjl.factorybean;

public class Car {
    public Car(String name) {
        this.name=name;
    }
    String name;
    public void run(){
        System.out.println(this.name+" is running");
    }
}

  2、person類

package com.zjl.factorybean;

public class Person {
    public Person(String name) {
        this.name=name;
    }
    public String name;
    public int age;
    
    public Car car;
    
    public void sayHello(){
        System.out.println(this.name+" say hello");
    }
    public Car createCar(){
        return new Car("奧迪");
    }
}

  3、用來獲取person的FactoryBean,必須繼承FactoryBean接口 

package com.zjl.factorybean;
import org.springframework.beans.factory.FactoryBean;

public class PersonFactory implements FactoryBean<Person> {
    String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Person getObject() throws Exception {
        return new Person(name);
    }

    @Override
    public Class<Person> getObjectType() {
        return Person.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

}

  4、配置文件

 <bean id="personFactory" class="com.zjl.factorybean.PersonFactory">
        <property name="name" value="zhangsan"></property>
    </bean>  
    
    <bean id="car" factory-method="createCar" factory-bean="personFactory"></bean>

  5、測試類

package com.zjl.factorybean;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;


public class Test {
    public static void main(String[] args) throws Exception {
        DefaultListableBeanFactory beanFacory=new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(beanFacory);
        reader.loadBeanDefinitions(new ClassPathResource("factorybean.xml"));
        
        Person person=(Person)beanFacory.getBean("personFactory");
        person.sayHello();
        Person person2=(Person)beanFacory.getBean("personFactory");
        System.out.println("person==person2 is "+(person==person2));
        
        Car car=(Car)beanFacory.getBean("car");
        car.run();
        Car car2=(Car)beanFacory.getBean("car");
        System.out.println("car==car2 is "+(car==car2));
    }
}

  6、測試結果

zhangsan say hello
person==person2 is true
奧迪 is running
car==car2 is true

  7、結論

  我們可以看到:

  a)通過getBean(beanName)方法獲取到的直接就是Person的實例,而不是BeanFactory或者PersonFactory的實例。

  b)每次獲取到的Person實例都是同一個,根據接口中的方法isSingleton方法,猜測於此有關

  c)bean的id為car,並沒有配置我們常見的class配置,他應該是執行了Person的createCar方法

  d)car也遵循單例模式

二、FactoryBean代碼解析

  1、通過我們對bean的加載過程,發現所有的配置無論是spring默認bean的 配置,還是客戶自定義的配置均無差別的被解析后存放在beanDefinitionMap中,所以解析配置文件過程不再重復。

  2、Person person=(Person)beanFacory.getBean("personFactory");生成bean過程與第四部分重復的跳過

  3、來到bean生成實例后的地方

bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd)

  4、進入方法,判斷如果是bean不是FactoryBean的實例且beanName是&開頭,拋出錯誤。是FactoryBean的實例,且以&開頭,則直接返回實例。

    將實例轉化為FactoryBean的實例,並且調用getObjectFromFactoryBean(factory, beanName, !synthetic)方法

  注:也就是我們要獲得定義的通過personFactory返回PersonFactory的實例,可以使用beanFacory.getBean("&personFactory")進行獲取,然后調用getObject也可以返回Person的實例,不過這個需要自己控制單例模式

    protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

        // Don't let calling code try to dereference the factory if the bean isn't a factory.
        if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }//bean不是FactoryBean的實例且beanName是&開頭,報錯 // Now we have the bean instance, which may be a normal bean or a FactoryBean.
        // If it's a FactoryBean, we use it to create a bean instance, unless the
        // caller actually wants a reference to the factory.
     //bean是FactoryBean的實例,且beanName以&開頭,返回實例
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } Object object = null; if (mbd == null) { object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // Return bean instance from factory. FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // Caches object obtained from FactoryBean if it is a singleton. if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; }

  5、調用factory實例的isSingleton方法和containsSingleton(beanName),判斷是否是單例模式,單例模式的話,從factoryBeanObjectCache中嘗試讀取,否則直接生成。

  注:我們可以看到,通過FactoryBean的對象是否是單例模式取決於bean定義的范圍和方法isSingleton同時為單例才可以

    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
        if (factory.isSingleton() && containsSingleton(beanName)) {
            synchronized (getSingletonMutex()) {
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
            //入口,調用getObject方法 object
= doGetObjectFromFactoryBean(factory, beanName); // Only post-process and store if not put there already during getObject() call above // (e.g. because of circular reference processing triggered by custom getBean calls) Object alreadyThere = this.factoryBeanObjectCache.get(beanName); if (alreadyThere != null) { object = alreadyThere; } else { if (object != null && shouldPostProcess) { try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex); } } this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT)); } } return (object != NULL_OBJECT ? object : null); } } else { Object object = doGetObjectFromFactoryBean(factory, beanName); if (object != null && shouldPostProcess) { try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); } } return object; } }

  6、doGetObjectFromFactoryBean中調用getObject方法,返回實例

  7、調用bean后處理postProcessObjectFromFactoryBean並放入緩存factoryBeanObjectCache

  到此,我們已經獲取到了真正的bean,並且也知道了怎么獲取原來定義的FactoryBean的實例,但是,似乎少了一個方法,那就說FactoryBean中的getObjectType,我們需要回頭去找哪里漏掉了

  我翻遍了源代碼,並沒有找到此方法調用的地方,事實上通過改動

    @Override
    public Class<Car> getObjectType() {
        return Car.class;
    }

或者 

    @Override
    public Class<Person> getObjectType() {
        return null;
    }

都不會影響代碼執行結果的正確性,那么我們猜想,是否僅僅是一個預留,並無實際用處,或者客戶自定義使用方法。

三、FactoryBean實例

  在上一步查找源代碼過程中,我們有了新的發現,spring自定義了抽象類AbstractFactoryBean和大量他的子類,包括我們常見的list,map,set,object等,我們也來研究下

1、首先是他的繼承關系

public abstract class AbstractFactoryBean<T>
        implements FactoryBean<T>, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {

我們看到繼承了幾個熟悉的接口,包括FactoryBean和InitializingBean,還有幾個BeanClassLoaderAware, BeanFactoryAware, DisposableBean,這些接口分別是:

FactoryBean:通過getObjectBean生成bean實例

InitializingBean:在實例化后執行afterPropertiesSet方法

以上我們比較熟悉,其余三個接口簡單了解下

BeanClassLoaderAware:注入classLoad

BeanFactoryAware:注入一個BeanFactory

DisposableBean:銷毀bean默認調用destroy方法

我們這里重點關注FactoryBean的三個接口實現:

2、是否單例,通過外部注入

    public boolean isSingleton() {
        return this.singleton;
    }

3、getObject方法,如果是單例且已經創建,返回單例模式,未創建調用getEarlySingletonInstance方法,不是單例模式,調用createInstance方法

    @Override
    public final T getObject() throws Exception {
        if (isSingleton()) {
            return (this.initialized ? this.singletonInstance : getEarlySingletonInstance());
        }
        else {
            return createInstance();
        }
    }

4、getEarlySingletonInstance方法,通過第5步判斷,是否為接口,如果是通過動態代理,創建對象

    private T getEarlySingletonInstance() throws Exception {
        Class<?>[] ifcs = getEarlySingletonInterfaces();
        if (ifcs == null) {
            throw new FactoryBeanNotInitializedException(
                    getClass().getName() + " does not support circular references");
        }
        if (this.earlySingletonInstance == null) {
            this.earlySingletonInstance = (T) Proxy.newProxyInstance(
                    this.beanClassLoader, ifcs, new EarlySingletonInvocationHandler());
        }
        return this.earlySingletonInstance;
    }

5、此處調用getObjectType,判斷是否為空或者是否為接口,如果是,返回,否則為空

    protected Class<?>[] getEarlySingletonInterfaces() {
        Class<?> type = getObjectType();
        return (type != null && type.isInterface() ? new Class<?>[] {type} : null);
    }

6、動態代理的InvocationHandler 類,似乎什么都沒干,存疑

private class EarlySingletonInvocationHandler implements InvocationHandler {

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (ReflectionUtils.isEqualsMethod(method)) {
                // Only consider equal when proxies are identical.
                return (proxy == args[0]);
            }
            else if (ReflectionUtils.isHashCodeMethod(method)) {
                // Use hashCode of reference proxy.
                return System.identityHashCode(proxy);
            }
            else if (!initialized && ReflectionUtils.isToStringMethod(method)) {
                return "Early singleton proxy for interfaces " +
                        ObjectUtils.nullSafeToString(getEarlySingletonInterfaces());
            }
            try {
                return method.invoke(getSingletonInstance(), args);
            }
            catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }
    }

分析到這里,似乎這個類什么都沒做,我們具體看個實例類ListFactoryBean,此類注入了以下參數:

a、sourceList是一個list

b、targetListClass是一個Class

c、重寫了createInstance(),將sourceList修改后注入

public class ListFactoryBean extends AbstractFactoryBean<List<Object>> {

    private List<?> sourceList;

    @SuppressWarnings("rawtypes")
    private Class<? extends List> targetListClass;


    /**
     * Set the source List, typically populated via XML "list" elements.
     */
    public void setSourceList(List<?> sourceList) {
        this.sourceList = sourceList;
    }

    /**
     * Set the class to use for the target List. Can be populated with a fully
     * qualified class name when defined in a Spring application context.
     * <p>Default is a {@code java.util.ArrayList}.
     * @see java.util.ArrayList
     */
    @SuppressWarnings("rawtypes")
    public void setTargetListClass(Class<? extends List> targetListClass) {
        if (targetListClass == null) {
            throw new IllegalArgumentException("'targetListClass' must not be null");
        }
        if (!List.class.isAssignableFrom(targetListClass)) {
            throw new IllegalArgumentException("'targetListClass' must implement [java.util.List]");
        }
        this.targetListClass = targetListClass;
    }


    @Override
    @SuppressWarnings("rawtypes")
    public Class<List> getObjectType() {
        return List.class;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected List<Object> createInstance() {
        if (this.sourceList == null) {
            throw new IllegalArgumentException("'sourceList' is required");
        }
        List<Object> result = null;
        if (this.targetListClass != null) {
            result = BeanUtils.instantiateClass(this.targetListClass);
        }
        else {
            result = new ArrayList<Object>(this.sourceList.size());
        }
        Class<?> valueType = null;
        if (this.targetListClass != null) {
            valueType = GenericCollectionTypeResolver.getCollectionType(this.targetListClass);
        }
        if (valueType != null) {
            TypeConverter converter = getBeanTypeConverter();
            for (Object elem : this.sourceList) {
                result.add(converter.convertIfNecessary(elem, valueType));
            }
        }
        else {
            result.addAll(this.sourceList);
        }
        return result;
    }

}
ListFactoryBean

7、配置文件

        <bean id="list" class="org.springframework.beans.factory.config.ListFactoryBean">
            <property name="targetListClass">
                <value>java.util.ArrayList</value>
            </property>
            <property name="sourceList">
                <list>
                    <value>zhangsan</value>
                    <value>lisi</value>
                    <value>wangwu</value>
                </list>
            </property>
        </bean>

8、測試代碼

    public static void main(String[] args) throws Exception {
        DefaultListableBeanFactory beanFacory=new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(beanFacory);
        reader.loadBeanDefinitions(new ClassPathResource("factorybean.xml"));
        
        @SuppressWarnings("unchecked")
        List<String> list=(List<String>)beanFacory.getBean("list");
        System.out.println(list.toString());

    }

四、factory-bean的源碼解析

1、與之前解析類似,直到進入,如果有beancalss,直接返回beanClass,此處返回值為null

protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
            throws CannotLoadBeanClassException {
        try {
            if (mbd.hasBeanClass()) {
                return mbd.getBeanClass();
            }
            if (System.getSecurityManager() != null) {
                return AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
                    @Override
                    public Class<?> run() throws Exception {
                        return doResolveBeanClass(mbd, typesToMatch);
                    }
                }, getAccessControlContext());
            }
            else {
                return doResolveBeanClass(mbd, typesToMatch);
            }
        }
        catch (PrivilegedActionException pae) {
            ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
        }
        catch (ClassNotFoundException ex) {
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
        }
        catch (LinkageError err) {
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
        }
    }

2、開始創建bean實例,判斷是否有beanClass,如果有FactoryMethodname,調用instantiateUsingFactoryMethod(beanName, mbd, args)

    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
        // Make sure bean class is actually resolved at this point.
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }

        if (mbd.getFactoryMethodName() != null)  {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

3、進入instantiateUsingFactoryMethod方法,判斷factoryBeanName是否為空,如果不為空,判斷是否為自身,自身則報錯。不是自身,獲取factoryBean和factoryClass,設定為非靜態;如果factoryBeanName為空,且沒有classname則報錯,有的話,獲得factoryClass,設定為靜態

注:此處應該是由兩種方式,一種通過其他bean來生成,一種是通過class的靜態方法生成

String factoryBeanName = mbd.getFactoryBeanName();
        if (factoryBeanName != null) {
            if (factoryBeanName.equals(beanName)) {
                throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                        "factory-bean reference points back to the same bean definition");
            }
            factoryBean = this.beanFactory.getBean(factoryBeanName);
            if (factoryBean == null) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "factory-bean '" + factoryBeanName + "' (or a BeanPostProcessor involved) returned null");
            }
            if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
                throw new IllegalStateException("About-to-be-created singleton instance implicitly appeared " +
                        "through the creation of the factory bean that its bean definition points to");
            }
            factoryClass = factoryBean.getClass();
            isStatic = false;
        }
        else {
            // It's a static factory method on the bean class.
            if (!mbd.hasBeanClass()) {
                throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                        "bean definition declares neither a bean class nor a factory-bean reference");
            }
            factoryBean = null;
            factoryClass = mbd.getBeanClass();
            isStatic = true;
        }

4、從factoryClass中檢查是否有FactoryBeanMethod,此處獲得的是數組,說明可能可以根據重寫的方法和參數生成不同的bean

factoryClass = ClassUtils.getUserClass(factoryClass);

            Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
            List<Method> candidateSet = new ArrayList<Method>();
            for (Method candidate : rawCandidates) {
                if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
                    candidateSet.add(candidate);
                }
            }
            Method[] candidates = candidateSet.toArray(new Method[candidateSet.size()]);
            AutowireUtils.sortFactoryMethods(candidates);

5、進入instantiate,反射生成真正的bean

public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner,
            Object factoryBean, final Method factoryMethod, Object... args) {

        try {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    @Override
                    public Object run() {
                        ReflectionUtils.makeAccessible(factoryMethod);
                        return null;
                    }
                });
            }
            else {
                ReflectionUtils.makeAccessible(factoryMethod);
            }

            Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
            try {
                currentlyInvokedFactoryMethod.set(factoryMethod);
                return factoryMethod.invoke(factoryBean, args);
            }
            finally {
                if (priorInvokedFactoryMethod != null) {
                    currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
                }
                else {
                    currentlyInvokedFactoryMethod.remove();
                }
            }
        }

到這里bean就真正的生成了

 五、bean-factory驗證

主要需要驗證的有兩點:

1、如過沒有factory-bean,我們可以使用一個class的靜態方法進行生成bean

2、可以使用多個重寫的方法選擇進行生成bean,參數可以從外部傳遞

 我們增加一個CarFactory類,其中有一個靜態方法createCar()

public class CarFactory {
    public static Car createCar(){
        return new Car();
    }
}

修改Car類,與一般的bean相同

package com.zjl.factorybean;

public class Car {
    public Car() {
    }
    String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void run(){
        System.out.println(this.name+" is running");
    }
}

編寫配置文件

   <bean id="car" factory-method="createCar" class="com.zjl.factorybean.CarFactory"><!-- 使用class的靜態方法 -->
       <property name="name" value="奔馳"></property><!-- 屬性注入 -->
   </bean>

測試類:

public class Test {
    public static void main(String[] args) throws Exception {
        DefaultListableBeanFactory beanFacory=new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(beanFacory);
        reader.loadBeanDefinitions(new ClassPathResource("factorybean.xml"));

        Car car=(Car)beanFacory.getBean("car");
        car.run();
        Car car2=(Car)beanFacory.getBean("car");
        System.out.println("car==car2 is "+(car==car2));
    }
}

結果:

奔馳 is running
car==car2 is true

可以看到,結果跟我們在閱讀源碼時候的猜想完全一致

六、總結

1、FactoryBean與factory-bean的作用都是通過其他的一個bean工廠產生一個真實的bean,不同的是,FactoryBean是使用了spring默認的接口,具有一定侵入性,對框架造成依賴,factory-bean不會改變代碼接口,屬於注入方式。spring中很多類似的組隊,比如init-method和InitializingBean。

2、從原則上,我們使用spring,很大的優點在於它沒有侵略性。那么為什么會提供接口形式呢。接口形式更傾向於框架的使用,比如spirng的另一個重要的特性AOP,框架編寫了AOPFactoryBean,我們不需要知道他內部實現,也不會獲取他的實力,只需要配置它需要代理的類和接口,便可以成功返回一個真實的bean,也就是目標類的代理類,從而完成各種工作。

3、可以說spirng的很多擴展工作都是基於預留接口提供,同時新擴展的功能也會提供新的預留接口,比如aop的切面等。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM