@Scope注解源码浅析

使用Spring框架定义一个bean时,可以使用@Scope注解定义bean的作用域,最常见的就是singleton和prototype两种类型,同时,在WEB工程中还衍生出了@RequestScope@SessionScope@ApplicationScope三种范围的作用域注解

使用java注解定义一个bean

@Configuration
public class Config {
    @Bean
    @Scope    // 默认单例模式
    public User user() {
        return new User();
    }
}

当Spring容器启动时,会根据配置的扫描路径扫描所有的类信息,搜集所有标注@Bean注解的方法构造BeanDefinition,每个BeanDefinition都保存了相应待创建的bean模板信息(类似java通过Class信息反射创建一个对象,Spring通过BeanDefinition创建一个bean)

BeanDefinition接口抽象实现类AbstractBeanDefinition有如下相关方法:

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
            implements BeanDefinition, Cloneable {

    @Nullable
    private String scope = SCOPE_DEFAULT;
    
    @Override
    public void setScope(@Nullable String scope) { this.scope = scope; }

    @Override
    @Nullable
    public String getScope() { return this.scope; }

    @Override
    public boolean isSingleton() {
        return SCOPE_SINGLETON.equals(this.scope) || SCOPE_DEFAULT.equals(this.scope);
    }

    @Override
    public boolean isPrototype() {
        return SCOPE_PROTOTYPE.equals(this.scope);
    }
}

通过上述源码可以得知BeanDefinition记录了一个bean的Scope信息,一般来说,原型和单例梁两种作用域是互斥的,同时,如果使用了自定义的Scope则既不是singleton也不是prototype

那么,作用域Scope在创建bean的过程中起到什么作用?

AbstractBeanFactory中,有如下获取bean的方法,若从作用域中获取不到bean,则通过AbstractBeanFactory#createBean创建目标bean

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport 
            implements ConfigurableBeanFactory {

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

        // ...
        try {
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            // 若当前bean依赖其他bean,先创建被依赖的bean
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        // 省略异常...
                    }
                    registerDependentBean(dep, beanName);
                    try {
                        getBean(dep);
                    } catch (NoSuchBeanDefinitionException ex) {
                        // 省略异常...
                    }
                }
            }

            // 从以下代码可以获知,单例、原型、以及自定义的scope
            // 在创建一个bean的时候选择不同的分支,逻辑互斥
            // 可以简单的理解scope表示一个bean的“圈子”
            // 获取一个“圈子”内的bean前先根据圈子的定义在“圈子”内查询,若查询不到则由容器创建

            // Create bean instance.
            if (mbd.isSingleton()) {
                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();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    // 省略异常...
                }
                try {
                    // 从自定义的scope中获取bean
                    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) {
                    // 省略异常...
                }
            }
        } catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }
    // ...
}

从上面源码可以得出结论,创建bean的时候,会根据定义信息BeanDefinition判断scope类型,如果是自定义的scope,先尝试从scope获取bean对象,若获取不到则由容器创建

可以从Spring提供的一个自定义Scope范例一探究竟,如下:

// 注册Scope方式:
// 1. org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope
// 2. 定位org.springframework.beans.factory.config.CustomScopeConfigurer类,将Scope注入属性中
public class SimpleThreadScope implements Scope {

    private static final Log logger = LogFactory.getLog(SimpleThreadScope.class);
    // 线程安全的scope
    private final ThreadLocal<Map<String, Object>> threadScope =
            new NamedThreadLocal<Map<String, Object>>("SimpleThreadScope") {
                @Override
                protected Map<String, Object> initialValue() {
                    return new HashMap<>();
                }
            };


    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> scope = this.threadScope.get();
        Object scopedObject = scope.get(name);
        // 如果当前的Scope获取不到bean
        if (scopedObject == null) {
            // 根据AbstractBeanFactory中的源码,交给createBean方法创建bean对象
            scopedObject = objectFactory.getObject();
            scope.put(name, scopedObject);
        }
        return scopedObject;
    }

    @Override
    @Nullable
    public Object remove(String name) {
        Map<String, Object> scope = this.threadScope.get();
        return scope.remove(name);
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        logger.warn("SimpleThreadScope does not support destruction callbacks. " +
                "Consider using RequestScope in a web environment.");
    }

    @Override
    @Nullable
    public Object resolveContextualObject(String key) {
        return null;
    }

    @Override
    public String getConversationId() {
        return Thread.currentThread().getName();
    }

}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容