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的基本方法含义;
//从作用域标识符字符串映射到相应的作用域。
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;
}
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());
}
@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 配置拉取原理