spring 从bean实例中获取对象

简介: spring 从bean实例中获取对象标签:spring源码分析主要方法:AbstractBeanFactory类的getObjectForBeanInstance方法protected Object getObjectForBeanInstance( Object beanInstance, String name, String

spring 从bean实例中获取对象

标签:spring源码分析


主要方法:AbstractBeanFactory类的getObjectForBeanInstance方法

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方法中。

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实例的方法

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;
    }

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

ApplicationContext bf = new ClassPathXmlApplicationContext("lookupTest.xml");
        Car car = (Car) bf.getBean("car");
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;
    }
}
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配置

<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

目录
相关文章
|
8天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
1月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
66 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
27天前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
69 1
|
1月前
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
37 1
|
1月前
|
前端开发 Java Spring
【Spring】“请求“ 之传递单个参数、传递多个参数和传递对象
【Spring】“请求“ 之传递单个参数、传递多个参数和传递对象
102 2
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
84 1
|
1月前
|
存储 Java 程序员
SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解
本文详细讲解了Spring框架中IOC容器如何存储和取出Bean对象,包括五大类注解(@Controller、@Service、@Repository、@Component、@Configuration)和方法注解@Bean的用法,以及DI(依赖注入)的三种注入方式:属性注入、构造方法注入和Setter注入,并分析了它们的优缺点。
27 0
SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解
|
2月前
|
XML Java 数据格式
spring复习03,注解配置管理bean
Spring框架中使用注解配置管理bean的方法,包括常用注解的标识组件、扫描组件、基于注解的自动装配以及使用注解后的注意事项,并提供了一个基于注解自动装配的完整示例。
spring复习03,注解配置管理bean
|
5月前
|
Java 开发者 Spring
解析Spring中Bean的生命周期
解析Spring中Bean的生命周期
54 2