Scope实现原理

[size=medium]内置Scope分类
Singleton 每个IOC容器对一个bean定义创建唯一实例
Prototype 对一个bean定义,每次请求容器都会创建新的实例
Request 对一个bean定义,一次web请求会创建一个实例
Session 对一个bean定义,一次web会话创建一个实例
Global Session 对一个bean定义,一次porlet会话创建一个实例
后三种只在Web环境下使用,AbstractApplicationContext refresh入口
[img]http://dl2.iteye.com/upload/attachment/0086/2360/64e104ec-5c07-3729-83b8-891845a4e2a8.jpg[/img]
AbstractRefreshableWebApplicationContext会注册这三种BEAN

[img]http://dl2.iteye.com/upload/attachment/0086/2362/dde430a8-6eda-38e2-90f5-a19198fe9062.jpg[/img]
WebApplicationContextUtils具体代码

[img]http://dl2.iteye.com/upload/attachment/0086/2366/730c2033-47aa-3b6d-b094-b9b9ffc010cc.jpg[/img]

当使用AbstractRefreshableWebApplicationContext并不会注册这三种Bean.
这三种Scope父类方法调用RequestContextHolder

[img]http://dl2.iteye.com/upload/attachment/0086/2377/ffe9d2b8-e454-38e7-af7e-3aef4b4a1751.jpg[/img]
在RequestContextHolder实现中,RequestAttribute为空,则抛出错误

[img]http://dl2.iteye.com/upload/attachment/0086/2379/d7b19745-e5d4-38d6-8198-8a3d02da54cd.jpg[/img]

RequestAttribute的实现ServletRequestAttributes中,封装了HTTP对象和Scope的Bean获取,设置和销毁方法

[img]http://dl2.iteye.com/upload/attachment/0086/2381/1460bc34-7b9e-3824-bf1a-2bf36f396475.jpg[/img]

[img]http://dl2.iteye.com/upload/attachment/0086/2387/340eebad-5a76-3cca-b111-21e66d93437b.jpg[/img]

[img]http://dl2.iteye.com/upload/attachment/0086/2389/fc7b9d7d-8f1d-3dda-8ce6-984fb423b43d.jpg[/img]

所以在WEB环境下,如果使用SPRING MVC,则在 DispatcherServlet, or DispatcherPortlet已经初始化RequestAttribute对象,否则必须做相关配置以初始化。
使用servlet2.4+容器,web.xml配置如下[/size]
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>

[size=medium]servlet2.3,web配置如下[/size]
<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>


[size=medium]RequestContextFilter初始化RequestAtrributes[/size][img]http://dl2.iteye.com/upload/attachment/0086/2391/e7c53c34-430a-3f61-8054-67ce78889190.jpg[/img]

[size=medium]
Scope只有在getBean中有效
Spring不仅负责Bean的实例化,而且还管理依赖关系,根据依赖仅仅会在第一次请求时创建和装配好bean。因此:如果在bean定义中只是指定了scope,则除了singleton,其他的scope定义的bean实例的含义是无效的,必须钩入向Spring容器请求,也就是调用getBean方法。换句话说,我们必须改变依赖关系的注入。可以想到使用代理作为被注入的对象,当调用代理方法时,会实时的getBean 请求容器。实现这种机制的是 <aop:scoped-proxy/>[/size]

<?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>

[size=medium]我们插入了<aop:scoped-proxy/>元素在被注入的userPreferences定义中,为什么scope等于request,session, global session,或自定义的scope bean需要这样?对比下面的定义[/size]

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>

[size=medium]上面的例子中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动态代理,则作如下配置。[/size]

<!-- 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>

[size=medium]ScopedProxyFactoryBean实现<aop:scoped-proxy/>
spring-beans DTD 或者 XSD的解析者DefaultBeanDefinitionDocumentReader
解析根元素及代理BeanDefinitionParserDelegate解析其他的子元素
根元素有beans,alias,import[/size]

/**
* 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);
}
}

[size=medium]子元素的解析者BeanDefinitionParserDelegate,当一个bean定义解析好之后,要进一步进行可能的自定义属性或内置元素的解析,进入decorateIfRequired方法。[/size]
[img]http://dl2.iteye.com/upload/attachment/0086/2450/f195d0e2-24e4-3964-96c5-8a8feaecb51d.jpg[/img]


[img]http://dl2.iteye.com/upload/attachment/0086/2454/7efb4629-738b-39c5-bd83-87577dd62566.jpg[/img]
[size=medium]
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
载入资源代码
[/size]
[img]http://dl2.iteye.com/upload/attachment/0086/2456/5cf8efb9-9009-3b9e-b313-a46b3662c23f.jpg[/img]
[size=medium]AopNamespaceHandler实现中可以看到config用于事务处理的;aspectj-autoproxy用于aspectj自动代理的;scoped-proxy用于Scope bean处理的;所以<aop:scoped-proxy/>将由ScopedProxyBeanDefinitionDecorator处理[/size][img]http://dl2.iteye.com/upload/attachment/0086/2462/29f85e78-4d41-33f6-ae24-3e6273b024b0.jpg[/img]
[size=medium]ScopedProxyBeanDefinitionDecorator最终代理ScopedProxyUtils.createScopedProxy
1.创建一个ScopedProxyFactoryBean对应的代理RootBeanDefinition
2.占有了Scope bean的标识符,可能的候选者(当以类型装配查找时)
3.Scope bean的名字为标识符变成 "scopedTarget." + ID ,同时丧失候选资格[/size]

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());

[size=medium]ScopedProxyFactoryBean实现
1.setProxyTargetClass设置代理方式,true为CGliB代理,false为JDK代理
2.scopedTargetSource = new SimpleBeanTargetSource()代理方法每调用一次,就会向Spring容器发送getBean请求
3.添加AopInfrastructureBean接口,生成代理对象;说明代理对象类型并不适合自动代理机制
4.添加DelegatingIntroductionInterceptor introduction借口,并暴露DefaultScopedObject对象,生成代理;所以可以编程式把代理对象转化ScopedObject对象而从scope中进行获取和移除bean[/size]

/*
* 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;
}

}


[size=medium]自定义scope
编写了Scope实现之后,要将他注册到Spring容器中,下面是核心注册方法
void registerScope(String scopeName, Scope scope);
这个方法在ConfigurableBeanFactory中声明,大多数ApplicationContext都实现了它。
方法中的第一个参数是scope的名字,用于配置bean指定scope时使用,第二个参数是具体实现。
编程式的注册[/size]
Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);

[size=medium]xml配置[/size]
<bean id="..." class="..." scope="thread">

[size=medium]声明式注册
xml配置[/size]
<?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>

[size=medium] 实现
AbstractApplicationContext入口 refresh[/size]
[img]http://dl2.iteye.com/upload/attachment/0086/2742/fb2361e5-5c98-350a-aa06-808124297b7a.jpg[/img]
[size=medium]显然所有的BeanFactoryPostProcessor会在此处被调用,包括注册Scope的CustomScopeConfigurer,因为它是一个BeanFactoryPostProcessor实例。[/size]

@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");
}
}
}
}

[size=medium]那不得不提的是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方法[/size]

/**
* 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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值