- 浏览: 94895 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
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 2999PropertyResolver 是 Environment的 ... -
支持不同运行环境下的属性处理--Environment 特性
2013-07-14 01:47 4123介绍 Environment架构是spring 3.1版本引 ... -
支持开发、测试、生产环境下bean配置切换的profiles特性
2013-07-11 12:31 5632介绍 Bean definition profiles ... -
方法缓存
2013-07-10 18:20 4244介绍 spring3.1之后提供了方法的缓存支持,透明的将 ... -
基于xml schema的扩展标签
2013-07-09 13:34 1571xml schema是spring 2.0版本之后引入的,在之 ... -
BeanDefinition数据流
2013-07-08 19:41 1862BeanDefinition是Spring配置文件中bean定 ... -
bean的创建周期回调
2013-06-29 16:24 1557初始化回调 实现org.springframework ... -
MethodInjection 动态方法替换原理
2013-06-21 14:45 1434singleton实例依赖于prototy ... -
AbstractBeanFactory获取bean周期
2013-05-11 22:58 935AbstractBeanFactory是IOC容器实现的骨 ...
相关推荐
此外,`@Scope`注解用于设置Bean的作用域,如单例(singleton)或原型(prototype)。 6. **AOP代理**:Spring的面向切面编程(AOP)可以通过注解实现,如`@Aspect`定义一个切面,`@Before`、`@After`、`@Around`等...
其实现原理是动态生成一个类方法,该方法返回一个根据指定条件筛选的结果集。下面是一个简单的示例: ```ruby class Cat scope :tabby, -> { where(coat_coloration: 'tabby') } end ``` 这个示例定义了一个名为...
在本文中,我们将深入探讨style-scope库的核心特性、工作原理以及它如何与PostCSS和PostHTML插件协同工作。 首先,让我们了解一下什么是"style-scope"。style-scope是一种CSS样式管理策略,它允许开发者在组件或...
在ng的生态中scope处于一个核心的地位,ng对外宣称的双向绑定的底层其实就是scope实现的,本章主要对scope的watch机制、继承性以及事件的实现作下分析。 监听 1. $watch 1.1 使用 // $watch: function(watchExp, ...
在编译原理中,符号表(Symbol Table)是至关重要的组成部分,它用于存储源程序中所有标识符(如变量、函数、常量等)的相关信息。这个符号表管理功能通常在词法分析和语法分析阶段被引入,为后续的编译过程提供必要...
深度强化学习-Actor-Critic算法原理和实现 Actor-Critic 算法是深度强化学习中的一种重要算法,结合了 Policy Gradient 和 Q-learning 两种算法的优点。下面我们将详细介绍 Actor-Critic 算法的原理和实现。 ...
通过将Bean声明为`Managed Bean`并设置合适的scope(如`session`),可以实现在不同页面或请求间共享数据。控制器(通常是管理Bean的一个实例)可以直接调用模型Bean的setter方法来设定要显示的数据,然后再由JSF...
STM32F103平衡车程序与Visual Scope的整合是一项技术含量较高的...通过理解STM32F103的工作原理、MPU6050的数据处理以及Visual Scope的使用,开发者可以深入掌握微控制器在复杂系统中的应用,并进一步提升自己的技能。
类方法 类方法其执行原理和用户函数是相同的,也是翻译成opcodes顺次调用。类的实现,zend用一个数据...就函数这一块来说,method实现原理和 function完全相同,理论上其性能也差不多,后面我们将做详细的性能对比。 性
【Girinoscope Arduino Scope】是一款基于Arduino的个人计算机示波器软件,它将Arduino板的功能与计算机软件相结合,提供了一种经济、便捷的方式来观测和分析电子信号。这个项目主要面向电子爱好者、学生以及对DIY...
"uart_scope_Ayaka"是一个典型的UART Scope实现,可能包含了上述所有组件。通过运行并分析其源代码,我们可以学习到如何实际操作UART接口,如何设计有效的数据解析算法,以及如何构建一个直观的图形界面。此外,这个...
@RefreshScope 是 Spring Cloud 中的一种特殊的 scope 实现,用来实现配置、实例热加载。了解 @RefreshScope 的原理和使用需要先了解 Scope 的概念。 Scope 是 Spring 2.0 开始就有的核心概念,表示 Bean 实例的...
这样,当需要为多个类实现相同功能时,只需要在一个地方定义,然后在需要的地方应用`@methodscope`。 2. **面向对象编程优化**: 使用MethodScope,可以减少代码冗余,提高代码复用性。传统的多继承结构可能导致...
这个压缩包的核心内容是关于“作用域卫士”(Scope Guard)的概念和实现,它在C++中是一种用于确保资源在正确的时间释放或者在异常情况下执行清理操作的编程技术。 首先,我们来看`scope_guard.h`文件,这通常是一...
NoScope利用Python的灵活性和丰富的库资源,为开发者提供了一个易于使用的工具,以实现快速、实时的目标检测解决方案。这个框架特别适合那些需要实时处理视频流的场景,如监控系统、自动驾驶汽车或无人机等。 No...
这篇文章将深入探讨Vue的作用域插槽的实现原理。 首先,我们要明白传统插槽(Slot)的概念。在Vue中,插槽是用于在组件内部定义可替换的内容区域。例如,一个组件可能有一个预设的模板结构,但允许用户插入自定义的...
4. **NameScope实现** - `NameScope`类是`INameScope`接口的主要实现,它还提供了一个依赖属性`NameScopeProperty`,用于附加到DependencyObject上,从而实现NameScope的附加和获取。 - 另一个实现`...
1. IQ解调的概念和原理,涉及数字信号处理。 2. LabVIEW编程技术,特别是如何用LabVIEW实现IQ解调算法。 3. 使用NI的示波器硬件进行信号采集的方法。 4. 可能涉及的高级主题,如符号定时恢复、噪声抑制等。 通过...
本文将围绕编译原理实验这一主题,详细介绍C--语言及其编译器的实现原理和使用方法。通过对C--语言的语法和编译器的编写说明,我们将了解编译原理的基本概念和实现步骤。 首先, lets introducethe C--语言。C--...
`scope-eval`的源代码位于`scope-eval-master`文件夹中,包含详细的实现细节。开发者可以通过阅读源码了解其内部结构和工作流程,这对于深入理解和定制`scope-eval`的功能非常有帮助。同时,源码也可以作为一个学习...