`
diecui1202
  • 浏览: 97948 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Spring 5-从容器中取得bean

阅读更多

三、从容器中取得bean

1、前面体会到了一点,那就是解析bean的职责分工;在这里,这个特点又有充分的体现;
2、如何取得bean?
  1. 当应用程序通过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 代码流程

    1. getBean()一开始就检查单例容器中是否存在指定的bean实例,这是因为容器通过beanName不能确定容器是单例还是原型,如果单例的bean存在,当然是单例优先,这个也没什么异议;
    2. 根据beanName找到对应的BeanDefinition定义,这里还是有一点不太明白的地方,就是getMergedLocalBeanDefinition()这个方法;
    3. 如果是单例,创建并注册到单例容器,这样下次取单例bean时,直接就从上面第一步就取到了;
    4. 如果是原型或其它类型,则直接委托子类创建bean实例;
3、小结
  1. 取得bean的工作,完全是由AbstractBeanFactory来完成的;
  2. 如果是单例的bean,则由其父类DefaultSingletonRegistry来管理;
  3. 不管是单例还是原型或是其它类型的bean,AbstractBeanFactory都把创建bean的工作回收给自己的模板方法,然后交由子类AbstractAutowireCapableBeanFactory专门做这件事情;
  4. 通过这篇解读,可以从中了解到,Rod在写Spring框架时,Spring框架所要完成的几部分工作以及该由哪些类去完成,这些思想已经很到位了;这也可以延伸到工作中:
    1. 作为一件事情的owner或管理者,你既要对你的工作了如指掌,同时还要把工作进行拆分,让团队中的不同角色去完成相对独立的模块;
    2. 软件在进行设计时,要充分考虑系统的模块及其耦合,如果能做到恰如其分的拆分,并行进行模块级别的开发,既会让效率大大提升,同时系统的质量也是令人赞扬的;
分享到:
评论

相关推荐

    spring学习----工厂Bean

    当Spring容器遇到一个被标记为FactoryBean的Bean定义时,它不会直接实例化这个Bean,而是调用`getObject()`方法来获取实际需要的对象。 在实际应用中,工厂Bean有多种用途。例如: 1. **复杂初始化逻辑**:如果一...

    在非spring注解类中使用spring容器中的bean_普通类中使用yml配置文件中的配置信息

    要从一个非Spring管理的类中获取Bean,我们需要先创建或获取`ApplicationContext`实例。有多种方式可以做到这一点,例如: 1. 通过`ClassPathXmlApplicationContext`或`FileSystemXmlApplicationContext`加载XML...

    spring-aware接口实现与bean作用域(spring多容器层面)

    在多个项目整合且跨越Spring容器的情况下,获取Bean的实现方式可能更复杂。可以通过Spring的`ConfigurableApplicationContext`接口的`getBeanFactory()`方法获取`BeanFactory`,然后使用`BeanFactory`的`...

    spring-spring容器中bean知识点总结

    Prototype作用域是指每次通过容器的getBean()方法获取Bean时,Spring容器将创建一个新的Bean实例。Prototype作用域通常用于需要动态创建Bean实例的情况。 3. Request作用域 Request作用域是指对于一次HTTP请求,...

    详解Spring简单容器中的Bean基本加载过程

    4. 获取 bean:应用程序可以从容器中获取 bean 并使用它。 在加载 bean 的过程中,Spring 会使用 Resource 对象来表示 XML 文件,然后使用 XmlBeanDefinitionReader 对象来解析 XML 文件,并将 bean 的定义注册到...

    简单Spring框架模拟器--Demo

    首先,我们从“tiny-spring-step-1-container-register-and-get.zip”开始,这是Spring容器的基础。这个步骤讲解了如何注册Bean并从容器中获取,这是Spring框架的核心功能之一。在这里,你会了解到BeanFactory是如何...

    Java-Spring-SpringIoC容器-SpringIoC的学习

    在Java Spring框架中,Spring IoC(Inversion of Control,控制反转)是核心特性之一,它使得应用程序的组件之间的依赖关系不再由代码直接管理,而是交由Spring IoC容器负责。这种设计模式降低了代码间的耦合,提高...

    Java中Spring获取bean方法小结

    - **通过代码注解**:Spring也支持通过注解来获取Bean,如`@Autowired`和`@Resource`,它们能够自动将依赖注入到目标字段或方法中,无需手动从ApplicationContext获取。 3. **静态Singleton Bean Manager** 通常...

    spring-framework-5.0.2.RELEASE-中文注释版-终极完美版.rar

    例如,`org.springframework.beans.factory.BeanFactory`接口定义了容器的基本操作,如获取Bean、初始化Bean等;`org.springframework.context.ApplicationContext`扩展了BeanFactory,提供了更多的企业级服务,如...

    深度解析spring容器管理bean

    "深度解析spring容器管理bean"这一主题,旨在深入理解Spring如何通过反射机制、依赖注入(DI)以及XML或Java配置来实现对Bean的生命周期管理。 首先,Spring容器主要有两种类型:DefaultListableBeanFactory和...

    spring运行过程中动态注册bean

    在Spring框架中,动态注册Bean是一项非常实用的功能,它允许我们在应用运行时向Spring容器添加新的Bean定义。这种能力在很多场景下都是极其有用的,比如根据不同的环境配置加载不同的服务实现,或者在运行时根据某些...

    Spring-Framework-Notes-For-Professionals.pdf

    - Spring容器中的Bean可以有不同的作用域。 - 默认作用域是单例(singleton),确保容器中只有一个共享实例。 - 除了单例作用域,还有原型(prototype)作用域,每次请求Bean都会创建一个新的实例。 7. Spring中...

    spring中的bean

    5. **生命周期管理**:Spring容器负责Bean的生命周期,包括初始化、使用和销毁。我们可以自定义初始化和销毁方法,或者使用`@PostConstruct`和`@PreDestroy`注解。 6. **作用域**:Spring Bean有多种作用域,如单例...

    Spring Bean创建初始化流程.docx

    5. **获取Bean实例**: 在预实例化过程中,`getBean(beanName)`被调用,这是`AbstractBeanFactory`类中的一个方法,用于从Bean工厂中获取指定名称的Bean实例。 6. **实际获取Bean**: 进入`doGetBean()`方法,这...

    在web容器(WebApplicationContext)中获取spring中的bean

    Spring把Bean放在这个容器中,普通的类在需要的时候,直接用getBean()方法取出

    获取Spring容器

    在这个类中,我们定义了一个静态方法`getBean`,通过传入Bean的名称,可以从Spring容器中获取对应的Bean实例。 ##### 3. 通过公共方法获取其他对象 一旦`ApplicationContextUtil`被配置并初始化,就可以通过调用其...

    04-spring5-spring-bean

    依赖注入是Spring的核心特性,它允许Bean之间的依赖关系由Spring容器管理。我们可以使用@Autowired注解自动装配,也可以通过@Qualifier指定特定的Bean。此外,@Value可以注入基本类型或SpEL(Spring Expression ...

    spring在IoC容器中装配Bean详解

    Spring 在 IoC 容器中装配 Bean 详解 Spring 框架中的 IoC 容器是一个核心组件,它提供了 Bean 的装配、管理和依赖注入等功能。在 Spring 框架中,IoC 容器是 Bean 的容器,负责创建、管理和装配 Bean。在本文中,...

    Spring-ioc-jar

    5. **生命周期管理**: Spring容器还提供了对Bean生命周期的管理,包括初始化回调、销毁回调、Bean的后处理器等机制,允许开发者在特定阶段插入自定义逻辑。 6. **AOP代理**: Spring的IOC容器与AOP框架紧密集成,...

Global site tag (gtag.js) - Google Analytics