三、从容器中取得bean
1、前面体会到了一点,那就是解析bean的职责分工;在这里,这个特点又有充分的体现;
2、如何取得bean?
- 当应用程序通过beanFactory.getBean("simpleBean")从容器中取得bean实例时,处理该请求的是AbstractBeanFactory中的以下方法:
protected Object doGetBean(
final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean = null;
// 看是否能取到单例对象,这里调用的是DefaultSingletonBeanRegistry的方法
// DefaultSingletonBeanRegistry负责管理单例的bean,这个我们在后面会谈到
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 这里处理与FactoryBean相关的逻辑
// 1 如果不是FactoryBean,直接返回
// 2 如果是FactoryBean,且beanName以&开头,则直接返回FactoryBean
// 3 如果不是以上两者,则通过factoryBean.getObject()取到工厂生产的bean实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 如果当前的bean正在创建中,则说明是循环引用,这是不允许的
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 如果当前容器中没有该bean的定义信息,则检查父容器中是否存在指定beanName的实例
// 由上一节可知,DefaultListableBeanFactory主要负责BeanDefinition的注册
// 这里调用的containsBeanDefinition(beanName)是由DefaultListableBeanFactory实现的
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
// 取得合并后的beanDefinition信息,然后cache起来
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// depend-on属性定义的前置bean,就是在这里创建的,看下面调用了getBean方法
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (int i = 0; i < dependsOn.length; i++) {
String dependsOnBean = dependsOn[i];
getBean(dependsOnBean);
// 同时注册depend-on的bean与原bean的关系,主要是销毁bean时,要先销毁depend-on的bean
// 这个功能是由DefaultSingletonBeanRegistry来完成的
registerDependentBean(dependsOnBean, beanName);
}
}
// 到现在,创建bean的条件都准备好了
// 如果bean是单例,由DefaultSingletonBeanRegistry来完成单例的创建工作
if (mbd.isSingleton()) {
// 这里通过新产生一个ObjectFactory来创建并注册一个单例bean
sharedInstance = getSingleton(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
try {
// 很巧妙地又将创建bean的主动权收回给自己
// 虽然最后创建bean的工作还是委托给了专门负责这一块的
// AbstractAutowireCapableBeanFactory来完成
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
// 这里和前面的一样,拿到单例bean后,又检查一下是否是FactoryBean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 如果是原型bean
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
// 在创建原型bean前,将beanName放在prototypesCurrentlyInCreation中,避免循环创建
beforePrototypeCreation(beanName);
// 由子类AbstractAutowireCapableBeanFactory来完成bean的创建工作
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// 创建完成后,清理一下现场
afterPrototypeCreation(beanName);
}
// 同样是检查是否是FactoryBean
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 其它类型的bean
else {
String scopeName = mbd.getScope();
final Scope scope = (Scope) this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
// 其它类型的scope,其创建bean的实现方式,和前面创建singleton一样
Object scopedInstance = scope.get(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
// 由子类AbstractAutowireCapableBeanFactory来完成bean的创建工作
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
// 同样是检查是否是FactoryBean
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
// 检查bean的类型是否是继承或实现自requiredType
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return bean;
}
2 代码流程
- getBean()一开始就检查单例容器中是否存在指定的bean实例,这是因为容器通过beanName不能确定容器是单例还是原型,如果单例的bean存在,当然是单例优先,这个也没什么异议;
- 根据beanName找到对应的BeanDefinition定义,这里还是有一点不太明白的地方,就是getMergedLocalBeanDefinition()这个方法;
- 如果是单例,创建并注册到单例容器,这样下次取单例bean时,直接就从上面第一步就取到了;
- 如果是原型或其它类型,则直接委托子类创建bean实例;
3、小结
- 取得bean的工作,完全是由AbstractBeanFactory来完成的;
- 如果是单例的bean,则由其父类DefaultSingletonRegistry来管理;
- 不管是单例还是原型或是其它类型的bean,AbstractBeanFactory都把创建bean的工作回收给自己的模板方法,然后交由子类AbstractAutowireCapableBeanFactory专门做这件事情;
- 通过这篇解读,可以从中了解到,Rod在写Spring框架时,Spring框架所要完成的几部分工作以及该由哪些类去完成,这些思想已经很到位了;这也可以延伸到工作中:
- 作为一件事情的owner或管理者,你既要对你的工作了如指掌,同时还要把工作进行拆分,让团队中的不同角色去完成相对独立的模块;
- 软件在进行设计时,要充分考虑系统的模块及其耦合,如果能做到恰如其分的拆分,并行进行模块级别的开发,既会让效率大大提升,同时系统的质量也是令人赞扬的;
分享到:
相关推荐
使用了ApplicationContextAware接口,获取spring管理的bean; 多项目整合夸spring容器获取bean的实现方式。
Spring把Bean放在这个容器中,普通的类在需要的时候,直接用getBean()方法取出
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中获取Spring配置的bean呢...下面通过本文给大家介绍Java中Spring获取bean方法小结,对spring获取bean方法相关知识感兴趣的朋友一起学习吧
本篇将对定义在 XMl 文件中的 bean,从静态的的定义到变成可以使用的对象的过程,即 bean 的加载和获取的过程进行一个整体的了解
主要介绍了Spring实战之让Bean获取Spring容器操作,结合实例形式分析了Bean获取Spring容器的相关原理、实现方法及操作注意事项,需要的朋友可以参考下
12.2.2. 在Spring的application context中创建 SessionFactory 12.2.3. HibernateTemplate 12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. ...
这些方法都是 IOC 容器的基本行为,不关心 Bean 是如何定义和加载的,而是关心如何从 IOC 容器中获取 Bean 实例。 三、XmlBeanFactory XmlBeanFactory 是 Spring 提供的一种 IOC 容器的实现,它使用 Xml 文件来...
NULL 博文链接:https://mengqingyu.iteye.com/blog/568935
Spring的生命周期是指实例化Bean时所经历的一系列阶段,即通过getBean()获取bean对象及...Bean的生命周期从Spring容器实例化Bean到销毁Bean。 本文分别对 BeanFactory 和 ApplicationContext 中的生命周期进行分析。
目的:Spring容器已经成功获取了UserController实例,并通过调用实例中的方法执行了各层中的输出语句。 运行结果为: User [id=1, name=张三, password=123] userDao say hello world! UserService say hello world ...
主要介绍了JSP 获取spring容器中bean的方法总结的相关资料,需要的朋友可以参考下
一般Spring容器默认Bean的作用域为singleton 2>prototype: 与singleton相反, 每次通过容器的getBean()方法获取该作用域下的Bean时都将产生一个新的Bean实例 3>request: 对于同一次Http请求,request作用域下的...
本文通过实例代码给大家详解了springboot获取ioc容器中注入的bean问题,非常不错,具有一定的参考借鉴价值,需要的朋友参考下吧
熊小泉 关于 tiny-spring是简化版的spring框架,能帮助您...定义一个简单的bean容器BeanFactory,内部包含一个地图可以保存bean,只有注册bean和获取bean两个方法 public class BeanFactory { private Map<String> bea
spring开发基础部分, Spring框架:核心技术:IOC和AOP 搭建开发环境: 1> 下载开发包,在工程中添加jar包; a> IOC:spring-core.jar\spring-context.jar\spring-test.jar\spring-beans....c> 从容器中获取bean的方法
如果bean的作用域的属性被声明为 singleton, 那么Spring Ioc容器只会创建一个共享的bean实例。对于所有的bean请求,只要id与该bean定义的相匹配,那么Spring在每次需要时都返回同一个bean实例。 Singleton是单例...
在 UserManageTest 类中,我们首先需要创建一个 Spring 的应用上下文对象 ApplicationContext,然后使用该对象来获取一个名为 oneUserInfoManage 的 bean。接着,我们可以使用该 bean 来调用 doUserLogin 方法,并将...
12.2.2. 在Spring容器中创建 SessionFactory 12.2.3. The HibernateTemplate 12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的...
ApplicationContext 是 Spring 框架中的核心组件之一,负责加载和管理应用程序中的 Bean 对象。在 Web 应用程序中,ApplicationContext 的加载机制是非常重要的, Spring 提供了多种方式来加载 ApplicationContext。...
实例工厂 <bean bean-factory="" factory-method=""> 管理对象 对象关系DI 构造器注入<construct-arg> set注入 生命周期 scope:prototype/singleton init-method destroy-method API ...