Singleton 每个IOC容器对一个bean定义创建唯一实例
Prototype 对一个bean定义,每次请求容器都会创建新的实例
Request 对一个bean定义,一次web请求会创建一个实例
Session 对一个bean定义,一次web会话创建一个实例
Global Session 对一个bean定义,一次porlet会话创建一个实例
后三种只在Web环境下使用,AbstractApplicationContext refresh入口
AbstractRefreshableWebApplicationContext会注册这三种BEAN
WebApplicationContextUtils具体代码
当使用AbstractRefreshableWebApplicationContext并不会注册这三种Bean.
这三种Scope父类方法调用RequestContextHolder
在RequestContextHolder实现中,RequestAttribute为空,则抛出错误
RequestAttribute的实现ServletRequestAttributes中,封装了HTTP对象和Scope的Bean获取,设置和销毁方法
所以在WEB环境下,如果使用SPRING MVC,则在 DispatcherServlet, or DispatcherPortlet已经初始化RequestAttribute对象,否则必须做相关配置以初始化。
使用servlet2.4+容器,web.xml配置如下
<web-app> ... <listener> <listener-class> org.springframework.web.context.request.RequestContextListener </listener-class> </listener> ... </web-app>
servlet2.3,web配置如下
<web-app> .. <filter> <filter-name>requestContextFilter</filter-name> <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class> </filter> <filter-mapping> <filter-name>requestContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ... </web-app>
RequestContextFilter初始化RequestAtrributes
Scope只有在getBean中有效
Spring不仅负责Bean的实例化,而且还管理依赖关系,根据依赖仅仅会在第一次请求时创建和装配好bean。因此:如果在bean定义中只是指定了scope,则除了singleton,其他的scope定义的bean实例的含义是无效的,必须钩入向Spring容器请求,也就是调用getBean方法。换句话说,我们必须改变依赖关系的注入。可以想到使用代理作为被注入的对象,当调用代理方法时,会实时的getBean 请求容器。实现这种机制的是 <aop:scoped-proxy/>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- an HTTP Session-scoped bean exposed as a proxy --> <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"> <!-- instructs the container to proxy the surrounding bean --> <aop:scoped-proxy/> </bean> <!-- a singleton-scoped bean injected with a proxy to the above bean --> <bean id="userService" class="com.foo.SimpleUserService"> <!-- a reference to the proxied userPreferences bean --> <property name="userPreferences" ref="userPreferences"/> </bean> </beans>
我们插入了<aop:scoped-proxy/>元素在被注入的userPreferences定义中,为什么scope等于request,session, global session,或自定义的scope bean需要这样?对比下面的定义
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/> <bean id="userManager" class="com.foo.UserManager"> <property name="userPreferences" ref="userPreferences"/> </bean>
上面的例子中userManager被注入了一个scope等于HTTP session的bean userPreferences.userManager是单例的,它只会在每个容器中初始化一次,他所依赖的Bean也只会初始化一次。就是说userManager只会在一个userPreferences上操作,就是在第一次初始化的userPreferences上。
把生命周期短的注入到生命周期长的bean,可能不是想要的结果,就比如把session scope的bean注入到一个单例Bean中。你需要单例Bean负责Http session bean的特定于Http Session生命周期。因此容器创建了userPreferences的代理对象,把它注入到userManager,但userManager并不知道userPreferences是个代理对象。当userManager调用userPreferences实例的方法时,其实调用的是代理对象的方法。代理对象会请求真正的Bean并调用之上的方法。
同时可以选择创建代理的方式 JDK接口或CGLIB类方式,MethodInjection之中有讨论。默认情况下会使用CGLIB方式,如果想使用JDK动态代理,则作如下配置。
<!-- DefaultUserPreferences implements the UserPreferences interface --> <bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session"> <aop:scoped-proxy proxy-target-class="false"/> </bean> <bean id="userManager" class="com.foo.UserManager"> <property name="userPreferences" ref="userPreferences"/> </bean>
ScopedProxyFactoryBean实现<aop:scoped-proxy/>
spring-beans DTD 或者 XSD的解析者DefaultBeanDefinitionDocumentReader
解析根元素及代理BeanDefinitionParserDelegate解析其他的子元素
根元素有beans,alias,import
/** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document */ protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
子元素的解析者BeanDefinitionParserDelegate,当一个bean定义解析好之后,要进一步进行可能的自定义属性或内置元素的解析,进入decorateIfRequired方法。
NamespaceHandler命名空间处理器,比如<aop:.../>将使用AOPNamespaceHandler.
DefaultNamespaceHandlerResolver将会在所有的JAR包中查找META-INF/spring.handlers并读入,在JAR spring-aop下有META-INF/spring.handlers
内容为
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
在JAR spring-bean下有META-INF/spring.handlers,内容为
http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
载入资源代码
AopNamespaceHandler实现中可以看到config用于事务处理的;aspectj-autoproxy用于aspectj自动代理的;scoped-proxy用于Scope bean处理的;所以<aop:scoped-proxy/>将由ScopedProxyBeanDefinitionDecorator处理
ScopedProxyBeanDefinitionDecorator最终代理ScopedProxyUtils.createScopedProxy
1.创建一个ScopedProxyFactoryBean对应的代理RootBeanDefinition
2.占有了Scope bean的标识符,可能的候选者(当以类型装配查找时)
3.Scope bean的名字为标识符变成 "scopedTarget." + ID ,同时丧失候选资格
String originalBeanName = definition.getBeanName(); BeanDefinition targetDefinition = definition.getBeanDefinition(); // Create a scoped proxy definition for the original bean name, // "hiding" the target bean in an internal target definition. RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class); proxyDefinition.setOriginatingBeanDefinition(definition.getBeanDefinition()); proxyDefinition.setSource(definition.getSource()); proxyDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); String targetBeanName = getTargetBeanName(originalBeanName); proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName); if (proxyTargetClass) { targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE); // ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here. } else { proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE); } // Copy autowire settings from original bean definition. proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate()); proxyDefinition.setPrimary(targetDefinition.isPrimary()); if (targetDefinition instanceof AbstractBeanDefinition) { proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition); } // The target bean should be ignored in favor of the scoped proxy. targetDefinition.setAutowireCandidate(false); targetDefinition.setPrimary(false); // Register the target bean as separate bean in the factory. registry.registerBeanDefinition(targetBeanName, targetDefinition); // Return the scoped proxy definition as primary bean definition // (potentially an inner bean). return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
ScopedProxyFactoryBean实现
1.setProxyTargetClass设置代理方式,true为CGliB代理,false为JDK代理
2.scopedTargetSource = new SimpleBeanTargetSource()代理方法每调用一次,就会向Spring容器发送getBean请求
3.添加AopInfrastructureBean接口,生成代理对象;说明代理对象类型并不适合自动代理机制
4.添加DelegatingIntroductionInterceptor introduction借口,并暴露DefaultScopedObject对象,生成代理;所以可以编程式把代理对象转化ScopedObject对象而从scope中进行获取和移除bean
/* * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.aop.scope; import java.lang.reflect.Modifier; import org.springframework.aop.framework.AopInfrastructureBean; import org.springframework.aop.framework.ProxyConfig; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.DelegatingIntroductionInterceptor; import org.springframework.aop.target.SimpleBeanTargetSource; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBeanNotInitializedException; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.util.ClassUtils; /** * Convenient proxy factory bean for scoped objects. * * <p>Proxies created using this factory bean are thread-safe singletons * and may be injected into shared objects, with transparent scoping behavior. * * <p>Proxies returned by this class implement the {@link ScopedObject} interface. * This presently allows for removing the corresponding object from the scope, * seamlessly creating a new instance in the scope on next access. * * <p>Please note that the proxies created by this factory are * <i>class-based</i> proxies by default. This can be customized * through switching the "proxyTargetClass" property to "false". * * @author Rod Johnson * @author Juergen Hoeller * @since 2.0 * @see #setProxyTargetClass */ public class ScopedProxyFactoryBean extends ProxyConfig implements FactoryBean<Object>, BeanFactoryAware { /** The TargetSource that manages scoping */ private final SimpleBeanTargetSource scopedTargetSource = new SimpleBeanTargetSource(); /** The name of the target bean */ private String targetBeanName; /** The cached singleton proxy */ private Object proxy; /** * Create a new ScopedProxyFactoryBean instance. */ public ScopedProxyFactoryBean() { setProxyTargetClass(true); } /** * Set the name of the bean that is to be scoped. */ public void setTargetBeanName(String targetBeanName) { this.targetBeanName = targetBeanName; this.scopedTargetSource.setTargetBeanName(targetBeanName); } public void setBeanFactory(BeanFactory beanFactory) { if (!(beanFactory instanceof ConfigurableBeanFactory)) { throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory); } ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory; this.scopedTargetSource.setBeanFactory(beanFactory); ProxyFactory pf = new ProxyFactory(); pf.copyFrom(this); pf.setTargetSource(this.scopedTargetSource); Class beanType = beanFactory.getType(this.targetBeanName); if (beanType == null) { throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName + "': Target type could not be determined at the time of proxy creation."); } if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) { pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader())); } // Add an introduction that implements only the methods on ScopedObject. ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName()); pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject)); // Add the AopInfrastructureBean marker to indicate that the scoped proxy // itself is not subject to auto-proxying! Only its target bean is. pf.addInterface(AopInfrastructureBean.class); this.proxy = pf.getProxy(cbf.getBeanClassLoader()); } public Object getObject() { if (this.proxy == null) { throw new FactoryBeanNotInitializedException(); } return this.proxy; } public Class<?> getObjectType() { if (this.proxy != null) { return this.proxy.getClass(); } if (this.scopedTargetSource != null) { return this.scopedTargetSource.getTargetClass(); } return null; } public boolean isSingleton() { return true; } }
自定义scope
编写了Scope实现之后,要将他注册到Spring容器中,下面是核心注册方法
void registerScope(String scopeName, Scope scope);
这个方法在ConfigurableBeanFactory中声明,大多数ApplicationContext都实现了它。
方法中的第一个参数是scope的名字,用于配置bean指定scope时使用,第二个参数是具体实现。
编程式的注册
Scope threadScope = new SimpleThreadScope(); beanFactory.registerScope("thread", threadScope);
xml配置
<bean id="..." class="..." scope="thread">
声明式注册
xml配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="thread"> <bean class="org.springframework.context.support.SimpleThreadScope"/> </entry> </map> </property> </bean> <bean id="bar" class="x.y.Bar" scope="thread"> <property name="name" value="Rick"/> <aop:scoped-proxy/> </bean> <bean id="foo" class="x.y.Foo"> <property name="bar" ref="bar"/> </bean> </beans>
实现
AbstractApplicationContext入口 refresh
显然所有的BeanFactoryPostProcessor会在此处被调用,包括注册Scope的CustomScopeConfigurer,因为它是一个BeanFactoryPostProcessor实例。
@SuppressWarnings("unchecked") public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { if (this.scopes != null) { for (Map.Entry<String, Object> entry : this.scopes.entrySet()) { String scopeKey = entry.getKey(); Object value = entry.getValue(); if (value instanceof Scope) { beanFactory.registerScope(scopeKey, (Scope) value); } else if (value instanceof Class) { Class scopeClass = (Class) value; Assert.isAssignable(Scope.class, scopeClass); beanFactory.registerScope(scopeKey, (Scope) BeanUtils.instantiateClass(scopeClass)); } else if (value instanceof String) { Class scopeClass = ClassUtils.resolveClassName((String) value, this.beanClassLoader); Assert.isAssignable(Scope.class, scopeClass); beanFactory.registerScope(scopeKey, (Scope) BeanUtils.instantiateClass(scopeClass)); } else { throw new IllegalArgumentException("Mapped value [" + value + "] for scope key [" + scopeKey + "] is not an instance of required type [" + Scope.class.getName() + "] or a corresponding Class or String value indicating a Scope implementation"); } } } }
那不得不提的是BeanFactoryPostProcessor的调用情况
1.可以编程式的添加BeanFactoryPostProcessor和对于BeanFactory是BeanDefinitionRegistry类型的可以声明式的注册BeanFactoryPostProcessor实例
2.BeanFactoryPostProcessor的子类BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法被调用
3.调用顺序为:
编程式添加的BeanFactoryPostProcessor子类实例的postProcessBeanDefinitionRegistry方法
声明式注册的BeanFactoryPostProcessor子类实例的postProcessBeanDefinitionRegistry方法
编程式添加的BeanFactoryPostProcessor子类实例的postProcessBeanFactory方法
声明式注册的BeanFactoryPostProcessor子类实例的postProcessBeanFactory方法
编程式添加的BeanFactoryPostProcessor实例的postProcessBeanFactory方法
声明式注册的BeanFactoryPostProcessor实现PriorityOrdered接口实例的postProcessBeanFactory方法
声明式注册的BeanFactoryPostProcessor实现Ordered接口实例的postProcessBeanFactory方法
声明式注册的BeanFactoryPostProcessor没有实现PriorityOrdered或Ordered接口实例的postProcessBeanFactory方法
/** * Instantiate and invoke all registered BeanFactoryPostProcessor beans, * respecting explicit order if given. * <p>Must be called before singleton instantiation. */ protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // Invoke BeanDefinitionRegistryPostProcessors first, if any. Set<String> processedBeans = new HashSet<String>(); if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>(); List<BeanDefinitionRegistryPostProcessor> registryPostProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>(); for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryPostProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryPostProcessor.postProcessBeanDefinitionRegistry(registry); registryPostProcessors.add(registryPostProcessor); } else { regularPostProcessors.add(postProcessor); } } Map<String, BeanDefinitionRegistryPostProcessor> beanMap = beanFactory.getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false); List<BeanDefinitionRegistryPostProcessor> registryPostProcessorBeans = new ArrayList<BeanDefinitionRegistryPostProcessor>(beanMap.values()); OrderComparator.sort(registryPostProcessorBeans); for (BeanDefinitionRegistryPostProcessor postProcessor : registryPostProcessorBeans) { postProcessor.postProcessBeanDefinitionRegistry(registry); } invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(registryPostProcessorBeans, beanFactory); invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); processedBeans.addAll(beanMap.keySet()); } else { // Invoke factory processors registered with the context instance. invokeBeanFactoryPostProcessors(getBeanFactoryPostProcessors(), beanFactory); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // Separate between BeanFactoryPostProcessors that implement PriorityOrdered, // Ordered, and the rest. List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); List<String> orderedPostProcessorNames = new ArrayList<String>(); List<String> nonOrderedPostProcessorNames = new ArrayList<String>(); for (String ppName : postProcessorNames) { if (processedBeans.contains(ppName)) { // skip - already processed in first phase above } else if (isTypeMatch(ppName, PriorityOrdered.class)) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); } else if (isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. OrderComparator.sort(priorityOrderedPostProcessors); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // Next, invoke the BeanFactoryPostProcessors that implement Ordered. List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class)); } OrderComparator.sort(orderedPostProcessors); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // Finally, invoke all other BeanFactoryPostProcessors. List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); for (String postProcessorName : nonOrderedPostProcessorNames) { nonOrderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class)); } invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); }