环境:spring5.3.3

通过@Scope注解可以指定Bean的作用域,默认情况都是单例的(ConfigurableBeanFactory.SCOPE_SINGLETON=singleton)
在创建bean实例时就是根据当前定义BeanDefinition中的Scope来做不同的创建,源码如下:
- protected
 T doGetBean( - String name, @Nullable Class
 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()) {
 - // 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 {
 - 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;
 - }
 
从上面源码看到分别判断是了 是否是 Singleton及Proptotype,如果都不是则会从Map
 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);
 - }
 - });
 
自定义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设置为多例,以便查看效果。交替执行上面的接口,只要删除了就会创建新的实例。
如果一个Bean 设置了@Scope(value =
ConfigurableBeanFactory.SCOPE_PROTOTYPE) 当这个Bean需要在一个单例Bean中被注入时,需要如下配置才可
- @Component
 - @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
 - public class ApplyScopeBean {
 - }
 
这样才能正确地注入Bean,否则因为本身使用者是单例的,属性只会被初始化一次。也可以在每次使用前调用BeanFactory#getBean()。
                新闻标题:SpringBean的作用域scope你知道多少?如何自定义作用域?
                
                文章分享:http://www.csdahua.cn/qtweb/news13/372363.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网