首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

Scope兑现原理

2013-07-04 
Scope实现原理内置Scope分类Singleton 每个IOC容器对一个bean定义创建唯一实例Prototype 对一个bean定义,

Scope实现原理
内置Scope分类
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" 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" ref="userPreferences"/>  </bean></beans>

我们插入了<aop:scoped-proxy/>元素在被注入的userPreferences定义中,为什么scope等于request,session, global session,或自定义的scope bean需要这样?对比下面的定义
<bean id="userPreferences" scope="session"/><bean id="userManager" 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" scope="session">  <aop:scoped-proxy proxy-target-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)) {// recursedoRegisterBeanDefinitions(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="..." 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 scope="thread">      <property name="name" value="Rick"/>      <aop:scoped-proxy/>  </bean>  <bean id="foo" 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);}
 

热点排行