Spring Bean的作用域scope你知道多少?如何自定义作用域?

域名2025-11-05 07:07:123

环境:spring5.3.3

1 Scope作用

通过@Scope注解可以指定Bean的作道多作用域,默认情况都是用域义作用域单例的(ConfigurableBeanFactory.SCOPE_SINGLETON=singleton)

在创建bean实例时就是根据当前定义BeanDefinition中的Scope来做不同的创建,源码如下:

protected <T> T doGetBean(             String name,知自定 @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)             throws BeansException {   String beanName = transformedBeanName(name);   Object bean;   // Eagerly check singleton cache for manually registered singletons.   Object sharedInstance = getSingleton(beanName);   if (sharedInstance != null && args == null) {     // other code   } else {     // other code     try {       RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);       checkMergedBeanDefinition(mbd, beanName, args);       // Guarantee initialization of beans that the current bean depends on.       // other code       // Create bean instance.       // 根据BeanDefinition中定义的Scope创建实例       // 判断如果是单例       if (mbd.isSingleton()) {         // 如果是单例Bean会将Bean保存到缓存中singletonObjects           sharedInstance = getSingleton(beanName, () -> {           try {             return createBean(beanName, mbd, args);           } catch (BeansException ex) {             destroySingleton(beanName);             throw ex;           }         });         bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);       }       // 判断如果是原型(多例)       else if (mbd.isPrototype()) {         // Its 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 {         String scopeName = mbd.getScope();         if (!StringUtils.hasLength(scopeName)) {           throw new IllegalStateException("No scope name defined for bean 麓" + beanName + "");         }         Scope scope = this.scopes.get(scopeName);         // 当集合中也不存在时抛出异常           if (scope == null) {           throw new IllegalStateException("No Scope registered for scope name " + scopeName + "");         }         try {           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);         }       }     } catch (BeansException ex) {       cleanupAfterBeanCreationFailure(beanName);       throw ex;     }   }   // other code   return (T) bean; } 

从上面源码看到分别判断是了 是否是b2b供应网 Singleton及Proptotype,如果都不是少何则会从Mapscopes中获取。如果当前你配置的作道多@Scope不是singleton及prototype那么从scopes集合中取(这个集合是通过AbstractBeanFactory#registerScope方法进行注册的,一般我们可以通过

BeanDefinitionRegistryPostProcessor进行注册),如果集合中也不存在那么就会抛出异常。知自定如果存在就会执行Scope#get方法 Scope scope = this.scopes.get(scopeName); Object scopedInstance = scope.get(beanName,少何 () -> {   beforePrototypeCreation(beanName);   try {     return createBean(beanName, mbd, args);   } finally {     afterPrototypeCreation(beanName);   } }); 

2 自定义Scope

自定义Scope

public class CustomScope implements Scope {   private Object target ;   @Override   public Object get(String name, ObjectFactory<?> objectFactory) {     return target != null ? target : objectFactory.getObject() ;   }   // 如果调用了这个方法,那么下次在注入有@Scope("custom")的作道多bean时 将会重写调用objectFactory.getObject()方法。   @Override   public Object remove(String name) {     target = null ;     return "success" ;   }   @Override   public void registerDestructionCallback(String name,用域义作用域 Runnable callback) {   }   @Override   public Object resolveContextualObject(String key) {     return null;   }   @Override   public String getConversationId() {     return null;   } } 

注册Scope

@Component public class CustomScopeRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {   @Override   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {     beanFactory.registerScope("custom", new CustomScope()) ;   }   @Override   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {   } } 

使用Scope

@Component @Scope("custom") public class ApplyScopeBean { } 

示例

@RestController @RequestMapping("/refresh") @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class RefreshController implements ApplicationContextAware{   @Resource   private ApplyScopeBean scopeBean ;   @Resource   private CustomScope customScope ;   @GetMapping("/custom")   public String custom() {     return scopeBean.getCustom() ;   }   @GetMapping("/remove")    public Object remove() {     return customScope.remove("applyScopeBean") ;   }   } 

这里将Controller设置为多例,WordPress模板以便查看效果。知自定交替执行上面的少何接口,只要删除了就会创建新的作道多实例。

3 多例注入

如果一个Bean 设置了@Scope(value =

ConfigurableBeanFactory.SCOPE_PROTOTYPE) 当这个Bean需要在一个单例Bean中被注入时,用域义作用域需要如下配置才可

@Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,知自定 proxyMode = ScopedProxyMode.TARGET_CLASS) public class ApplyScopeBean { } 

这样才能正确地注入Bean,否则因为本身使用者是单例的,属性只会被初始化一次。也可以在每次使用前调用BeanFactory#getBean()。

本文地址:http://www.bzve.cn/html/502d65198846.html
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

全站热门

电脑远程连接显示错误的解决方法(教你如何应对常见的远程连接显示错误)

SpringBoot外化配置源码解析:综合实战演示参数及配置

这些高阶的函数技术,你掌握了么

FastThreadLocal 是什么鬼?吊打 ThreadLocal 的存在!!

Flyme5.1.6.0a(打造独特个性化的手机主题,尽享视觉盛宴)

C++多元组Tuple使用方法?你熟悉吗?快来看看吧

33岁大叔自学编程,简历被拒的他是如何8个月就在Twitter上找到工作的?

除了 time.sleep,你还有一个暂停代码的方法

友情链接

滇ICP备2023006006号-39