Spring源码导读之Scope解析

Spring源码导读

 

目录

Scope注册

Scope创建

RequestScope

RequestContextHolder

SessionScope

ScopeProxy


 

Spring为我们提供的scope有: singleton,prototype,request,session,globalSession

1、singleton
2、prototype:每次调用新建一个Bean的实例
3、request: 给每一个http request新建一个Bean实例
4、session: 给每一个http session新建一个Bean实例。
5、globalSession:这个只在portal应用中有用,给每一个global http session新建一个Bean实例。

其中:
1、2是Spring自带的。3、4、5是Spring为我们自定义的。我也可以自定义Scope。

Scope注册

public class CustomScopeConfigurer implements BeanFactoryPostProcessor, BeanClassLoaderAware, Ordered:

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	if (this.scopes != null) {
		this.scopes.forEach((scopeKey, value) -> {
			if (value instanceof Scope) {
				beanFactory.registerScope(scopeKey, (Scope) value);
			}
			else if (value instanceof Class) {
				Class<?> scopeClass = (Class<?>) value;
				Assert.isAssignable(Scope.class, scopeClass, "Invalid scope class");
				beanFactory.registerScope(scopeKey, (Scope) BeanUtils.instantiateClass(scopeClass));
			}
			else if (value instanceof String) {
				Class<?> scopeClass = ClassUtils.resolveClassName((String) value, this.beanClassLoader);
				Assert.isAssignable(Scope.class, scopeClass, "Invalid scope class");
				beanFactory.registerScope(scopeKey, (Scope) BeanUtils.instantiateClass(scopeClass));
			}
			else {
				throw new IllegalArgumentException("Mapped value [" + value + "] for scope key [" +
						scopeKey + "] is not an instance of required type [" + Scope.class.getName() +
						"] or a corresponding Class or String value indicating a Scope implementation");
			}
		});
	}
}

AbstractBeanFactory#registerScope

public void registerScope(String scopeName, Scope scope) {
	Assert.notNull(scopeName, "Scope identifier must not be null");
	Assert.notNull(scope, "Scope must not be null");
	if (SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)) {
		throw new IllegalArgumentException("Cannot replace existing scopes 'singleton' and 'prototype'");
	}
	Scope previous = this.scopes.put(scopeName, scope);
	if (previous != null && previous != scope) {
		if (logger.isInfoEnabled()) {
			logger.info("Replacing scope '" + scopeName + "' from [" + previous + "] to [" + scope + "]");
		}
	}
	else {
		if (logger.isDebugEnabled()) {
			logger.debug("Registering scope '" + scopeName + "' with implementation [" + scope + "]");
		}
	}
}

 

Scope创建

看下AbstractBeanFactory#doGetBean中scope创建是如何发起的

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
 
	// 转化一下传入的beanName.如果是别名转真名,如果是&开头,去掉&。&代表取factoryBean
	final String beanName = transformedBeanName(name);
	Object bean;
 
	// 1、这里为了解决Singleton循环依赖,如果允许早期暴露,会在这里取到其早期暴露,后面会介绍
	// 2、如果是工厂模式,在获取bean的时候,在这里会先获取到factoryBean
	Object sharedInstance = getSingleton(beanName);
	// 如果 sharedInstance 不为空,说明当前singleton是依赖者在注入属性时创建的。则打印相关日志
	if (sharedInstance != null && args == 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 + "'");
			}
		}
		// 这里会将name和beanName同时传进来, 因为一开始我们的name可能是带&符号的,代表这里需要获取factoryBean而不是bean
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
 
	else {
		// Fail if we're already creating this bean instance:
		// We're assumably within a circular reference.
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
 
		// 判断是否有父容器,如果有父容器,优先用父容器调用其getBean
		BeanFactory parentBeanFactory = get
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值