九零后大叔
技术人的点点滴滴

beanfactory篇-(八)BeanFactoryPostProcessor接口的使用

回顾:通过前面的章节的了解,我们又了解了InstantiationAwareBeanPostProcessor接口的基本使用,当我们想要介入一个bean的实例化和初始化的各个环节的时候,只需要写一个创建一个类实现InstantiationAwareBeanPostProcessor接口,即可灵活的进行一些自定义的业务逻辑处理。本章节我们将学习一个新的接口,就是BeanFactoryPostProcessor接口


1. BeanFactoryPostProcessor接口的基本介绍

一、通过前面的一些章节的知识介绍,我们基本上可以确定一个观念了,那就是BeanFactory是spring落地到代码层面的基础实现,也就是标配版本的spring,提供spring最基础和最核心的功能;而ApplicationContext是spring落地到代码层面的丰富实现,也就是豪华版本的spring,不但提供spring最基础和最核心的功能,还提供一些我们业务开发过程中的常用扩展功能。

二、在spring的源码中,实际上ApplicationContext是间接的持有一个BeanFactory对象的。也就是说基于ApplicationContext的spring容器,在启动该过程中,一定是要创建并且初始化一个BeanFactory对象的。那么问题来了,在beanFactory对象被创建后,开发者希望自己能介入到beanFactory的
初始化过程中去,这个也是可以的。BeanFactoryPostProcessor接口就是spring提供的一个扩展机制,允许开发者在spring的启动过程中,有机会参与到beanFactory对象的初始化过程中去。一个常用的使用场景就是我们基于代码动态的注册一个bean信息到beanFactory中去,下面我们看看这个到底是如何使用的。

三、本接口主要包含一个重要方法:postProcessBeanFactory方法。该方法是beanFactory对象被创建后,给开发者一个扩展或者修改beanFactory对象的机会,下面我就看看如何使用这个接口。



2. BeanFactoryPostProcessor接口的基本使用

第一步:创建一个User类如下:

@Data
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class User implements Serializable {

    private static final long serialVersionUID = 4800166777883697833L;

    private Long id;
    private String name;
    private String identity;
    private String mobile;
    private String bankcard;
    private Integer age;
    private Integer gender;

}

第二步:创建一个接口和接口实现类如下:

public interface UserService {

    User findUserById(Long id);

}

//注意,这个地方不需要这个注解了
//@Service
public class UserServiceImpl implements UserService {

    private Map<Integer, String> blackListMap = new HashMap<>();

    @Override
    public User findUserById(Long id) {

        User user = new User();
        user.setId(id);
        user.setName("张山");
        user.setIdentity("张山");
        user.setBankcard("36457736355363");
        user.setMobile("16752652625");
        user.setGender(2);
        user.setAge(18);

        return user;
    }

}

第三步:创建一个GlobalBeanFactoryPostProcessor类,实现了BeanFactoryPostProcessor接口

@Component
public class GlobalBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("Execute postProcessBeanFactory.");

        //除了xml配置,@Service外,这里是第三种注册bean信息的方式,也就是代码中做注册
        BeanDefinitionRegistry bdr = (BeanDefinitionRegistry)beanFactory;
        GenericBeanDefinition gbd = new GenericBeanDefinition();
        gbd.setBeanClass(UserServiceImpl.class);
        gbd.setScope(BeanDefinition.SCOPE_SINGLETON);
        gbd.setAutowireCandidate(true);
        bdr.registerBeanDefinition("userService", gbd);

    }

}

第四步:配置applicationContext.xml文件内容:

<context:component-scan base-package="com.minesoft.tutorial" />

第五步:最后我们运行下面的代码

    ClassPathXmlApplicationContext cac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    UserService userService = cac.getBean(UserService.class);
    User user = userService.findUserById(100L);
    System.out.println(JSONObject.toJSONString(user));

运行完成上面的代码,我们会发现一个奇怪的事实,就是我们的UserServiceImpl这个bean,既不需要在applicationContext.xml文件中配置,也不需要加上@Service注解,居然也能被spring创建并管理起来,能够正常的使用。其实这种使用方式并不奇怪,只不过我们不常用而已,这种用法正是BeanFactoryPostProcessor接口的常用用法。

总结:从上面我们看到了除了xml配置,和@Service注解之外的第三种注册bean信息的方式,也就是通过实现BeanFactoryPostProcessor接口,在代码中动态的去注册bean信息。那么可能有同学好奇了,前面的两种和这种本质上有啥区别呢?答案是本质上无任何区别。前两种方式最终底层也是执行了第三步的postProcessBeanFactory方法的那段代码,即将bean描述信息注册到beanfactory中去。至于这个解析过程,后面我们会详细的提到。本章节我们先了解这些基础的功能用法。


3. BeanPostProcessor接口和BeanFactoryPostProcessor接口的区别

首先BeanFactory是一个spring的容器,也就是一个容器级别的对象,这个容器对象里面管理着多个bean对象。基于这一点,我们看看下面的二者的不同。

一、二者的量级就不一样,从名称上就能分辨。BeanFactoryPostProcessor接口作用于BeanFactory对象的初始化过程,而BeanPostProcessor接口只能作用Bean对象的初始化过程。一个用于拦截或者介入容器级对象(即BeanFactory对象)的初始化过程;一个用于拦截或者介入bean对象的初始化过程。

二、一个BeanFactoryPostProcessor接口的实现类在spring容器的启动过程中,一般只会被调用一次;而BeanPostProcessor接口的实现类在spring容器的启动过程中,一般会被调用N次(N与这个spring容器所创建和管理的Bean对象一样)。

更多知识请关注公众号

赞(0) 赏一下
未经允许不得转载:九零后大叔的技术博客 » beanfactory篇-(八)BeanFactoryPostProcessor接口的使用
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

九零后大叔的技术博客

联系我们联系我们

感谢您的支持

支付宝扫一扫打赏

微信扫一扫打赏