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
相关文章推荐
- Java Day 5
- 单例模式
- thnk in java上有趣的算法题1 吸血鬼数字
- 【ActiveMQ教程】简介
- 一个WebService入门实例
- Java正则表达式
- java jdbc
- java基础:String
- JAVA基础之正则表达式
- Java基础之时间
- Java基础之Json
- 华为机考Java版
- 设计模式——单例模式 Java源代码
- 团队开发之:eclipse自动格式化代码formatter使用方式
- 命令模式
- 团队开发之:eclipse注释模版使用方式
- 2015/12/25 ① 图灵测试 ② 安装jdk出现的问题 ③ 配置环境变量
- java中properties类的使用
- javaMap
- Log4j日志在java项目中的使用(附工程源码)