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