完成了XML配置文件的解析,接下来就是对bean加载的探索。
//2.从ioc容器中获取bean实例
MyTestBean myTestBean = (MyTestBean) beanFactory.getBean("myTestBean");
跟踪进Spring的源码
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
protected T doGetBean(String name, Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
// 1. 提取对应的beanName
final String beanName = this.transformedBeanName(name);
// 2. 直接尝试从缓存获取或者singletonFactories中的ObjectFactory中获取
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if (sharedInstance != null && args == null) {
if (this.logger.isDebugEnabled()) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 3.返回对应的实例,有时候存储诸如BeanFactory的情况并不是直接返回实例本身而是返回指定方法返回的实例
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
// 4.
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = this.getParentBeanFactory();
// 5.如果beanDefinitionMap中也就是在所有已经加载的类中不包括beanName,则尝试从parentBeanFactory中检测
if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
String nameToLookup = this.originalBeanName(name);
// 递归到BeanFactory中寻找
if (args != null) {
return parentBeanFactory.getBean(nameToLookup, args);
}
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
// 如果不是仅仅做类型检查则是创建bean,这里要进行记录
if (!typeCheckOnly) {
this.markBeanAsCreated(beanName);
}
try {
// 6.将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition,如果指定BeanName是子Bean的话同时会合并父类的相关属性
final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
String[] var11;
// 7.若存在依赖则需要递归实例化依赖的bean
if (dependsOn != null) {
var11 = dependsOn;
int var12 = dependsOn.length;
for(int var13 = 0; var13 < var12; ++var13) {
String dep = var11[var13];
if (this.isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 缓存依赖调用
this.registerDependentBean(dep, beanName);
this.getBean(dep);
}
}
// 8.singleton模式的创建
if (mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, new ObjectFactory
beanFactory.getBean(String name)
传入的参数,可能是别名,可能是beanName,也可能是FactoryBean,所以需要进行一系列的解析getObjectForBeanInstance
就是完成这个工作的 isPrototypeCurrentlyInCreation(beanName)
判断true一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean。
除此之外,Spring还提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。FactoryBean接口对于Spring来说很重要,它隐藏了实例化一些复杂bean的细节。
public interface FactoryBean<T> {
// 返回由FactoryBean创建的bean实例
// 如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中
T getObject() throws Exception;
// 返回FactoryBean创建的bean类型
Class> getObjectType();
// 返回由FactoryBean创建的bean实例的作用域是singleton还是prototype
boolean isSingleton();
}
当配置文件中
的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean.getObject()方法所返回的对象,相当于FactoryBean.getObject()代理了getBean()方法
public class Car {
private int maxSpeed;
private String brand;
private double price;
// get/set
}
如果使用传统方式配置Car的时候,Car的每个属性分别对应一个
元素标签
如果用FactoryBean的方式实现就会灵活一些
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo;
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;
}
public Class getObjectType() {
return Car.class;
}
public boolean isSingleton() {
return false;
}
public String getCarInfo() {
return this.carInfo;
}
public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
}
有了这个CarFactoryBean后,就可以如下配置了
<bean id="car" class="com.whyalwaysmea.factorybean.CarFactoryBean" >
<property name="carInfo" value="超级跑车,400,20000000" />
bean>
当调用getBean("car")
时,Spring通过反射机制发现CarFactoryBean实现了FactoryBean的接口,这时Spring容器就调用接口方法CarFactoryBean.getObject()方法返回。
如果希望获取CarFacoryBean的实例,则调用getBean("&car")