一、BeanFactoryPostProcessor
当spring初始化好BenaDefinnitionMap之后,提供了一个接口BeanFactoryPostProcessor,允许我们开发者自定义的去修改BeanFactory中的内容,这也是符合“spring”的开闭原则
public interface BeanFactoryPostProcessor {
/**
* 这里提供了修改beanFacotry的机会
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor ,提供了更强大的功能。
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/**
* 这个接口继承了postprocessor 并且将beanFactory转成了registry能够访问并修改BeanDefinition。
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
二、自定义BeanFactoryPostProcessor
实现BeanFactoryPostProcessor接口即可
public class MyFactoryProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//这里可以调用ConfigurableListableBeanFactory方法对它处理
//...
System.out.println("postProcessBeanFactory处理中....");
}
}
手动调用BeanFactoryPostProcessor
public class Tester {
public static void main(String[] args) throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new MyFactoryProcessor().postProcessBeanFactory(factory);
}
}
==============输出:============
postProcessBeanFactory处理中....
三、Spring常用BeanFactoryPostProcessor
spring也提供了不少BeanFactoryPostProcessor的实现,最常用的几个:PropertySourcesPlaceholderConfigurer 、 CustomerEditorConfigurer、 PropertyOverrideConfigurer等。
3.1 占位符处理器
【PropertyPlaceholderConfigurer】可以从属性文件、属性类获取属性
【PreferencesPlaceholderConfigurer】对属性来源具有优先级顺序
【PropertySourcesPlaceholderConfigurer 】提供了比PropertyPlaceholderConfigurer更强大的功能,可以从属性文件、属性类、环境、PropertySources等获取属性(Spring3.1以后推荐使用这个类)
【PropertyOverrideConfigurer】可以读取带有bean id的属性直接向bean注入属性,而不需要配置
PropertySourcesPlaceholderConfigurer
使用方法:
public class Tester {
public static void main(String[] args) throws Exception {
//创建一个BeanFactory,并注册一个bean,bean的类名用占位符表示
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
RootBeanDefinition beanDefinition = new RootBeanDefinition("${beanName}");//占位符
beanDefinition.setScope("${scop}");//占位符
factory.registerBeanDefinition("myBean", beanDefinition);
//创建一个PropertySourcesPlaceholderConfigurer,
//并加入含有占位符字符串对应的 MutablePropertySources
PropertySourcesPlaceholderConfigurer configurer
= new PropertySourcesPlaceholderConfigurer();
Map<String, Object> map = new HashMap<>();
map.put("beanName", "Tester");//占位符对应
map.put("scop", RootBeanDefinition.SCOPE_PROTOTYPE);//占位符对应“prototype”
MutablePropertySources sources = new MutablePropertySources();
sources.addLast(new MapPropertySource("abc", map));
configurer.setPropertySources(sources);
//对 BeanFactory增强,会替换掉占位符
configurer.postProcessBeanFactory(factory);
//获取这个bean
System.out.println(factory.getBeanDefinition("myBean"));
System.out.println(factory.getBean("myBean"));
}
@Override
public String toString() {
return "A bean";
}
}
3.2 CustomerEditorConfigurer
java是强类型的一种语言:int,String,String[],Person等等等等。
而我们配置的xml,里面都是字面量,也就是说,spring拿到的原始数据全部是字符串。
那么,spring是怎么把字符串转成各种各样的类型呢? 用 CustomEditorConfigurer,
Spring内部通过JavaBean的PropertyEditor来帮助进行String类型到其他类型的转换工作。只要为每种对象类型提供一个PropertyEditor,就可以根据该对象类型取得与其相对应的PropertyEditor来做具体的类型转换。Spring容器内部在做具体的类型转换的时候,会采用JavaBean框架内默认的PropertyEditor搜寻逻辑。
3.3 ConfigurationClassPostProcessor
ConfigurationClassPostProcessor是一个BeanFactory和BeanDefinitionRegistry处理器,BeanDefinitionRegistry处理方法能处理@Configuration等注解。
通过查看源码,ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry(..)内部使用ConfigurationClassParser类来处理@Configuration,@Import,@ImportResource和类内部的@Bean
如果@Import包含的Bean为ImportSelector类型。还会调用ImportSelector#selectImports()生成相应的Bean。
【ConfigurationClassPostProcessor基本使用】
class User{
//示例类
}
@Configuration
@Import({User.class})
public class ConfigTest {
@Bean
Date date() {
return new Date();
}
public static void main(String[] args) {
ConfigurationClassPostProcessor postProcessor = new ConfigurationClassPostProcessor();
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
registry.registerBeanDefinition("test", new RootBeanDefinition(ConfigTest.class));
//处理BeanDefinitionRegistry
postProcessor.postProcessBeanDefinitionRegistry(registry);
//输出结果
System.out.println(registry.getBeanDefinition("test"));//可以输出
System.out.println(registry.getBeanDefinition("date"));//可以输出
System.out.println(registry.getBeanDefinition("User"));//可以输出
}
}
【ConfigurationClassPostProcessor配合@Import/ImportSelector使用】
class User{
//示例类
}
class MySelector implements ImportSelector{
//自定义一个ImportSelector实现类
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//会生成两个Bean(java.util.Date和User)
return new String[]{"java.util.Date","User"};
}
}
@Configuration
@Import({MySelector.class})
public class ConfigTest {
public static void main(String[] args) {
ConfigurationClassPostProcessor postProcessor = new ConfigurationClassPostProcessor();
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
registry.registerBeanDefinition("test", new RootBeanDefinition(ConfigTest.class));
postProcessor.postProcessBeanDefinitionRegistry(registry);
System.out.println(registry.getBeanDefinition("test"));//
System.out.println(registry.getBeanDefinition("User"));//可以输出
System.out.println(registry.getBeanDefinition("java.util.Date"));//可以输出
}
}