【Spring4揭秘 BeanFactory】修改BeanFactory-BeanFactoryPostProcessor

一、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"));//可以输出
     }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值