- 浏览: 92327 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
dylan0514sina.cn:
youjianbo_han_87 写道dylan0514sin ...
方法缓存 -
youjianbo_han_87:
dylan0514sina.cn 写道youjianbo_ha ...
方法缓存 -
dylan0514sina.cn:
youjianbo_han_87 写道缓存方法有意义吗,方法+ ...
方法缓存 -
youjianbo_han_87:
缓存方法有意义吗,方法+调用从缓存中取内容的方法 换成 方法+ ...
方法缓存 -
dylan0514sina.cn:
Shen.Yiyang 写道剔除策略只有方法执行的时候指定ke ...
方法缓存
内置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配置如下
servlet2.3,web配置如下
RequestContextFilter初始化RequestAtrributes
Scope只有在getBean中有效
Spring不仅负责Bean的实例化,而且还管理依赖关系,根据依赖仅仅会在第一次请求时创建和装配好bean。因此:如果在bean定义中只是指定了scope,则除了singleton,其他的scope定义的bean实例的含义是无效的,必须钩入向Spring容器请求,也就是调用getBean方法。换句话说,我们必须改变依赖关系的注入。可以想到使用代理作为被注入的对象,当调用代理方法时,会实时的getBean 请求容器。实现这种机制的是 <aop:scoped-proxy/>
我们插入了<aop:scoped-proxy/>元素在被注入的userPreferences定义中,为什么scope等于request,session, global session,或自定义的scope 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动态代理,则作如下配置。
ScopedProxyFactoryBean实现<aop:scoped-proxy/>
spring-beans DTD 或者 XSD的解析者DefaultBeanDefinitionDocumentReader
解析根元素及代理BeanDefinitionParserDelegate解析其他的子元素
根元素有beans,alias,import
子元素的解析者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 ,同时丧失候选资格
ScopedProxyFactoryBean实现
1.setProxyTargetClass设置代理方式,true为CGliB代理,false为JDK代理
2.scopedTargetSource = new SimpleBeanTargetSource()代理方法每调用一次,就会向Spring容器发送getBean请求
3.添加AopInfrastructureBean接口,生成代理对象;说明代理对象类型并不适合自动代理机制
4.添加DelegatingIntroductionInterceptor introduction借口,并暴露DefaultScopedObject对象,生成代理;所以可以编程式把代理对象转化ScopedObject对象而从scope中进行获取和移除bean
自定义scope
编写了Scope实现之后,要将他注册到Spring容器中,下面是核心注册方法
void registerScope(String scopeName, Scope scope);
这个方法在ConfigurableBeanFactory中声明,大多数ApplicationContext都实现了它。
方法中的第一个参数是scope的名字,用于配置bean指定scope时使用,第二个参数是具体实现。
编程式的注册
xml配置
声明式注册
xml配置
实现
AbstractApplicationContext入口 refresh
显然所有的BeanFactoryPostProcessor会在此处被调用,包括注册Scope的CustomScopeConfigurer,因为它是一个BeanFactoryPostProcessor实例。
那不得不提的是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方法
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); }
发表评论
-
支持占位符的文本解析PropertySourcesPropertyResolver
2013-07-14 18:27 2939PropertyResolver 是 Environment的 ... -
支持不同运行环境下的属性处理--Environment 特性
2013-07-14 01:47 4087介绍 Environment架构是spring 3.1版本引 ... -
支持开发、测试、生产环境下bean配置切换的profiles特性
2013-07-11 12:31 5541介绍 Bean definition profiles ... -
方法缓存
2013-07-10 18:20 4191介绍 spring3.1之后提供了方法的缓存支持,透明的将 ... -
基于xml schema的扩展标签
2013-07-09 13:34 1542xml schema是spring 2.0版本之后引入的,在之 ... -
BeanDefinition数据流
2013-07-08 19:41 1805BeanDefinition是Spring配置文件中bean定 ... -
bean的创建周期回调
2013-06-29 16:24 1526初始化回调 实现org.springframework ... -
MethodInjection 动态方法替换原理
2013-06-21 14:45 1397singleton实例依赖于prototy ... -
AbstractBeanFactory获取bean周期
2013-05-11 22:58 897AbstractBeanFactory是IOC容器实现的骨 ...
相关推荐
类方法 类方法其执行原理和用户函数是相同的,也是翻译成opcodes顺次调用。类的实现,zend用一个数据...就函数这一块来说,method实现原理和 function完全相同,理论上其性能也差不多,后面我们将做详细的性能对比。 性
面向对象的 JavaScript 编程及其 Scope 处理,论述了Javascript面向对象的实现原理和技术细节,详细描述了JavaScript的对象模型。
在ng的生态中scope处于一个核心的地位,ng对外宣称的双向绑定的底层其实就是scope实现的,本章主要对scope的watch机制、继承性以及事件的实现作下分析。 监听 1. $watch 1.1 使用 // $watch: function(watchExp, ...
当$scope的一个属性被改变时,界面可能会更新。那么为什么angular里面,修改$scope上的一个属性,可以引起界面的变化呢?这是angular的数据响应机制决定的。在angular里面就是脏检查机制。而脏检查,和双向绑定离不...
AngularJS中scope之间的继承关系使用JavaScript的原型继承方式实现。本文结合AngularJS Scope的实现以及相关资料谈谈原型继承机制。下面来看看详细的介绍: 基本原理 在JavaScript中,每创建一个构造函数...
其中包括A/D模块,D/A模块,Detector模块,PIN衰减器模块,电阻衰减网络模块,alc模块,Scope模块和Detector2模块的实现。用正弦信号及调幅波作为输入信号,由检波器的特性和PIN衰减管的特性分别分析A/D与D/A的字长效应。...
Vue.js 是当前前端开发中较为流行的一款渐进式Javascript框架,因此,对于Vue.js的掌握程度也是目前前端工作面试中的一个关键点。而在Vue.js的面试题中...除此之外,面试官通常也会从Vue.js的实现原理、性能优化和Webp
主要实现原理:点击后,设置一个$interval,每一秒更改一次剩余时间,并依赖Angular数据绑定实时显示在页面中。设置一个$timeout,60秒后将按钮初始化到可用状态。 实现代码: (1)js代码,设置成一个directive以便...
2.5.2. 使用tf.variable_scope()修改变量的命名空间 20 2.6. 高级API 20 2.6.1. 其他基础API 21 2.6.2. 高级API 21 2.7. 案例:实现线性回归 22 2.7.1. 线性回归原理复习 23 2.7.2. 案例:实现线
MVC的工作原理,如下图1所示: <br/> Struts 是MVC的一种实现,它将 Servlet和 JSP 标记(属于 J2EE 规范)用作实现的一部分。Struts继承了MVC的各项特性,并根据J2EE的特点,做了相应的变化与扩展。Struts...
1.2.2. 工作原理........................................................................................................................................................... 26 1.3. Seam 中的可点击列表:...
参数是可变长的,原理就像string.Format(str,a0,a1..)一样。 可以(cmdtext,p0,p1,p2..)这样调用,也可以直接传递object[]数组。 详细请看C#的params关键字 附加的参数按 @p0,@p1,@p2,...等名称输入到SqlCommand...
web技术 1. angular的数据绑定采 么机制?详述原 angularjs的双向数据绑定,采 脏...function link(scope, iElement, iAttrs, controller) { ... } iElement为编译后的element,已经与作 域 关联起来,所以可以数据绑定
为了能在GPS接收端获取正确导航电文,研究了GPS接收机位同步、帧同步的基本原理和实现方式。提出一种采用FPGA来实现位同步、帧同步系统的设计方案。使用Xilinx开发软件,通过Verilog代码完成对位同步、帧同步的设计...
采用光照控制和时钟电路组合控制,实现了对鸡舍进行自动补光。解决了不同天气、不同季节鸡舍灯光控制复杂的问题。核心部分是控制电路,其优劣决定了补光的合理性与准确性等整体性能。 关键词:鸡舍补光;光照控制;...
在SABER Sketch中,用户能够创建自己的原理图,启动SABER完成各种仿真(偏置点分析、DC分析、AC分析、瞬态分析、温度分析、参数分析、傅立叶分析、蒙特卡诺分析、噪声分析、应力分析、失真分析等),可以直接在原理...
第四点:CGLIB动态代理代码实现 第五点:代码演示事务传播行为 第六点:代码演示事务隔离级别 第七点:Bean的循环依赖 第八点:Spring的八大设计模式 第九点:17种注入方案,其他视频讲10种以内。 第十点:Bean的8种...
其实分页的原理也很简单,我们根据分页选择的页码数和每页数据条数决定当前显示的是数组中的第多少项到多少项,然后再构造分页的参数传入已有的分页指令。 // 初始化分页参数 $scope.pageParams = { size: $...
2、原理 有两部分组成,抽象原型和具体原型。意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 3、原型模式UML图 4、实现 1>使用一个原型管理器; 2>实现克隆操作...
三、在Action获取Scope对象 19 方式一、与Servlet解耦合的非IOC方式 20 方式二、与Servlet解耦合的IOC方式 21 方式三、与Servlet耦合的非IOC方式 21 方式四、与Servlet耦合的IOC方式 22 四、OGNL与ValueStack(VS) 22...