专业的编程技术博客社区

网站首页 > 博客文章 正文

spring-context注解源码系列(十一)——@Scope

baijin 2024-08-17 11:11:22 博客文章 5 ℃ 0 评论

注解说明

When used as a type-level annotation in conjunction with {@link org.springframework.stereotype.Component @Component}, {@code @Scope} indicates the name of a scope to use for instances of the annotated type.
当和@Component一同使用,可以指定Bean的作用域。

@Scope默认作用域

单例(singleton)

针对一个BeanName,在spring容器中只存在一个Bean,不管怎么获取Bean都是得到相同的Bean。

多态(prototype)

针对一个BeanName,每次调用spring的getBean方法,会重新生成一个Bean。

request(Web专用)

针对一个BeanName,同一个请求生命周期内,多次调用spring的getBean方法得到的Bean是同一个;不同请求调用spring的getBean方法得到的Bean不一样。

session(Web专用)

针对一个BeanName,同一个session的所有请求,多次调用spring的getBean方法得到的Bean是同一个;不同session的请求调用spring的getBean方法得到的Bean不一样。

自定义

spring预留了实现自定义作用域的方式。

第一步,实现org.springframework.beans.factory.config.Scope接口生成自定义实现类,比如spring自带的SimpleThreadScope就是基于线程作用域的实现类,可以支持同一个线程,多次调用spring的getBean方法得到的Bean是同一个,不同线程调用spring的getBean方法得到的Bean不一样。

第二步,调用容器的beanFactory的registerScope方法注册自定义的作用域名称和实现之间的关系。比如,执行代码beanFactory.registerScope(“thread”, new SimpleThreadScope()),就完成了注册工作。之后,通过@Scope(value = “thread”)即可声明某个Bean使用thread级别的作用域。

属性说明

	/**
	 * 同 scopeName
	 */
	@AliasFor("scopeName")
	String value() default "";

	/**
	 * 作用域的名称,通过名称寻找实现类
	 */
	@AliasFor("value")
	String scopeName() default "";

	/**
	 * 作用域的代理模式,
	 * 一个非单例的bean通过@Autowared自动注入到其他bean,
	 * 如果不设置这个属性,会导致其作用域退化为单例
	 * INTERFACES : 使用JDK动态代理
	 * TARGET_CLASS : 使用CGLIB动态代理
	 */
	ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;

使用示例

正常使用

@Service
public class SingleService {

    private ProtoService protoService;

    public ProtoService getProtoService() {
        return protoService;
    }

    @Autowired
    public void setProtoService(ProtoService protoService) {
        this.protoService = protoService;
    }
}

@Service
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ProtoService {

}

public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

    applicationContext.scan("com.example.scope");

    applicationContext.refresh();

    System.out.println("通过自动注入获取:");
    SingleService singleService = applicationContext.getBean(SingleService.class);
    System.out.println(singleService.getProtoService());
    System.out.println(singleService.getProtoService());
    System.out.println("通过getBean方法获取:");
    System.out.println(applicationContext.getBean(ProtoService.class));
    System.out.println(applicationContext.getBean(ProtoService.class));
}

打印结果:

通过自动注入获取:
com.example.scope.ProtoService@25ce9dc4
com.example.scope.ProtoService@74ea2410
通过getBean方法获取:
com.example.scope.ProtoService@17f62e33
com.example.scope.ProtoService@76b1e9b8

如果不设置上述代码中的proxyMode = ScopedProxyMode.TARGET_CLASS

@Service
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ProtoService {

}

打印结果:

通过自动注入获取:
com.example.scope.ProtoService@6f46426d
com.example.scope.ProtoService@6f46426d
通过getBean方法获取:
com.example.scope.ProtoService@73700b80
com.example.scope.ProtoService@49c7b90e

从打印结果中可以看到,自动注入的是单例,多次访问得到的都是同一个Bean,但是不影响通过getBean方法访问得到不同的Bean

相关源码

ConfigurationClassBeanDefinitionReader

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {

// Consider scoping
// 和@Bean一起使用的@Scope由此代码解析
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
	// 如果存在@scope,将scope属性设置给beanDefinition
	beanDef.setScope(attributes.getString("value"));
	proxyMode = attributes.getEnum("proxyMode");
	if (proxyMode == ScopedProxyMode.DEFAULT) {
		proxyMode = ScopedProxyMode.NO;
	}
}

// Replace the original bean definition with the target one, if necessary
// 如果proxyMode 不为空,则生成一个包含代理信息的BeanDefinition取代原来的BeanDefinition,用于@Autowired自动注入
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
	BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
			new BeanDefinitionHolder(beanDef, beanName), this.registry,
			proxyMode == ScopedProxyMode.TARGET_CLASS);
	beanDefToRegister = new ConfigurationClassBeanDefinition(
			(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
  }
	......
}

AnnotationScopeMetadataResolver

/**
* 从beanDefinition里面解析scope元数据
* 和@Component一起使用的@Scope由此代码解析
*/
@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
	ScopeMetadata metadata = new ScopeMetadata();
	if (definition instanceof AnnotatedBeanDefinition) {
		AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
				annDef.getMetadata(), this.scopeAnnotationType);
		if (attributes != null) {
			// 如果存在@scope,将scope属性设置给beanDefinition
			metadata.setScopeName(attributes.getString("value"));
			ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
			if (proxyMode == ScopedProxyMode.DEFAULT) {
				proxyMode = this.defaultProxyMode;
			}
			metadata.setScopedProxyMode(proxyMode);
		}
  }
	return metadata;
}

AbstractBeanFactory

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

		try {
			......

			// Create bean instance.
			// 开始bean的创建工作
			if (mbd.isSingleton()) {
				// 单例将创建工作(createBean)封装在 ObjectFactory里,然后调用getSingleton方法
				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;
					}
				});
				// 根据name和beanName获得合适的对象
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}

			else if (mbd.isPrototype()) {
				// It's a prototype -> create a new instance.
				// 如果这个是多态
				Object prototypeInstance = null;
				try {
					// 调用bean创建前的相关工作
					beforePrototypeCreation(beanName);
					// 多态直接创建对象
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					// 调用bean创建后的相关工作
					afterPrototypeCreation(beanName);
				}
				// 根据name和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 + "'");
				}
				// 根据scopeName找到自定义作用域实现行为
				Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
				}
				try {
					// 将自定义的创建bean的行为封装在ObjectFactory里,然后调用Scope#get方法进行自定义创建行为
					Object scopedInstance = scope.get(beanName, () -> {
					beforePrototypeCreation(beanName);
					try {
						return createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
				});
				// 根据name和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;
		}
	}

	......
	return (T) bean;
}

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表