所谓作用域是指从BeanFactory获取所需的Bean始终是同一个对象的范围。
从这句话可以想到的作用域实现方式的几个点:
1、从BeanFactory获取
2、始终是同一个对象
3、范围
拆解说明:
1、获取和使用是两码事,作用域只管获取
1.1 显式获取
BeanFactory对象和ApplicationContext对象的getBean方法,每次返回的bean都是按照作用域的定义返回对应的bean。
1.2 依赖注入
@Autowired 和@Resource 依赖注入时,beanFactory确实按照作用域返回对应的bean,但是很明显,在使用时即使我们对Service指定了作用域为prototype,但是每次从controller调用的service依然是同一个
然而对controller指定作用域为prototype时,我们又可以发现每次调用的又是不同的bean,所以很明显RequestMappingHandlerMapping中相应的映射关系并不是简单的通过访问地址映射到具体的controller bean
,然后映射到具体的方法,而是通过地址映射到bean name,然后通过beanName从beanFactory获取对象,然后再来invoke对应的方法
2、缓存
始终是同一个对象,那么beanFactory中必然要缓存对象,否则无法在多次获取时返回同一个对象
3、范围控制由缓存介质控制
singleton bean存储在单例特有的缓存中,每次获取,有就直接返回,没有就创建缓存后返回,单例的三级缓存设计是跟随beanFactory存在的,一个beanFactory一个单例缓存
prototype 不缓存,每次都创建新的
request 按意思应该存储在HttpRequest中,有就直接返回,没有就创建缓存后返回
session 按意思应该存储在HttpSession中,有就直接返回,没有就创建缓存后返回,Spring的实现中 Request和Seesion范围由同一套体系实现,只是会标注不同的类型
题外话:如何在使用时调用不同的prototype bean
1、显式获取bean,需取得BeanFactory对象或者ApplicationContext对象
2、定义@Lookup方法,用来获取bean,由Spring进行method replace处理
3、依赖注入bean的接口继承ObjectFactory并满足相应条件
主要是DefaultListableBeanFactory和AutowireUtil中的两段代码
/**
* Find bean instances that match the required type.
* Called during autowiring for the specified bean.
* @param beanName the name of the bean that is about to be wired
* @param requiredType the actual type of bean to look for
* (may be an array component type or collection element type)
* @param descriptor the descriptor of the dependency to resolve
* @return a Map of candidate names and candidate instances that match
* the required type (never {@code null})
* @throws BeansException in case of errors
* @see #autowireByType
* @see #autowireConstructor
*/
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
AutowireUtil.java中的代码
/**
* Resolve the given autowiring value against the given required type,
* e.g. an {@link ObjectFactory} value to its actual object result.
* @param autowiringValue the value to resolve
* @param requiredType the type to assign the result to
* @return the resolved value
*/
public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) {
if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
ObjectFactory<?> factory = (ObjectFactory<?>) autowiringValue;
if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(),
new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
}
else {
return factory.getObject();
}
}
return autowiringValue;
}
实质也是代理,且必须是依赖注入。实际应用的例子是 controller层依赖注入HttpServletRequest对象,每次都是拿到当前正确的请求
4、创建代理进行调用时对象获取操作
4.1进行AOP切面编程,在最后实际进行被代理对象方法调用时,从BeanFactory重新获取bean
处理起来比较繁琐,因为代理对象和被代理对象都从BeanFactory,因此至少会有两个BeanDefinition,相关处理方式可以使用
BeanDefinitionRegistryPostProcessor + MergedBeanDefinitionPostProcessor
接口来进行处理
BeanDefinitionRegistryPostProcessor 提供BeanDefinitionRegistry,MergedBeanDefinitionPostProcessor在处理默认的BeanDefinition时,往BeanDefinitionRegistry注册一个新的BeanDefinition,两个BeanDefinition信息除beanName外相同,两个beanName必须可以通过算法互算,且一个BeanDefinition会被AutoProxyCreator判定为需要创建代理,而另一个不会,所以默认使用的AutoProxyCreator是达不到我们的要求的,只有Spring提供的BeanNameAutoProxyCreator可以达到我们的要求,我们还得再创建一个MethodInterceptor,然后在配置BeanNameAutoProxyCreator的时候将需要创建代理的beanName和MethodInterceptor配置给BeanNameAutoProxyCreator即可。
4.2 使用Spring提供的TargetSourceCreator进行处理
所有代理对象跟被代理对象之间并不是直接关联的,是通过TargetSource进行关联,创建代理对象的时间点大致有三个
1、AbstractAutoProxyCreator.postProcessBeforeInstantiation(实现了InstantiationAwareBeanPostProcessor接口)
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
2、BeanPostProcessor.postProcessAfterInitialization 和 3、SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference均指向以下方法
/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
这里我们可以使用的是AbstractAutoProxyCreator.postProcessBeforeInstantiation这个点,其中getCustomeTargetSource方法
@Nullable
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
// We can't create fancy target sources for directly registered singletons.
if (this.customTargetSourceCreators != null &&
this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
TargetSource ts = tsc.getTargetSource(beanClass, beanName);
if (ts != null) {
// Found a matching TargetSource.
if (logger.isTraceEnabled()) {
logger.trace("TargetSourceCreator [" + tsc +
"] found custom TargetSource for bean with name '" + beanName + "'");
}
return ts;
}
}
}
// No custom TargetSource found.
return null;
}
需要自定义TargetSourceCreator,并配置给AbstractAutoProxyCreator实现类的bean。
由TargetSourceCreator去生成TargetSource,TargetSource的类型很多,具体的功能其实跟作用域很像,可以多了解了解
看了以后可以可以再去看看 spring cloud的refreshscope是否可以换一种方法实现