spring的scope理解

基本介绍

摘自org.springframework:spring-beans:5.0.13.RELEASE的类:org.springframework.beans.factory.config.Scope
原文:

Even if its primary use is for extended scopes in a web environment, this SPI is completely generic: It provides the ability to get and put objects from any underlying storage mechanism, such as an HTTP session or a custom conversation mechanism. The name passed into this class's get and remove methods will identify the target object in the current scope.

Scope implementations are expected to be thread-safe. One Scope instance can be used with multiple bean factories at the same time, if desired (unless it explicitly wants to be aware of the containing BeanFactory), with any number of threads accessing the Scope concurrently from any number of factories.

有道翻译:

即使它的主要用途是用于web环境中的扩展范围,这个SPI也是完全通用的:它提供了从任何底层存储机制(如HTTP会话或自定义会话机制)获取和放置对象的能力。传入类的get和remove方法的名称将标识当前作用域中的目标对象。

作用域实现应该是线程安全的。如果需要,一个Scope实例可以同时与多个bean工厂一起使用(除非它显式地希望知道包含BeanFactory),并且可以让任意数量的线程从任意数量的工厂并发地访问Scope。

解释:

作用域提供的SPI是通用的,具体对象如何存储需要动过底层(也就是具体实现类)去实现(如request、session作用域)。作用域实现是线程安全,可以并发的从BeanFactory中获取对象。

代码调用过程

scope在使用过程中,实际是生成新的单例代理对象替换原对象。在真正对原对象操作时,再获取scope对象。

scope对象生成过程

  • 生成objectFactory代理对象
    • AnnotatedBeanDefinitionReader主要被用于注解解析;ConfigurationClassBeanDefinitionReader扫描Configure类,自动注入import;ClassPathBeanDefinitionScanner根据classpath包扫描Component注解标记的类。
    • org.springframework.context.annotation.AnnotationConfigUtils#applyScopedProxyMode
    • org.springframework.context.annotation.ScopedProxyCreator#createScopedProxy
    • org.springframework.aop.scope.ScopedProxyUtils#createScopedProxy
    • org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition
      在这里插入图片描述
  • 真实的scope对象获取
    • org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
    • org.springframework.beans.factory.config.Scope#get
      在这里插入图片描述

org.springframework.aop.scope.ScopedProxyUtils代理Scope

经过代理后会出现2个BeanDefinition,原orginalBeanName的BeanDefinition 被替换成ScopedProxyFactoryBean的定义,原BeanDefinition的名字变成“scopedTarget.”+orginalBeanName。

public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
			BeanDefinitionRegistry registry, boolean proxyTargetClass) {

		String originalBeanName = definition.getBeanName();
		BeanDefinition targetDefinition = definition.getBeanDefinition();
		// 在beanName前面拼接字符串“scopedTarget.”
		String targetBeanName = getTargetBeanName(originalBeanName);

		// Create a scoped proxy definition for the original bean name,
		// "hiding" the target bean in an internal target definition.
		// 使用ScopedProxyFactoryBean创建工厂类bean
		RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
		// 原被装饰的beandefinition
		proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
		// 原beandefinition
		proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
		proxyDefinition.setSource(definition.getSource());
		proxyDefinition.setRole(targetDefinition.getRole());
		// 设置ScopedProxyFactoryBean的targetBeanName为“scopedTarget.”+orginalBeanName
		proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
		if (proxyTargetClass) {
			targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
			// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
		}
		else {
			proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
		}

		// Copy autowire settings from original bean definition.
		proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
		proxyDefinition.setPrimary(targetDefinition.isPrimary());
		if (targetDefinition instanceof AbstractBeanDefinition) {
			proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
		}

		// The target bean should be ignored in favor of the scoped proxy.
		// 下面2个设置很关键,否则byType注入会有问题
		// 这里设置不被byType转载,targetDefinition代表的是原始bean,不应被自动注入到业务类中
		targetDefinition.setAutowireCandidate(false);
		// 这里在类的bean时,不是主类,不会被自动注入到业务类中
		targetDefinition.setPrimary(false);

		// Register the target bean as separate bean in the factory.
		// 把Definition使用“scopedTarget.”+orginalBeanName作为beanName注入到容器中
		registry.registerBeanDefinition(targetBeanName, targetDefinition);

		// Return the scoped proxy definition as primary bean definition
		// (potentially an inner bean).
		// 返回Definition,一般外层直接使用原beanName注入到容器中
		// 且替换过的bean是单例
		return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
	}
    
    public static String getTargetBeanName(String originalBeanName) {
		return TARGET_NAME_PREFIX + originalBeanName;
	}
	
	public static boolean isScopedTarget(@Nullable String beanName) {
		return (beanName != null && beanName.startsWith(TARGET_NAME_PREFIX));
	}

org.springframework.aop.scope.ScopedProxyFactoryBean代理获取bean

/**
 * 首先该类是FactoryBean,其次该类继承ProxyConfig用于增强class实现代理的配置。
 * 实现AopInfrastructureBean接口用于表示切面基础设置,spring切面不会影响该bean。
 */
public class ScopedProxyFactoryBean extends ProxyConfig
		implements FactoryBean<Object>, BeanFactoryAware, AopInfrastructureBean {

	/** The TargetSource that manages scoping */
	// 该对象的isStatic()方法返回false,这里很重要,代表每次都需要从beanFactory中获取scope实际对象
	private final SimpleBeanTargetSource scopedTargetSource = new SimpleBeanTargetSource();

	/** The name of the target bean */
	@Nullable
	private String targetBeanName;

	/** The cached singleton proxy */
	@Nullable
	private Object proxy;


	/**
	 * Create a new ScopedProxyFactoryBean instance.
	 */
	public ScopedProxyFactoryBean() {
		setProxyTargetClass(true);
	}


	/**
	 * Set the name of the bean that is to be scoped.
	 * ScopedProxyUtils提到,设置为原bean的名称,命名方式为:“scopedTarget.”+orginalBeanName
	 */
	public void setTargetBeanName(String targetBeanName) {
		this.targetBeanName = targetBeanName;
		this.scopedTargetSource.setTargetBeanName(targetBeanName);
	}
	
	/**
	 * BeanFactoryAware时候调用,自动生成代理类proxy。
	 * 该proxy为业务中使用的bean,而实际bean为TargetSource中获取,这里很简单从beanFactory中获取bean。
	*/
	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		if (!(beanFactory instanceof ConfigurableBeanFactory)) {
			throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
		}
		ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;

		this.scopedTargetSource.setBeanFactory(beanFactory);

		ProxyFactory pf = new ProxyFactory();
		pf.copyFrom(this);
		// 这里设置targetSource,jdk/cglib代理增强时,会动态从targetSource中重新获取bean
		pf.setTargetSource(this.scopedTargetSource);

		Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");
		Class<?> beanType = beanFactory.getType(this.targetBeanName);
		if (beanType == null) {
			throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +
					"': Target type could not be determined at the time of proxy creation.");
		}
		if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
			pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
		}

		// Add an introduction that implements only the methods on ScopedObject.
		ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
		pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));

		// Add the AopInfrastructureBean marker to indicate that the scoped proxy
		// itself is not subject to auto-proxying! Only its target bean is.
		pf.addInterface(AopInfrastructureBean.class);
		// 生成代理bean
		this.proxy = pf.getProxy(cbf.getBeanClassLoader());
	}


	@Override
	public Object getObject() {
		if (this.proxy == null) {
			throw new FactoryBeanNotInitializedException();
		}
		return this.proxy;
	}

	@Override
	public Class<?> getObjectType() {
		if (this.proxy != null) {
			return this.proxy.getClass();
		}
		return this.scopedTargetSource.getTargetClass();
	}
	
	/**
	 * 代理生成的bean是单例
	 **/
	@Override
	public boolean isSingleton() {
		return true;
	}

}
public class SimpleBeanTargetSource extends AbstractBeanFactoryBasedTargetSource {

	@Override
	public Object getTarget() throws Exception {
		return getBeanFactory().getBean(getTargetBeanName());
	}

}

容器scope使用

  1. org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope 注册scope名字对应的处理对象

例如request,session作用域在方法org.springframework.web.context.support.WebApplicationContextUtils#registerWebApplicationScopes(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, javax.servlet.ServletContext)中设置

beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
		beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
		if (sc != null) {
			ServletContextScope appScope = new ServletContextScope(sc);
			beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
			// Register as ServletContext attribute, for ContextCleanupListener to detect it.
			sc.setAttribute(ServletContextScope.class.getName(), appScope);
		}

在这里插入图片描述

  1. org.springframework.beans.factory.support.AbstractBeanFactory
    在代理单例ProxyBean获取scope bean时,调用scope方法获取,例如requestScope每次request请求从beanFactory中生成,session在会话周期内有效。
  • RequestScope
public class RequestScope extends AbstractRequestAttributesScope {

	@Override
	protected int getScope() {
		return RequestAttributes.SCOPE_REQUEST;
	}

	/**
	 * There is no conversation id concept for a request, so this method
	 * returns {@code null}.
	 */
	@Override
	@Nullable
	public String getConversationId() {
		return null;
	}
}

public abstract class AbstractRequestAttributesScope implements Scope {

	@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
	    // 当前线程内有效的request请求
		RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
		// 根据beanName从request中获取bean,name这里就是“scopedTarget.”+orginalBeanName
		Object scopedObject = attributes.getAttribute(name, getScope());
		if (scopedObject == null) {
		    // 重新生成bean,objectFactory参考下图
			scopedObject = objectFactory.getObject();
			// 给上下文设置值
			attributes.setAttribute(name, scopedObject, getScope());
			// Retrieve object again, registering it for implicit session attribute updates.
			// As a bonus, we also allow for potential decoration at the getAttribute level.
			Object retrievedObject = attributes.getAttribute(name, getScope());
			if (retrievedObject != null) {
				// Only proceed with retrieved object if still present (the expected case).
				// If it disappeared concurrently, we return our locally created instance.
				scopedObject = retrievedObject;
			}
		}
		return scopedObject;
	}
   .... 省略部分内容......
}

在这里插入图片描述

  • SessionScope
public class SessionScope extends AbstractRequestAttributesScope {

	@Override
	protected int getScope() {
		return RequestAttributes.SCOPE_SESSION;
	}

	@Override
	public String getConversationId() {
		return RequestContextHolder.currentRequestAttributes().getSessionId();
	}

	@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
	    // 存在并发问题,这里加锁,mutx就是session中一个属性值
		Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex();
		synchronized (mutex) {
			return super.get(name, objectFactory);
		}
	}

	@Override
	@Nullable
	public Object remove(String name) {
		Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex();
		synchronized (mutex) {
			return super.remove(name);
		}
	}

}

RefreshScope动态刷新配置过程

  • refresh缓存实际需要的对象
public class RefreshScope extends GenericScope{
   ...省略..
}

GenericScope中get方法

@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
	    // 这里的cache经过特殊处理,put就是putIfAbsent,所以已经初始化的,直接返回BeanLifecycleWrapper
		BeanLifecycleWrapper value = this.cache.put(name,
				new BeanLifecycleWrapper(name, objectFactory));
		locks.putIfAbsent(name, new ReentrantReadWriteLock());
		try {
			return value.getBean();
		}
		catch (RuntimeException e) {
			this.errors.put(name, e);
			throw e;
		}
	}
private static class BeanLifecycleWrapper {

		private Object bean;

		private Runnable callback;

		private final String name;

		private final ObjectFactory<?> objectFactory;

		public BeanLifecycleWrapper(String name, ObjectFactory<?> objectFactory) {
			this.name = name;
			this.objectFactory = objectFactory;
		}
        ... 省略 ...
		/**
	     * 如果bean不存在从beanFactory中获取
	     */
		public Object getBean() {
			if (this.bean == null) {
				synchronized (this.name) {
					if (this.bean == null) {
						this.bean = this.objectFactory.getObject();
					}
				}
			}
			return this.bean;
		}
         ... 省略 ...
	}

org.springframework.cloud.endpoint.event.RefreshEventListener 缓存刷新

  1. 使用spring的消息总线监听事件RefreshEvent;
  2. 收到消息后,调用org.springframework.cloud.context.refresh.ContextRefresher#refresh
  3. 方法中调用org.springframework.cloud.context.refresh.ContextRefresher#addConfigFilesToEnvironment重新初始化环境变量,然后替换现在的环境变量;
  4. 最后调用org.springframework.cloud.context.scope.refresh.RefreshScope#refreshAll清空org.springframework.cloud.context.scope.GenericScope#cache缓存
  5. 因为情况了cache,那么在使用对象属性或方法时,会重新生成bean,那么就完成了配置刷新。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值