您的位置:首页 > 编程语言 > Java开发

Spring源码解析笔记9——容器的功能扩展BeanFactory的后处理(BeanFactoryPostProcessor)

2018-01-31 14:27 796 查看
BeanFactoryPostProcessor接口跟BeanPostProcessor类似,可以对bean的定义(配置元数据)进行处理。SpringIoc容器允许BeanFactoryPostProcessor在容器实际实例化任何其他的bean之前读取配置元数据,并有可能修改它。

如果想改变实际的bean实例(例如从配置元数据创建的对象),那么最好使用BeanPostProcessor。

BeanFactoryPostProcessor的作用域范围是容器级的。它只和你所使用的容器有关。如果你在容器中定义了一个BeanFactoryPostProcessor,它仅仅对此容器中的bean进行后处理。BeanFactoryPostProcessor不会对定义在另一个容器中的bean进行后处理,即使这两个容器都在同一层次。

1.BeanFactoryPostProcessor的典型应用:PropertyPlaceholderConfigurer

<!--xml配置文件中加入以下代码-->

<bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>jdbc.properties</value>
</property>
<property name="fileEncoding">
<value>UTF-8</value>
</property>
</bean>


#jdbc.properties文件内容

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.1.105:3306/msmk1231?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF-8
jdbc.username=mysql
jdbc.password=mysql


<!--spring配置文件中使用外部文件的值-->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" >
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>


propertyConfigurer只不过是Spring框架管理的一个bean,并没有被bean或者对象引用,Spring的beanFactory是怎么知道要从这个bean 中获取配置信息呢?

PropertyPlaceholderConfigurer实现了BeanFactoryPostProcessor接口,当spring加载任何实现了这个接口的bean的配置时,都会在bean工厂载入所有bean的配置之后执行postProcessBeanFactory方法。

PropertyResourceConfigurer类中实现了postProcessFactory方法,在方法中先后调用了mergeProperties,convertProperties,processorProperties这三个方法。分别得到配置,将得到的配置转换为合适的类型,最后将配置内容告知BeanFactory。

2.使用自定义BeanFactoryPostProcessor

配置文件BeanFactory.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"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bfpp" class="cn.partner4java.beanfactorypostprocessor.ObscenityRemovingBeanFactoryPostProcessor">
<property name="obscenities">
<set>
<value>winky</value>
<value>bum</value>
</set>
</property>
</bean>
<bean id="simpleBean" class="cn.partner4java.beanfactorypostprocessor.SimpleBean">
<property name="connectionString" value="bollocks"/>
<property name="password" value="winky"/>
<property name="username" value="bum"/>
</bean>

</beans>


ObscenityRemovingBeanFactoryPostProcessor类:

class ObscenityRemovingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
/** bean的名称 */
private String name;
/** 注册过滤文字 */
private Set<String> obscenities;

public ObscenityRemovingBeanFactoryPostProcessor() {
this.obscenities = new HashSet<String>();

}

/**
* 主要业务处理。
*/
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();

for(String beanName:beanNames){

BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);

StringValueResolver valueResolver = new StringValueResolver() {
public String resolveStringValue(String strVal) {
if(isObscene(strVal)){

10692
return "****";
}
return strVal;
}
};
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
visitor.visitBeanDefinition(beanDefinition);
}

}

private boolean isObscene(Object value) {
String potentialObscenity = value.toString().toUpperCase();
return this.obscenities.contains(potentialObscenity);
}

public void setObscenities(Set<String> obscenities) {
this.obscenities.clear();
for(String obscentity:obscenities){
this.obscenities.add(obscentity.toUpperCase());
}
}
}


测试代码:

ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("/META-INF/Beanfactory.xml"));
BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor)beanFactory.getBean("bfpp");
bfpp.postProcessBeanFactory(beanFactory);
System.out.println(beanFactory.getBean("simpleBean"));


运行结果:

SimpleBean{password='****', username='****', connectionString='bollocks'}


3.激活BeanFactoryPostProcessor

继续跟踪refresh方法中的this.invokeBeanFactoryPostProcessors(beanFactory)方法(在上一篇文章里面——笔记8中):

public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();

if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();

for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}

// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}

// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}

else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, 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<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}

// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}


4.注册BeanPostProcessor,继续跟踪refresh方法中的registerBeanPostProcessors(beanFactory)方法(在上一篇文章里面——笔记8中):

/**
Spring中大部分功能都是通过后处理的方式进行扩展的,
但是BeanFactory中其实并没有实现后处理的自动注册,
所以在调用的时候如果没有进行手动注册是不能使用的,
但是ApplicationContext中添加了自动注册功能。
**/

//举例:自定义一个后处理器。
class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor{

@Override
public Object postProcessBeforeInstantiation(Class<?> aClass, String s) throws BeansException {
System.out.println("################");
return null;
}

@Override
public boolean postProcessAfterInstantiation(Object o, String s) throws BeansException {
return false;
}

@Override
public PropertyValues postProcessPropertyValues(PropertyValues propertyValues, PropertyDescriptor[] propertyDescriptors, Object o, String s) throws BeansException {
return null;
}

@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
return null;
}

@Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
return null;
}
}

//在配置中加上这句话:
<bean class="test.MyInstantiationAwareBeanPostProcessor"/>

/**
使用BeanFactory方式加载时不会有任何改变的,但是使用ApplicationContext方式获取bean时,
会在获取每个bean时打印出"################",
这个特性就是在registerBeanPostProcessors方法中完成的。
**/


//registerBeanPostProcessors源码:
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}

// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring