在第二编对BeanFactory的分析中,我们老能看见BeanFactoyPostProcessor的身影,那么在这一节中,我们来详细的讨论一下
BeanFactoryPostProcessor的代码结构,从中学习他的优秀之处;
BeanFactoryPostProcessor能够修改bean配置文件中的bean的定义;使得我们能够进行一些额外的处理;
在spring中,我们几乎不用自己扩展这个接口,因为他内置了很多实现,但是,我们从原理上和代码上来分析其功能的实现;
一下是他的类图实现:
拿PropertyPlaceholderConfigurer举例;
PropertyPlaceholderConfigurer的功能是这样的,我们在配置文件中配置如下Bean:
userinfo.properties:
db.username:scott
db.password:tiger
然后在ApplicationContext下面会自动调用这个PostProcessor;把 ${db.userName}转换为scott;
在BeanFactory下面的话,必须手动生成以上PostProcesor对象,并且手动调用postProcessorBeanFactory(configureableBeanFactory)方法;
那么我们现在来看一下代码的实现
在PropertyResourceConfigurer中,定义了 postProcessBeanFactory方法,定义了方法执行的流程,使用了模板模式;
将具体算法的实现暴露到了子类;
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
Properties mergedProps = mergeProperties();
// Convert the merged properties, if necessary.
convertProperties(mergedProps);
// Let the subclass process the properties.
processProperties(beanFactory, mergedProps);
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
模板方法1:mergeProperties()如下:
protected Properties mergeProperties() throws IOException {
Properties result = new Properties();
if (this.localOverride) {
// Load properties from file upfront, to let local properties override.
loadProperties(result);
}
if (this.localProperties != null) {
for (int i = 0; i < this.localProperties.length; i++) {
Properties props = this.localProperties[i];
// Use propertyNames enumeration to also catch default properties.
for (Enumeration en = props.propertyNames(); en.hasMoreElements();) {
String key = (String) en.nextElement();
result.setProperty(key, props.getProperty(key));
}
}
}
if (!this.localOverride) {
// Load properties from file afterwards, to let those properties override.
loadProperties(result);
}
return result;
}
在这个方法中,将加载你在构造bean的时候传入的properties值,然后存储到这个PostProcessor中,方便覆盖bean定义的元数据,如${db.username}等等;
模板方法processProperties被推到子类实现了:
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
throws BeansException {
//构造一个BeanDefinition访问器(前一节已经分析过),是其内部类:
BeanDefinitionVisitor visitor = new PlaceholderResolvingBeanDefinitionVisitor(props);
//得到所有beanName
String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
for (int i = 0; i < beanNames.length; i++) {
// Check that we're not parsing our own bean definition,
// to avoid failing on unresolvable placeholders in properties file locations.
if (!(beanNames[i].equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(beanNames[i]);
try {
//在这段代码中会遍历所有的Bean定义的带来${}的属性,包括map ,list,String等等;
visitor.visitBeanDefinition(bd);
}
catch (BeanDefinitionStoreException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanNames[i], ex.getMessage());
}
}
}
}
内部的BeanDefinition访问器:
private class PlaceholderResolvingBeanDefinitionVisitor extends BeanDefinitionVisitor {
private final Properties props;
public PlaceholderResolvingBeanDefinitionVisitor(Properties props) {
this.props = props;
}
protected String resolveStringValue(String strVal) throws BeansException {
return parseStringValue(strVal, this.props, new HashSet());
}
}
在访问器中visitBeanDefinition(bd)会遍历此BeanDefinition的proerty,constructor等等可以设置${}的地方例如propertiy:
protected void visitPropertyValues(MutablePropertyValues pvs) {
PropertyValue[] pvArray = pvs.getPropertyValues();
for (int i = 0; i < pvArray.length; i++) {
PropertyValue pv = pvArray[i];
//分别解决每个属性字段的解析;
Object newVal = resolveValue(pv.getValue());
if (!ObjectUtils.nullSafeEquals(newVal, pv.getValue())) {
pvs.addPropertyValue(pv.getName(), newVal);
}
}
}
如何解析,是暴露到子类中去进行的如PropertyPlaceholderConfigurer是对${}进行外部文件的替换,我们也可以自己实现别的替换方式,如:****替换位"corey",很无聊吧: ->;
resolveStringValue((String) value);:
protected Object resolveValue(Object value) {
if (value instanceof BeanDefinition) {
visitBeanDefinition((BeanDefinition) value);
}
else if (value instanceof BeanDefinitionHolder) {
visitBeanDefinition(((BeanDefinitionHolder) value).getBeanDefinition());
}
else if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
String newBeanName = resolveStringValue(ref.getBeanName());
if (!newBeanName.equals(ref.getBeanName())) {
return new RuntimeBeanReference(newBeanName);
}
}
else if (value instanceof List) {
visitList((List) value);
}
else if (value instanceof Set) {
visitSet((Set) value);
}
else if (value instanceof Map) {
visitMap((Map) value);
}
else if (value instanceof TypedStringValue) {
TypedStringValue typedStringValue = (TypedStringValue) value;
String visitdString = resolveStringValue(typedStringValue.getValue());
typedStringValue.setValue(visitdString);
}
else if (value instanceof String) {
return resolveStringValue((String) value);
}
return value;
}
那${userName}举例:在PropertyPlaceholderConfigurer中:
protected String parseStringValue(String strVal, Properties props, Set visitedPlaceholders)
throws BeanDefinitionStoreException {
StringBuffer buf = new StringBuffer(strVal);
//提取出${}中间的字符串,
int startIndex = strVal.indexOf(this.placeholderPrefix);
while (startIndex != -1) {
int endIndex = buf.toString().indexOf(
this.placeholderSuffix, startIndex + this.placeholderPrefix.length());
if (endIndex != -1) {
String placeholder = buf.substring(startIndex + this.placeholderPrefix.length(), endIndex);
if (!visitedPlaceholders.add(placeholder)) {
throw new BeanDefinitionStoreException(
"Circular placeholder reference '" + placeholder + "' in property definitions");
}
//用System.getEnv和外部的properties文件替代了${}中间的值
String propVal = resolvePlaceholder(placeholder, props, this.systemPropertiesMode);
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
//嵌套执行;直至无法解析;
propVal = parseStringValue(propVal, props, visitedPlaceholders);
buf.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
if (logger.isDebugEnabled()) {
logger.debug("Resolved placeholder '" + placeholder + "' to value [" + propVal + "]");
}
startIndex = buf.toString().indexOf(this.placeholderPrefix, startIndex + propVal.length());
}
else if (this.ignoreUnresolvablePlaceholders) {
// Proceed with unprocessed value.
startIndex = buf.toString().indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
}
else {
throw new BeanDefinitionStoreException("Could not resolve placeholder '" + placeholder + "'");
}
visitedPlaceholders.remove(placeholder);
}
else {
startIndex = -1;
}
}
return buf.toString();
}
在这里,模板模式再一次展现了他的魅力,我想在这里讨论一下:PropertiesLoaderSupport和PropertyResourceConfigurer的关系,我们看见PropertiesLoaderSupport提供了properties文件的加载,在这里继承抽象类PropertiesLoaderSupport其实是达到与复用;
我们继承一个抽象类的原因有两个:
1):与其它类功能方法之间的复用(比如这里的PropertiesLoaderSupport);而不是从分类学上面属于一类,这样的抽象类属于工具类;这里的功能复用,有两种手段可以实现,一种是组合,一种是继承;
2):抽象类中约定类流程,把算法的具体实现暴露给子类;
BeanFactoryPostProcessor的代码结构,从中学习他的优秀之处;
BeanFactoryPostProcessor能够修改bean配置文件中的bean的定义;使得我们能够进行一些额外的处理;
在spring中,我们几乎不用自己扩展这个接口,因为他内置了很多实现,但是,我们从原理上和代码上来分析其功能的实现;
一下是他的类图实现:
拿PropertyPlaceholderConfigurer举例;
PropertyPlaceholderConfigurer的功能是这样的,我们在配置文件中配置如下Bean:
- <bean id="PropertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="order">1</property>
- <property name="locations">
- <list>
- <value>userinfo.properties</value>
- </list>
- </property>
- </bean>
- <bean id="user" class="org.test.UserInfo">
- <property name="order" value="${db.userName}"></property>
- <property name="order" value="${db.password}"></property>
- </property>
- </bean>
userinfo.properties:
db.username:scott
db.password:tiger
然后在ApplicationContext下面会自动调用这个PostProcessor;把 ${db.userName}转换为scott;
在BeanFactory下面的话,必须手动生成以上PostProcesor对象,并且手动调用postProcessorBeanFactory(configureableBeanFactory)方法;
那么我们现在来看一下代码的实现
在PropertyResourceConfigurer中,定义了 postProcessBeanFactory方法,定义了方法执行的流程,使用了模板模式;
将具体算法的实现暴露到了子类;
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
Properties mergedProps = mergeProperties();
// Convert the merged properties, if necessary.
convertProperties(mergedProps);
// Let the subclass process the properties.
processProperties(beanFactory, mergedProps);
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
模板方法1:mergeProperties()如下:
protected Properties mergeProperties() throws IOException {
Properties result = new Properties();
if (this.localOverride) {
// Load properties from file upfront, to let local properties override.
loadProperties(result);
}
if (this.localProperties != null) {
for (int i = 0; i < this.localProperties.length; i++) {
Properties props = this.localProperties[i];
// Use propertyNames enumeration to also catch default properties.
for (Enumeration en = props.propertyNames(); en.hasMoreElements();) {
String key = (String) en.nextElement();
result.setProperty(key, props.getProperty(key));
}
}
}
if (!this.localOverride) {
// Load properties from file afterwards, to let those properties override.
loadProperties(result);
}
return result;
}
在这个方法中,将加载你在构造bean的时候传入的properties值,然后存储到这个PostProcessor中,方便覆盖bean定义的元数据,如${db.username}等等;
模板方法processProperties被推到子类实现了:
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
throws BeansException {
//构造一个BeanDefinition访问器(前一节已经分析过),是其内部类:
BeanDefinitionVisitor visitor = new PlaceholderResolvingBeanDefinitionVisitor(props);
//得到所有beanName
String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
for (int i = 0; i < beanNames.length; i++) {
// Check that we're not parsing our own bean definition,
// to avoid failing on unresolvable placeholders in properties file locations.
if (!(beanNames[i].equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(beanNames[i]);
try {
//在这段代码中会遍历所有的Bean定义的带来${}的属性,包括map ,list,String等等;
visitor.visitBeanDefinition(bd);
}
catch (BeanDefinitionStoreException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanNames[i], ex.getMessage());
}
}
}
}
内部的BeanDefinition访问器:
private class PlaceholderResolvingBeanDefinitionVisitor extends BeanDefinitionVisitor {
private final Properties props;
public PlaceholderResolvingBeanDefinitionVisitor(Properties props) {
this.props = props;
}
protected String resolveStringValue(String strVal) throws BeansException {
return parseStringValue(strVal, this.props, new HashSet());
}
}
在访问器中visitBeanDefinition(bd)会遍历此BeanDefinition的proerty,constructor等等可以设置${}的地方例如propertiy:
protected void visitPropertyValues(MutablePropertyValues pvs) {
PropertyValue[] pvArray = pvs.getPropertyValues();
for (int i = 0; i < pvArray.length; i++) {
PropertyValue pv = pvArray[i];
//分别解决每个属性字段的解析;
Object newVal = resolveValue(pv.getValue());
if (!ObjectUtils.nullSafeEquals(newVal, pv.getValue())) {
pvs.addPropertyValue(pv.getName(), newVal);
}
}
}
如何解析,是暴露到子类中去进行的如PropertyPlaceholderConfigurer是对${}进行外部文件的替换,我们也可以自己实现别的替换方式,如:****替换位"corey",很无聊吧: ->;
resolveStringValue((String) value);:
protected Object resolveValue(Object value) {
if (value instanceof BeanDefinition) {
visitBeanDefinition((BeanDefinition) value);
}
else if (value instanceof BeanDefinitionHolder) {
visitBeanDefinition(((BeanDefinitionHolder) value).getBeanDefinition());
}
else if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
String newBeanName = resolveStringValue(ref.getBeanName());
if (!newBeanName.equals(ref.getBeanName())) {
return new RuntimeBeanReference(newBeanName);
}
}
else if (value instanceof List) {
visitList((List) value);
}
else if (value instanceof Set) {
visitSet((Set) value);
}
else if (value instanceof Map) {
visitMap((Map) value);
}
else if (value instanceof TypedStringValue) {
TypedStringValue typedStringValue = (TypedStringValue) value;
String visitdString = resolveStringValue(typedStringValue.getValue());
typedStringValue.setValue(visitdString);
}
else if (value instanceof String) {
return resolveStringValue((String) value);
}
return value;
}
那${userName}举例:在PropertyPlaceholderConfigurer中:
protected String parseStringValue(String strVal, Properties props, Set visitedPlaceholders)
throws BeanDefinitionStoreException {
StringBuffer buf = new StringBuffer(strVal);
//提取出${}中间的字符串,
int startIndex = strVal.indexOf(this.placeholderPrefix);
while (startIndex != -1) {
int endIndex = buf.toString().indexOf(
this.placeholderSuffix, startIndex + this.placeholderPrefix.length());
if (endIndex != -1) {
String placeholder = buf.substring(startIndex + this.placeholderPrefix.length(), endIndex);
if (!visitedPlaceholders.add(placeholder)) {
throw new BeanDefinitionStoreException(
"Circular placeholder reference '" + placeholder + "' in property definitions");
}
//用System.getEnv和外部的properties文件替代了${}中间的值
String propVal = resolvePlaceholder(placeholder, props, this.systemPropertiesMode);
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
//嵌套执行;直至无法解析;
propVal = parseStringValue(propVal, props, visitedPlaceholders);
buf.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
if (logger.isDebugEnabled()) {
logger.debug("Resolved placeholder '" + placeholder + "' to value [" + propVal + "]");
}
startIndex = buf.toString().indexOf(this.placeholderPrefix, startIndex + propVal.length());
}
else if (this.ignoreUnresolvablePlaceholders) {
// Proceed with unprocessed value.
startIndex = buf.toString().indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
}
else {
throw new BeanDefinitionStoreException("Could not resolve placeholder '" + placeholder + "'");
}
visitedPlaceholders.remove(placeholder);
}
else {
startIndex = -1;
}
}
return buf.toString();
}
在这里,模板模式再一次展现了他的魅力,我想在这里讨论一下:PropertiesLoaderSupport和PropertyResourceConfigurer的关系,我们看见PropertiesLoaderSupport提供了properties文件的加载,在这里继承抽象类PropertiesLoaderSupport其实是达到与复用;
我们继承一个抽象类的原因有两个:
1):与其它类功能方法之间的复用(比如这里的PropertiesLoaderSupport);而不是从分类学上面属于一类,这样的抽象类属于工具类;这里的功能复用,有两种手段可以实现,一种是组合,一种是继承;
2):抽象类中约定类流程,把算法的具体实现暴露给子类;