Spring Scope作用域

Spring Scope作用域

1. ConfigurationBeanFactory使用的策略接口,表示要在其中保存bean实例的目标作用域。这允许使用为特定键注册的自定义其他作用域扩展BeanFactory的标准作用域“singleton”和“prototype”。
2. 如org.springfframework.web.context.WebApplicationContext,可以基于此作用域SPI注册特定于其环境的其他标准作用域,例如“request”和“session”。
即使它的主要用途是用于web环境中的扩展作用域,这个SPI也是完全通用的:它提供了从任何底层存储机制(如HTTP会话或自定义会话机制)获取和放置对象的能力。传入此类的get和remove方法的名称将标识当前作用域中的目标对象。
作用域实现应该是线程安全的。一个Scope实例可以同时用于多个bean工厂.

public interface Scope {

	/**
	 * 从基础作用域返回具有给定名称的对象,如果在基础存储机制中找不到该对象,则创建该对象。
     * 这是Scope的中心操作,也是唯一绝对需要的操作。
     * name–要检索的对象的名称
     * objectFactory–如果基础存储机制中不存在作用域对象,则用于创建作用域对象的objectFactory
	 */
	Object get(String name, ObjectFactory<?> objectFactory);

	/**
	 * 从基础作用域中删除具有给定名称的对象。
     * 如果未找到对象,则返回null;否则返回删除的Object。
     * 请注意,如果存在实现还应该删除指定对象的已注册销毁回调.
	 */
	@Nullable
	Object remove(String name);

	/**
	 * 注册一个回调,该回调将在销毁作用域中的指定对象时执行(或者在销毁整个作用域时执行,如果作用域不销毁单个对象,而只是整体终止)。
     * 注意:这是一个可选操作。此方法将仅对具有实际销毁配置(DisposableBean、destroy方法、DestructionAwareBeanPostProcessor)的
     * 作用域bean调用。实现应该尽最大努力在适当的时间执行给定的回调。如果底层运行时环境根本不支持这样的回调,则必须忽略该回调,
     * 并记录相应的警告。
     * 请注意,“销毁”是指作为作用域自身生命周期的一部分自动销毁对象,而不是指应用程序已明确删除的单个作用域对象。
     * 如果通过这个facade的remove方法删除了作用域对象,那么也应该删除任何注册的销毁回调
	 */
	void registerDestructionCallback(String name, Runnable callback);

	/**
	 * 解析给定键的上下文对象(如果存在)。例如,键“request”的HttpServlet请求对象。
	 */
	@Nullable
	Object resolveContextualObject(String key);

	/**
	 * 当前基础作用域的会话ID(如果有)。
     * 会话ID的确切含义取决于底层存储机制。在会话范围对象的情况下,会话ID通常等于(或派生自)会话ID;
     * 如果自定义会话位于整个会话中,则当前会话的特定ID将是合适的。
     * 注意:这是一个可选操作。如果底层存储机制没有明显的候选ID,那么在该方法的实现中返回null是完全有效的。
	 */
	@Nullable
	String getConversationId();

}

上面以了解Scope 接口 Api的基本方法含义;

  • 接下来让我们看一下在哪里使用的作用域Scope:

//从作用域标识符字符串映射到相应的作用域。
private final Map<String, Scope> scopes = new LinkedHashMap<>(8);

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		        
				//.....以上代码省略.....
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							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 = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
				// 获取Scope值
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName)) {
						throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
					}
					//根据名称获取Scope对象
					Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
					   //从Scope作用域中获取对象
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						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);
					}
				}
			}
	    //.....以下代码省略.....
		return (T) bean;
	}
  • 上面看到了从scopes中根据名称获取Scope 让我们来看一下是哪里注册进去的:

public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {

   //.......省略
	/**
	 * 注册给定的范围,并由给定的范围实现支持。
	 */
	void registerScope(String scopeName, Scope scope);

	/**
	 * 返回当前注册的所有作用域的名称。这将只返回显式注册的作用域的名称。
	 * 如“singleton”和“prototype”之类的内置作用域不会被公开。
	 */
	String[] getRegisteredScopeNames();

	/**
	 * 返回给定作用域名称的作用域实现(如果有)。
     * 这将只返回显式注册的作用域。诸如“singleton”和“prototype”之类的内置作用域不会被公开
	 */
	@Nullable
	Scope getRegisteredScope(String scopeName);

	/**
	 * 销毁当前目标作用域中指定的作用域bean(如果有的话)。
     * 销毁过程中出现的任何异常都应该被捕获并记录,而不是传播到此方法的调用方
	 */
	void destroyScopedBean(String beanName);

   //.......省略
}

	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.isDebugEnabled()) {
				logger.debug("Replacing scope '" + scopeName + "' from [" + previous + "] to [" + scope + "]");
			}
		}
		else {
			if (logger.isTraceEnabled()) {
				logger.trace("Registering scope '" + scopeName + "' with implementation [" + scope + "]");
			}
		}
	}
  • ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS
  • 主要看ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass)
BeanDefinitionHolder applyScopedProxyMode(
			ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

		ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
		if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
			return definition;
		}
		boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
		//
		return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
		}
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
			BeanDefinitionRegistry registry, boolean proxyTargetClass) {
        //获取原始bean 名称
		String originalBeanName = definition.getBeanName();
		//目标bean定义
		BeanDefinition targetDefinition = definition.getBeanDefinition();
		//targetBeanName  = scopedTarget.+ originalBeanName
		String targetBeanName = getTargetBeanName(originalBeanName);
		
		//构建类型为ScopedProxyFactoryBean的bean 定义
		//为原始bean名称创建一个作用域代理定义,将目标bean“隐藏”在内部目标定义中
		RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
		//注册这个bean定义修饰的目标定义
		proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
		//设置发起BeanDefinition
		proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
		proxyDefinition.setSource(definition.getSource());
		proxyDefinition.setRole(targetDefinition.getRole());
        //添加参数targetBeanName的值
		proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
		//判断是否基于目标类代理 -CGLIB
		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);
		}

		// 应该忽略目标bean,而使用作用域代理
		//将目标bean 不作为自动装配的候选者
		targetDefinition.setAutowireCandidate(false);
		//优先级设置为false
		targetDefinition.setPrimary(false);

		// 将目标bean注册。
		registry.registerBeanDefinition(targetBeanName, targetDefinition);

		//将作用域代理定义返回为主bean定义
		return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
	}
  • 下面让我们来看一些实际中的应用:

  • RequestScope

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_REQUEST)
public @interface RequestScope {

	/**
	 * Alias for {@link Scope#proxyMode}.
	 * <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.
	 */
	@AliasFor(annotation = Scope.class)
	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}
  • ApplicationScope
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_APPLICATION)
public @interface ApplicationScope {

	/**
	 * Alias for {@link Scope#proxyMode}.
	 * <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.
	 */
	@AliasFor(annotation = Scope.class)
	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}

  • SessionScope
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_SESSION)
public @interface SessionScope {

	/**
	 * Alias for {@link Scope#proxyMode}.
	 * <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.
	 */
	@AliasFor(annotation = Scope.class)
	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}

接下来看一下注册位置
AbstractApplicationContext.refresh()

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				//允许在上下文子类中对bean工厂进行后处理
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);
				//...省略以下代码
}
@Override
	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		if (this.servletContext != null) {
			beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));
			beanFactory.ignoreDependencyInterface(ServletContextAware.class);
		}
		//注册Web环境下的Scope作用域
		WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
		WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext);
	}
//注册Web作用域Scope
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
			@Nullable ServletContext sc) {
        //注册RequestScope
		beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
		//注册SessionScope
		beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
		if (sc != null) {
			ServletContextScope appScope = new ServletContextScope(sc);
			//注册SevletContextScope--@ApplicationScope 
			beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
			// Register as ServletContext attribute, for ContextCleanupListener to detect it.
			sc.setAttribute(ServletContextScope.class.getName(), appScope);
		}
  
       //注册特殊的依赖项类型,而在工厂中没有定义为bean;比如ApplicationContext | BeanFactory | ApplicationEventPublisher等等;
		beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
		beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
		beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
		beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
		if (jsfPresent) {
			FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
		}
	}
private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {

		@Override
		public ServletRequest getObject() {
			return currentRequestAttributes().getRequest();
		}

		@Override
		public String toString() {
			return "Current HttpServletRequest";
		}
	}

其他Web作用域同理;

  • 以下内容为文章重点:

下面来看我们再Spring Cloud 中经常使用使用的RefreshScope:

ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {

	/**
	 * 目标类--创建一个基于类的代理(使用CGLIB)
	 */
	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}

从以下代码中可以看出RefreshScope 继承 GenericScope,GenericScope 默认中name = “generic”;在RefreshScope 构造函数中super.setName(“refresh”);设置名称为refresh;

public class RefreshScope extends GenericScope implements ApplicationContextAware,
		ApplicationListener<ContextRefreshedEvent>, Ordered {

	private ApplicationContext context;

	private BeanDefinitionRegistry registry;

	private boolean eager = true;

	private int order = Ordered.LOWEST_PRECEDENCE - 100;

	/**
	 * Creates a scope instance and gives it the default name: "refresh".
	 */
	public RefreshScope() {
		super.setName("refresh");
	}

	@Override
	public int getOrder() {
		return this.order;
	}

	public void setOrder(int order) {
		this.order = order;
	}

	/**
	 * Flag to determine whether all beans in refresh scope should be instantiated eagerly
	 * on startup. Default true.
	 * @param eager The flag to set.
	 */
	public void setEager(boolean eager) {
		this.eager = eager;
	}

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
			throws BeansException {
		this.registry = registry;
		super.postProcessBeanDefinitionRegistry(registry);
	}

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		start(event);
	}

	public void start(ContextRefreshedEvent event) {
		if (event.getApplicationContext() == this.context && this.eager
				&& this.registry != null) {
			eagerlyInitialize();
		}
	}
    //为了早期创建对象
	private void eagerlyInitialize() {
		for (String name : this.context.getBeanDefinitionNames()) {
			BeanDefinition definition = this.registry.getBeanDefinition(name);
			if (this.getName().equals(definition.getScope())
					&& !definition.isLazyInit()) {
				Object bean = this.context.getBean(name);
				if (bean != null) {
					bean.getClass();
				}
			}
		}
	}

	@ManagedOperation(description = "Dispose of the current instance of bean name "
			+ "provided and force a refresh on next method execution.")
	public boolean refresh(String name) {
		if (!name.startsWith(SCOPED_TARGET_PREFIX)) {
			// User wants to refresh the bean with this name but that isn't the one in the
			// cache...
			name = SCOPED_TARGET_PREFIX + name;
		}
		// Ensure lifecycle is finished if bean was disposable
		if (super.destroy(name)) {
			this.context.publishEvent(new RefreshScopeRefreshedEvent(name));
			return true;
		}
		return false;
	}

	@ManagedOperation(description = "Dispose of the current instance of all beans "
			+ "in this scope and force a refresh on next method execution.")
	//刷新
	public void refreshAll() {
	//销毁所有@RefreshScope的Bean
		super.destroy();
		this.context.publishEvent(new RefreshScopeRefreshedEvent());
	}

	@Override
	public void setApplicationContext(ApplicationContext context) throws BeansException {
		this.context = context;
	}

}

从GenericScope 代码中可以看出此类实现了BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor;了解spring 的都知道此两个拓展接口的调用时机,此处针对两接口不做详解;
postProcessBeanDefinitionRegistry.postProcessBeanDefinitionRegistry在此类中主要用来处理BeanDefinition的Scope为当前类的name值的BeanDefinition,相等则设置BeanClass为LockedScopedProxyFactoryBean 构造函数参数为当前Scope;
BeanFactoryPostProcessor.postProcessBeanFactory 在此类在主要用来注册Scope 和生成BeanFactory id;

public class GenericScope implements Scope, BeanFactoryPostProcessor,
		BeanDefinitionRegistryPostProcessor, DisposableBean {

	/**
	 * Prefix for the scoped target.
	 */
	public static final String SCOPED_TARGET_PREFIX = "scopedTarget.";

	private static final Log logger = LogFactory.getLog(GenericScope.class);

	private BeanLifecycleWrapperCache cache = new BeanLifecycleWrapperCache(
			new StandardScopeCache());

	private String name = "generic";

	private ConfigurableListableBeanFactory beanFactory;

	private StandardEvaluationContext evaluationContext;

	private String id;

	private Map<String, Exception> errors = new ConcurrentHashMap<>();

	private ConcurrentMap<String, ReadWriteLock> locks = new ConcurrentHashMap<>();

	static RuntimeException wrapIfNecessary(Throwable throwable) {
		if (throwable instanceof RuntimeException) {
			return (RuntimeException) throwable;
		}
		if (throwable instanceof Error) {
			throw (Error) throwable;
		}
		return new IllegalStateException(throwable);
	}

	public void setId(String id) {
		this.id = id;
	}

	public void setScopeCache(ScopeCache cache) {
		this.cache = new BeanLifecycleWrapperCache(cache);
	}

	public Map<String, Exception> getErrors() {
		return this.errors;
	}

	@Override
	public void destroy() {
		List<Throwable> errors = new ArrayList<Throwable>();
		Collection<BeanLifecycleWrapper> wrappers = this.cache.clear();
		for (BeanLifecycleWrapper wrapper : wrappers) {
			try {
				Lock lock = this.locks.get(wrapper.getName()).writeLock();
				lock.lock();
				try {
					wrapper.destroy();
				}
				finally {
					lock.unlock();
				}
			}
			catch (RuntimeException e) {
				errors.add(e);
			}
		}
		if (!errors.isEmpty()) {
			throw wrapIfNecessary(errors.get(0));
		}
		this.errors.clear();
	}
	
	protected boolean destroy(String name) {
		BeanLifecycleWrapper wrapper = this.cache.remove(name);
		if (wrapper != null) {
		// 根据名称获取写锁
			Lock lock = this.locks.get(wrapper.getName()).writeLock();
			lock.lock();
			try {
			//执行销毁---将之前的bean引用设置为null,下次再get的时候因为为null 所以又需要重新创建Bean执行createBean流程
				wrapper.destroy();
			}
			finally {
				lock.unlock();
			}
			this.errors.remove(name);
			return true;
		}
		return false;
	}

   /**
    * 1. 因为默认缓存使用的是StandardScopeCache,只需要去缓存中判断是否存在。如果存在即复用BeanLifecycleWrapper,
    * 2. 创建读写锁 主要是 在销毁(destroy)的时候使用写锁   在获取的时候使用读锁;
    * 3. 调用BeanLifecycleWrapper的getBean,如果bean 已创建 就直接返回, 没有则调用ObjectFactory.getObject()回调创建Bean.
   **/
	@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
	//1.创建Bean生命周期包装对象
	//2.根据名称 缓存---这里是重点
	//private BeanLifecycleWrapperCache cache = new BeanLifecycleWrapperCache(new StandardScopeCache())
	//cache 为BeanLifecycleWrapperCache 参数为StandardScopeCache 还有其他实现比如ThreadLocalScopeCache 都是实现ScopeCache接口
	//ScopeCache:专门用于GenericScope的专用缓存接口,用于管理缓存的bean实例。实现通常分为两类:一类是“全局”存储值(即每个键一个实例)
	//另一类是基于上下文(例如通过线程本地)为每个键存储多个实例。所有实现都应该是线程安全的。
	//StandardScopeCache.put方法 内部是ConcurrentHashMap -->this.cache.putIfAbsent(name, value);
		BeanLifecycleWrapper value = this.cache.put(name,
				new BeanLifecycleWrapper(name, objectFactory));
				//设置读写锁-以名称维度设置
				//主要再销毁的时候要获取写锁,在getObject 是使用读锁
		this.locks.putIfAbsent(name, new ReentrantReadWriteLock());
		try {
		//获取或者创建bean-----LockedScopedProxyFactoryBean
			return value.getBean();
		}
		catch (RuntimeException e) {
			this.errors.put(name, e);
			throw e;
		}
	}

	@Override
	public String getConversationId() {
		return this.name;
	}

	@Override
	public void registerDestructionCallback(String name, Runnable callback) {
		BeanLifecycleWrapper value = this.cache.get(name);
		if (value == null) {
			return;
		}
		value.setDestroyCallback(callback);
	}

	@Override
	public Object remove(String name) {
		BeanLifecycleWrapper value = this.cache.remove(name);
		if (value == null) {
			return null;
		}
		// Someone might have added another object with the same key, but we
		// keep the method contract by removing the
		// value we found anyway
		return value.getBean();
	}

	@Override
	public Object resolveContextualObject(String key) {
		Expression expression = parseExpression(key);
		return expression.getValue(this.evaluationContext, this.beanFactory);
	}

	private Expression parseExpression(String input) {
		if (StringUtils.hasText(input)) {
			ExpressionParser parser = new SpelExpressionParser();
			try {
				return parser.parseExpression(input);
			}
			catch (ParseException e) {
				throw new IllegalArgumentException("Cannot parse expression: " + input,
						e);
			}

		}
		else {
			return null;
		}
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
			throws BeansException {
		this.beanFactory = beanFactory;
		//注册Scope
		beanFactory.registerScope(this.name, this);
		setSerializationId(beanFactory);
	}

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
			throws BeansException {
			//获取所有BeanNames
		for (String name : registry.getBeanDefinitionNames()) {
		
			BeanDefinition definition = registry.getBeanDefinition(name);
			if (definition instanceof RootBeanDefinition) {
				RootBeanDefinition root = (RootBeanDefinition) definition;
				if (root.getDecoratedDefinition() != null && root.hasBeanClass()
				        //首先要判断类型是否为ScopedProxyFactoryBean,前面流程已经将bean定义处理设置主(beanName)ScopedProxyFactoryBean
				        //的类型,包装原始目标类型其bean名称为scopedTarget.+ beanName;
						&& root.getBeanClass() == ScopedProxyFactoryBean.class) {
						//如果BeanDefinition中的作用域等于getName这里我们就以它的一个子类RefreshScope为例;
						//如果当前bean定义的作用域为refresh,则设置BeanClas为代理工厂bean
					if (getName().equals(root.getDecoratedDefinition().getBeanDefinition()
							.getScope())) {
							//设置需要创建的bean类型
						root.setBeanClass(LockedScopedProxyFactoryBean.class);
						//添加构造函数参数
						root.getConstructorArgumentValues().addGenericArgumentValue(this);
						// surprising that a scoped proxy bean definition is not already
						// marked as synthetic?
						root.setSynthetic(true);
					}
				}
			}
		}
	}

	protected String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	protected ReadWriteLock getLock(String beanName) {
		return this.locks.get(beanName);
	}

    //bean生命周期包装器缓存
	private static class BeanLifecycleWrapperCache {
            
        //作用域缓存    
		private final ScopeCache cache;

		BeanLifecycleWrapperCache(ScopeCache cache) {
			this.cache = cache;
		}

		public BeanLifecycleWrapper get(String name) {
			return (BeanLifecycleWrapper) this.cache.get(name);
		}

		public BeanLifecycleWrapper put(String name, BeanLifecycleWrapper value) {
			return (BeanLifecycleWrapper) this.cache.put(name, value);
		}

	}

	private static class BeanLifecycleWrapper {

        //bean名称
		private final String name;

		private final ObjectFactory<?> objectFactory;
        //提示:这里当前版本没有 volatile修饰  后面的版本以处理;    
		private Object bean;

		private Runnable callback;

		BeanLifecycleWrapper(String name, ObjectFactory<?> objectFactory) {
			this.name = name;
			this.objectFactory = objectFactory;
		}

		public String getName() {
			return this.name;
		}

		public void setDestroyCallback(Runnable callback) {
			this.callback = callback;
		}

		public Object getBean() {
			if (this.bean == null) {
				synchronized (this.name) {
					if (this.bean == null) {
						this.bean = this.objectFactory.getObject();
					}
				}
			}
			return this.bean;
		}
        
		public void destroy() {
			if (this.callback == null) {
				return;
			}
			synchronized (this.name) {
				Runnable callback = this.callback;
				if (callback != null) {
					callback.run();
				}
				this.callback = null;
				this.bean = null;
			}
		}
         //.......忽略一下代码
	}

       /**
       * 
       */
	@SuppressWarnings("serial")
	public static class LockedScopedProxyFactoryBean<S extends GenericScope>
			extends ScopedProxyFactoryBean implements MethodInterceptor {
        //作用域---
		private final S scope;
        //目标Bean名称
		private String targetBeanName;
        
      
		public LockedScopedProxyFactoryBean(S scope) {
			this.scope = scope;
		}

		@Override
		public void setBeanFactory(BeanFactory beanFactory) {
			super.setBeanFactory(beanFactory);
			Object proxy = getObject();
		    //this.proxy = pf.getProxy(cbf.getBeanClassLoader())
			if (proxy instanceof Advised) {
				Advised advised = (Advised) proxy;
				//LockedScopedProxyFactoryBean实现了MethodInterceptor 也是一个方法拦截器 (AOP)
				//将当前LockedScopedProxyFactoryBean对象,添加到目标代理对象拦截链中通知拦截;
				advised.addAdvice(0, this);
			}
		}

		@Override
		public void setTargetBeanName(String targetBeanName) {
			super.setTargetBeanName(targetBeanName);
			this.targetBeanName = targetBeanName;
		}

		@Override
		public Object invoke(MethodInvocation invocation) throws Throwable {
			Method method = invocation.getMethod();
			if (AopUtils.isEqualsMethod(method) || AopUtils.isToStringMethod(method)
					|| AopUtils.isHashCodeMethod(method)
					|| isScopedObjectGetTargetObject(method)) {
				return invocation.proceed();
			}
			Object proxy = getObject();
			//并发---获取读写锁
			ReadWriteLock readWriteLock = this.scope.getLock(this.targetBeanName);
			if (readWriteLock == null) {
				if (logger.isDebugEnabled()) {
					logger.debug("For bean with name [" + this.targetBeanName
							+ "] there is no read write lock. Will create a new one to avoid NPE");
				}
				//创建读写锁
				readWriteLock = new ReentrantReadWriteLock();
			}
			//获取读锁 ---这里使用读锁是为了都共享 , 与写锁互斥。如果正在执行销毁方法, 此处阻塞,等待写锁释放。
			Lock lock = readWriteLock.readLock();
			lock.lock();
			try {
				if (proxy instanceof Advised) {
					Advised advised = (Advised) proxy;
					ReflectionUtils.makeAccessible(method);
					return ReflectionUtils.invokeMethod(method,
					       //获取目标对象。--此处如果已经销毁获取的是最新的bean
							advised.getTargetSource().getTarget(),
							invocation.getArguments());
				}
				return invocation.proceed();
			}
			// see gh-349. Throw the original exception rather than the
			// UndeclaredThrowableException
			catch (UndeclaredThrowableException e) {
				throw e.getUndeclaredThrowable();
			}
			finally {
				lock.unlock();
			}
		}

		private boolean isScopedObjectGetTargetObject(Method method) {
			return method.getDeclaringClass().equals(ScopedObject.class)
					&& method.getName().equals("getTargetObject")
					&& method.getParameterTypes().length == 0;
		}

	}

}

put方法 内部是this.cache.putIfAbsent(name, value)

public class StandardScopeCache implements ScopeCache {

	private final ConcurrentMap<String, Object> cache = new ConcurrentHashMap<String, Object>();

	public Object remove(String name) {
		return this.cache.remove(name);
	}

	public Collection<Object> clear() {
		Collection<Object> values = new ArrayList<Object>(this.cache.values());
		this.cache.clear();
		return values;
	}

	public Object get(String name) {
		return this.cache.get(name);
	}

	public Object put(String name, Object value) {
		Object result = this.cache.putIfAbsent(name, value);
		if (result != null) {
			return result;
		}
		return value;
	}

}

适用于作用域对象的代理工厂bean。
使用这个工厂bean创建的代理是线程安全的单体,可以注入到共享对象中,并具有透明的作用域行为。

public class ScopedProxyFactoryBean extends ProxyConfig
		implements FactoryBean<Object>, BeanFactoryAware, AopInfrastructureBean {

	/** The TargetSource that manages scoping. */
	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.
	 */
	public void setTargetBeanName(String targetBeanName) {
		this.targetBeanName = targetBeanName;
		this.scopedTargetSource.setTargetBeanName(targetBeanName);
	}

	@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);
		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);
        //创建代理对象     
		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();
	}

	@Override
	public boolean isSingleton() {
		return true;
	}

}

接下来看一下触发刷新逻辑:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RefreshScope.class)
@ConditionalOnProperty(name = RefreshAutoConfiguration.REFRESH_SCOPE_ENABLED,
		matchIfMissing = true)
@AutoConfigureBefore(HibernateJpaAutoConfiguration.class)
public class RefreshAutoConfiguration {
 //....省略以上代码

	@Bean
	@ConditionalOnMissingBean(RefreshScope.class)
	public static RefreshScope refreshScope() {
		return new RefreshScope();
	}

	@Bean
	@ConditionalOnMissingBean
	public ContextRefresher contextRefresher(ConfigurableApplicationContext context,
			RefreshScope scope) {
		return new ContextRefresher(context, scope);
	}

	@Bean
	public RefreshEventListener refreshEventListener(ContextRefresher contextRefresher) {
		return new RefreshEventListener(contextRefresher);
	}
    //....省略
}
public class ContextRefresher {

      //....省略以上代码
      
     //刷新方法
	public synchronized Set<String> refresh() {
	//刷新上下文环境,获取改变的keys,发布EnvironmentChangeEvent事件 
	//@ConfigurationProperties   有ConfigurationPropertiesRebinder接收到事件调用 rebind(name)  销毁bean重新初始化;
   //LoggingRebinder.setLogLevels 获取配置设置日志级别
		Set<String> keys = refreshEnvironment();
		//调用RefreshScope 刷新所有标注@ResreshScope的bean,发布RefreshScopeRefreshedEvent事件
		this.scope.refreshAll();
		return keys;
	}
	//....省略以下代码
  • ConfigurationPropertiesRebinder
public class ConfigurationPropertiesRebinder
		implements ApplicationContextAware, ApplicationListener<EnvironmentChangeEvent> {


@Override
	public void onApplicationEvent(EnvironmentChangeEvent event) {
		if (this.applicationContext.equals(event.getSource())
				// Backwards compatible
				|| event.getKeys().equals(event.getSource())) {
			rebind();
		}
	}
	
	@ManagedOperation
	public void rebind() {
		this.errors.clear();
		for (String name : this.beans.getBeanNames()) {
			rebind(name);
		}
	}

	@ManagedOperation
	public boolean rebind(String name) {
		if (!this.beans.getBeanNames().contains(name)) {
			return false;
		}
		if (this.applicationContext != null) {
			try {
				Object bean = this.applicationContext.getBean(name);
				if (AopUtils.isAopProxy(bean)) {
					bean = ProxyUtils.getTargetObject(bean);
				}
				if (bean != null) {
					// TODO: determine a more general approach to fix this.
					// see https://github.com/spring-cloud/spring-cloud-commons/issues/571
					if (getNeverRefreshable().contains(bean.getClass().getName())) {
						return false; // ignore
					}
					this.applicationContext.getAutowireCapableBeanFactory()
							.destroyBean(bean);
					this.applicationContext.getAutowireCapableBeanFactory()
							.initializeBean(bean, name);
					return true;
				}
			}
			catch (RuntimeException e) {
				this.errors.put(name, e);
				throw e;
			}
			catch (Exception e) {
				this.errors.put(name, e);
				throw new IllegalStateException("Cannot rebind to " + name, e);
			}
		}
		return false;
	}
}
  • LoggingRebinder
public class LoggingRebinder
		implements ApplicationListener<EnvironmentChangeEvent>, EnvironmentAware {

	@Override
	public void onApplicationEvent(EnvironmentChangeEvent event) {
		if (this.environment == null) {
			return;
		}
		LoggingSystem system = LoggingSystem.get(LoggingSystem.class.getClassLoader());
		setLogLevels(system, this.environment);
	}

	protected void setLogLevels(LoggingSystem system, Environment environment) {
		Map<String, String> levels = Binder.get(environment)
				.bind("logging.level", STRING_STRING_MAP)
				.orElseGet(Collections::emptyMap);
		for (Entry<String, String> entry : levels.entrySet()) {
			setLogLevel(system, environment, entry.getKey(), entry.getValue().toString());
		}
	}

	private void setLogLevel(LoggingSystem system, Environment environment, String name,
			String level) {
		try {
			if (name.equalsIgnoreCase("root")) {
				name = null;
			}
			level = environment.resolvePlaceholders(level);
			system.setLogLevel(name, resolveLogLevel(level));
		}
		catch (RuntimeException ex) {
			this.logger.error("Cannot set level: " + level + " for '" + name + "'");
		}
	}

	private LogLevel resolveLogLevel(String level) {
		String trimmedLevel = level.trim();
		if ("false".equalsIgnoreCase(trimmedLevel)) {
			return LogLevel.OFF;
		}
		return LogLevel.valueOf(trimmedLevel.toUpperCase(Locale.ENGLISH));
	}

}

使用集成spring-boot-actuator endpoint 调用请求触发这里不做讲解;

  • 以Nacos为例
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.nacos.config.enabled", matchIfMissing = true)
public class NacosConfigAutoConfiguration {

	@Bean
	public NacosConfigProperties nacosConfigProperties(ApplicationContext context) {
		if (context.getParent() != null
				&& BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						context.getParent(), NacosConfigProperties.class).length > 0) {
			return BeanFactoryUtils.beanOfTypeIncludingAncestors(context.getParent(),
					NacosConfigProperties.class);
		}
		return new NacosConfigProperties();
	}

	@Bean
	public NacosRefreshProperties nacosRefreshProperties() {
		return new NacosRefreshProperties();
	}

	@Bean
	public NacosRefreshHistory nacosRefreshHistory() {
		return new NacosRefreshHistory();
	}

	@Bean
	public NacosConfigManager nacosConfigManager(
			NacosConfigProperties nacosConfigProperties) {
		return new NacosConfigManager(nacosConfigProperties);
	}

	@Bean
	public NacosContextRefresher nacosContextRefresher(
			NacosConfigManager nacosConfigManager,
			NacosRefreshHistory nacosRefreshHistory) {
		return new NacosContextRefresher(nacosConfigManager, nacosRefreshHistory);
	}
}
public class NacosContextRefresher
		implements ApplicationListener<ApplicationReadyEvent>, ApplicationContextAware {

//....省略以上代码

//ApplicationReadyEvent  已就绪,listeners.running(context) 事件发布得尽可能晚,以表明应用程序已准备好为请求提供服务;
	@Override
	public void onApplicationEvent(ApplicationReadyEvent event) {
		// many Spring context
		if (this.ready.compareAndSet(false, true)) {
			this.registerNacosListenersForApplications();
		}
	}

    //注册监听 
    //当有事件发生会回调innerReceive方法,发布RefreshEvent事件
	private void registerNacosListener(final String groupKey, final String dataKey) {
		String key = NacosPropertySourceRepository.getMapKey(dataKey, groupKey);
		Listener listener = listenerMap.computeIfAbsent(key,
				lst -> new AbstractSharedListener() {
					@Override
					public void innerReceive(String dataId, String group,
							String configInfo) {
						refreshCountIncrement();
						nacosRefreshHistory.addRefreshRecord(dataId, group, configInfo);
						// todo feature: support single refresh for listening
						//发布刷新事件
						applicationContext.publishEvent(
								new RefreshEvent(this, null, "Refresh Nacos config"));
						if (log.isDebugEnabled()) {
							log.debug(String.format(
									"Refresh Nacos config group=%s,dataId=%s,configInfo=%s",
									group, dataId, configInfo));
						}
					}
				});
		try {
		//  向nacos 注册事件监听,当有事件发生会回调innerReceive(String dataId, String group,String configInfo)
			configService.addListener(dataKey, groupKey, listener);
		}
		catch (NacosException e) {
			log.warn(String.format(
					"register fail for nacos listener ,dataId=[%s],group=[%s]", dataKey,
					groupKey), e);
		}
	}
	//....省略以下代码
}

在收到RefreshEvent时调用ContextRefresher.refresh。只有在收到ApplicationReadyEvent后才响应RefreshEvent;

public class RefreshEventListener implements SmartApplicationListener {

	private static Log log = LogFactory.getLog(RefreshEventListener.class);

	private ContextRefresher refresh;

	private AtomicBoolean ready = new AtomicBoolean(false);

	public RefreshEventListener(ContextRefresher refresh) {
		this.refresh = refresh;
	}

	@Override
	public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
		return ApplicationReadyEvent.class.isAssignableFrom(eventType)
				|| RefreshEvent.class.isAssignableFrom(eventType);
	}

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationReadyEvent) {
			handle((ApplicationReadyEvent) event);
		}
		else if (event instanceof RefreshEvent) {
			handle((RefreshEvent) event);
		}
	}

	public void handle(ApplicationReadyEvent event) {
		this.ready.compareAndSet(false, true);
	}
 //刷新
	public void handle(RefreshEvent event) {
		if (this.ready.get()) { // don't handle events before app is ready
			log.debug("Event received " + event.getEventDesc());
			//调用ContextRefresher.refresh()执行刷新逻辑
			Set<String> keys = this.refresh.refresh();
			log.info("Refresh keys changed: " + keys);
		}
	}

}

提示:想看Nacos 配置拉取,注册监听,事件接收等源码逻辑请移步至spring cloud nacos 配置拉取原理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Framework中的bean作用域是指在应用程序中实例化的bean的生命周期。Spring Framework支持多种作用域,包括singleton、prototype、request、session和global session等。其中,prototype作用域是最灵活的作用域之一,因为它允许每次请求时创建一个新的实例。 使用prototype作用域的bean在每次被注入或请求时都会创建一个新的实例。这意味着,每当你注入一个prototype作用域的bean时,你都会得到一个新的实例。prototype作用域非常适合那些需要创建多个实例的bean,例如线程池或数据库连接。 下面是使用prototype作用域的bean的示例: ```java @Component @Scope("prototype") public class MyPrototypeBean { // ... } ``` 在上面的示例中,`@Scope("prototype")`注解指定了这个bean的作用域是prototype。 在使用prototype作用域的bean时,需要注意以下几点: 1. Spring不会管理prototype作用域的bean的生命周期,因此在使用完bean后,需要手动销毁它们。 2. 在使用prototype作用域的bean时,不能依赖于Spring来自动注入它们的依赖项。必须手动注入它们的依赖项。 3. 如果使用prototype作用域的bean依赖于其他作用域的bean,那么这些bean的作用域应该是singleton或者是其他长期作用域。否则,你可能会遇到循环依赖的问题。 4. 在使用prototype作用域的bean时,如果有其他bean依赖于它们,那么这些bean必须使用依赖注入的方式来获取bean实例,而不是使用@Autowire注解来注入它们。 总之,prototype作用域是一种非常灵活的作用域,可以用于创建多个实例的bean。但是,需要注意一些细节,以确保正确地使用它们。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值