三、从容器中取得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或管理者,你既要对你的工作了如指掌,同时还要把工作进行拆分,让团队中的不同角色去完成相对独立的模块;
- 软件在进行设计时,要充分考虑系统的模块及其耦合,如果能做到恰如其分的拆分,并行进行模块级别的开发,既会让效率大大提升,同时系统的质量也是令人赞扬的;
分享到:
相关推荐
当Spring容器遇到一个被标记为FactoryBean的Bean定义时,它不会直接实例化这个Bean,而是调用`getObject()`方法来获取实际需要的对象。 在实际应用中,工厂Bean有多种用途。例如: 1. **复杂初始化逻辑**:如果一...
java *spring工具类 方便在非spring管理环境中获取beanjava *spring工具类 方便在非spring管理环境中获取beanjava *spring工具类 方便在非spring管理环境中获取beanjava *spring工具类 方便在非spring管理环境中获取...
要从一个非Spring管理的类中获取Bean,我们需要先创建或获取`ApplicationContext`实例。有多种方式可以做到这一点,例如: 1. 通过`ClassPathXmlApplicationContext`或`FileSystemXmlApplicationContext`加载XML...
在多个项目整合且跨越Spring容器的情况下,获取Bean的实现方式可能更复杂。可以通过Spring的`ConfigurableApplicationContext`接口的`getBeanFactory()`方法获取`BeanFactory`,然后使用`BeanFactory`的`...
Prototype作用域是指每次通过容器的getBean()方法获取Bean时,Spring容器将创建一个新的Bean实例。Prototype作用域通常用于需要动态创建Bean实例的情况。 3. Request作用域 Request作用域是指对于一次HTTP请求,...
4. 获取 bean:应用程序可以从容器中获取 bean 并使用它。 在加载 bean 的过程中,Spring 会使用 Resource 对象来表示 XML 文件,然后使用 XmlBeanDefinitionReader 对象来解析 XML 文件,并将 bean 的定义注册到...
首先,我们从“tiny-spring-step-1-container-register-and-get.zip”开始,这是Spring容器的基础。这个步骤讲解了如何注册Bean并从容器中获取,这是Spring框架的核心功能之一。在这里,你会了解到BeanFactory是如何...
在Java Spring框架中,Spring IoC(Inversion of Control,控制反转)是核心特性之一,它使得应用程序的组件之间的依赖关系不再由代码直接管理,而是交由Spring IoC容器负责。这种设计模式降低了代码间的耦合,提高...
- **通过代码注解**:Spring也支持通过注解来获取Bean,如`@Autowired`和`@Resource`,它们能够自动将依赖注入到目标字段或方法中,无需手动从ApplicationContext获取。 3. **静态Singleton Bean Manager** 通常...
例如,`org.springframework.beans.factory.BeanFactory`接口定义了容器的基本操作,如获取Bean、初始化Bean等;`org.springframework.context.ApplicationContext`扩展了BeanFactory,提供了更多的企业级服务,如...
"深度解析spring容器管理bean"这一主题,旨在深入理解Spring如何通过反射机制、依赖注入(DI)以及XML或Java配置来实现对Bean的生命周期管理。 首先,Spring容器主要有两种类型:DefaultListableBeanFactory和...
在Spring框架中,动态注册Bean是一项非常实用的功能,它允许我们在应用运行时向Spring容器添加新的Bean定义。这种能力在很多场景下都是极其有用的,比如根据不同的环境配置加载不同的服务实现,或者在运行时根据某些...
- Spring容器中的Bean可以有不同的作用域。 - 默认作用域是单例(singleton),确保容器中只有一个共享实例。 - 除了单例作用域,还有原型(prototype)作用域,每次请求Bean都会创建一个新的实例。 7. Spring中...
5. **生命周期管理**:Spring容器负责Bean的生命周期,包括初始化、使用和销毁。我们可以自定义初始化和销毁方法,或者使用`@PostConstruct`和`@PreDestroy`注解。 6. **作用域**:Spring Bean有多种作用域,如单例...
5. **获取Bean实例**: 在预实例化过程中,`getBean(beanName)`被调用,这是`AbstractBeanFactory`类中的一个方法,用于从Bean工厂中获取指定名称的Bean实例。 6. **实际获取Bean**: 进入`doGetBean()`方法,这...
Spring把Bean放在这个容器中,普通的类在需要的时候,直接用getBean()方法取出
Spring Boot普通类调用bean【从零开始学Spring Boot】”旨在指导初学者如何在非Spring管理的类中访问和使用Spring容器中的bean。下面将详细讲解这个主题。 首先,了解Spring Boot的基础概念是必要的。Spring Boot...
在这个类中,我们定义了一个静态方法`getBean`,通过传入Bean的名称,可以从Spring容器中获取对应的Bean实例。 ##### 3. 通过公共方法获取其他对象 一旦`ApplicationContextUtil`被配置并初始化,就可以通过调用其...
依赖注入是Spring的核心特性,它允许Bean之间的依赖关系由Spring容器管理。我们可以使用@Autowired注解自动装配,也可以通过@Qualifier指定特定的Bean。此外,@Value可以注入基本类型或SpEL(Spring Expression ...