您的位置:首页 > 编程语言 > Java开发

spring 从bean实例中获取对象

2015-12-26 00:26 609 查看

spring 从bean实例中获取对象

标签:spring源码分析

主要方法:AbstractBeanFactory类的getObjectForBeanInstance方法

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

//如果beanName以"&"符号开头,则是要获取Factorybean,如果该beanInstance不是FactoryBean类型,则抛出异常
        if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }

//现在我们获取的beanInstance可能是一个正常的bean或者是FactoryBean
如果不是FactoryBean,我们就直接返回该beanInstance
如果是FactoryBean,并且beanName以"&"符号开头,我们直接返回该beanInstance
        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }
//经过以上的判断 现在我们已经明确知道该beanInstance是FactoryBean
        Object object = null;
        if (mbd == null) {
            //尝试从缓存中加载bean
            object = getCachedObjectForFactoryBean(beanName);
        }
        if (object == null) {
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            //检查已经加载的类中是否有该beanName,如果该bean 是子bean则会合并父类的相关属性
            if (mbd == null && containsBeanDefinition(beanName)) {
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            //这里是判断该bean definition是不是用户自己定义的,
            //如果为true则指代那些不是用户自己定义的bean 如<aop:config>引入的auto-proxying类的bean,false指代用户自己定义的bean 如通过xml配置文件配置的bean
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }


之后调用getObjectFromFactoryBean方法获取bean实例,但该方法仍是做了一些预处理真正的调用在doGetObjectFromFactoryBean方法中。

[code]protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
//如果该FactoryBean是单例,则可以先从缓存中获取该bean实例,如果不是单例模式则直接调用doGetObjectFromFactoryBean方法。
//spring中单例bean都是先从缓存中获取,如果获取不到在去调用doxxx方法去生成该单例bean,这样可以提高性能。
        if (factory.isSingleton() && containsSingleton(beanName)) {
            synchronized (getSingletonMutex()) {
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
                    object = doGetObjectFromFactoryBean(factory, beanName);
//在上面的doGetObjectFromFactoryBean方法中,如果存在循环引用,会导致该方法被调用两次,此时该beanName已经被加入了factoryBeanObjectCache缓存,可以直接返回结果,否则加入到缓存中去
//另一方面,加了这个判断也可以防止postProcessObjectFromFactoryBean方法被调用多次。
                    Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                    if (alreadyThere != null) {
                        object = alreadyThere;
                    }
                    else {
                        if (object != null && shouldPostProcess) {
                            try {
//bean加载的另一个特点就是在bean实例化结束都尽量调用BeanPostProcessor里面的方法                           
                                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;
        }
    }


真正从FactoryBean获取bean实例的方法

[code]private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
            throws BeanCreationException {

        Object object;
        try {
        //权限验证
            if (System.getSecurityManager() != null) {
                AccessControlContext acc = getAccessControlContext();
                try {
                    object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        @Override
                        public Object run() throws Exception {
                                return factory.getObject();
                            }
                        }, acc);
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
            //调用FactoryBean的getObject方法获取最终的bean实例
                object = factory.getObject();
            }
        }
        catch (FactoryBeanNotInitializedException ex) {
            throw new BeanCurrentlyInCreationException(beanName, ex.toString());
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
        }

//如果该FactoryBean还没有初始化完成,并且从FactoryBean中获取的bean实例为空则抛出异常。这是因为在很多情况下,可能由于FactoryBean没有完全初始化完成,导致调用FactoryBean中的getObject方法返回为空。
        if (object == null && isSingletonCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(
                    beanName, "FactoryBean which is currently in creation returned null from getObject");
        }
        return object;
    }


最后附上跟着书上讲解做实验的代码:

测试代码:

[code]ApplicationContext bf = new ClassPathXmlApplicationContext("lookupTest.xml");
        Car car = (Car) bf.getBean("car");


[code]public class Car {
private int maxSpeed;
private String brand;
private double price;

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}


[code]public class CarFactoryBean implements FactoryBean<Car> {
    private String carInfo;
    @Override public Car getObject() throws Exception {
        Car car = new Car();
        String[] infos = carInfo.split(",");
        car.setBrand(infos[0]);
        car.setMaxSpeed(Integer.valueOf(infos[1]));
        car.setPrice(Double.valueOf(infos[2]));
        return car;
    }

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

    @Override public boolean isSingleton() {
        return true;
    }
    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }
}


xml配置

[code]<bean id="car" class="lq.CarFactoryBean" lazy-init="true">
        <property name="carInfo" value="超级跑车,400,200000"/>
    </bean>


doGetObjectFromFactoryBean方法跟书上源码有变动,主要是因为一个bug修复,链接:https://jira.spring.io/browse/SPR-11937
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: