本文共 5772 字,大约阅读时间需要 19 分钟。
当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接口即可
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的实现,最常用的几个:PropertySourcesPlaceholderConfigurer 、 CustomerEditorConfigurer、 PropertyOverrideConfigurer等。
【PropertyPlaceholderConfigurer】可以从属性文件、属性类获取属性 【PreferencesPlaceholderConfigurer】对属性来源具有优先级顺序 【PropertySourcesPlaceholderConfigurer 】提供了比PropertyPlaceholderConfigurer更强大的功能,可以从属性文件、属性类、环境、PropertySources等获取属性(Spring3.1以后推荐使用这个类) 【PropertyOverrideConfigurer】可以读取带有bean id的属性直接向bean注入属性,而不需要配置
使用方法:
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(); Mapmap = 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"; }}
java是强类型的一种语言:int,String,String[],Person等等等等。
而我们配置的xml,里面都是字面量,也就是说,spring拿到的原始数据全部是字符串。 那么,spring是怎么把字符串转成各种各样的类型呢? 用 CustomEditorConfigurer, Spring内部通过JavaBean的PropertyEditor来帮助进行String类型到其他类型的转换工作。只要为每种对象类型提供一个PropertyEditor,就可以根据该对象类型取得与其相对应的PropertyEditor来做具体的类型转换。Spring容器内部在做具体的类型转换的时候,会采用JavaBean框架内默认的PropertyEditor搜寻逻辑。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"));//可以输出 }}