• [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的切面等。

  • 相关阅读:
    诸葛亮会议
    软件工程第十次作业——例行报告
    Beta阶段中间产物
    Beta冲刺贡献分数分配结果
    “Hello World!”团队第六周的第六次会议
    “Hello World!”团队第六周的第五次会议
    Beta发布文案+美工
    “Hello World!团队”Beta发布—视频链接+文案+美工
    软件工程第九次作业——例行报告
    “Hello World!”团队第五周第五次会议
  • 原文地址:https://www.cnblogs.com/jyyzzjl/p/5459335.html
Copyright © 2020-2023  润新知