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

beanfactory篇-(七)InstantiationAwareBeanPostProcessor接口的使用

回顾:通过前面的章节的了解,我们又了解了BeanPostProcessor接口的基本使用。当我们想要在一个bean被创建好之后,开发者能有机会参与到这个bean的初始化过程的时候,我们只需要实现BeanPostProcessor接口,并在接口方法里面选择性的初始化自己的bean对象即可。本章我们将新学习一个接口,这个接口就是InstantiationAwareBeanPostProcessor接口。


1. InstantiationAwareBeanPostProcessor接口的基本介绍


一、实际上来说,对于一个bean的生命周期而言,有两个非常重要的过程:bean的实例化和bean的初始化。 实例化就是创建一个bean,而初始化是对已经创建好的bean进行初始化。
[1]bean的实例化有三种方式:xml配置后spring容器创建,@Service等注解后spring创建,实现FactoryBean接口后用户代码自己创建。
[2]bean的初始化有三种方式:配置init-method属性方式,实现InitializingBean接口方式,实现BeanPostProcessor接口方式。

二、了解了上面的一些重要的概念之后,我们再来了解InstantiationAwareBeanPostProcessor接口就好理解了。
因为InstantiationAwareBeanPostProcessor接口是继承至BeanPostProcessor接口的,所以这个接口是对BeanPostProcessor接口的功能的扩展,BeanPostProcessor接口所有的功能他都有。那么问题是都扩展了哪些功能呢?就是扩展了postProcessBeforeInstantiation、postProcessAfterInstantiation、postProcessPropertyValues三个方法。下面我们重点介绍一下这三个方法:

[1] postProcessBeforeInstantiation方法:调用本方法之前某个业务bean还未被创建,开发者是否需要自己创建这个bean(用法与FactoryBean接口有点类似)。如果开发者在该方法内放置如下代码,则spring启动过程中不会自己通过反射的方式创建这个bean,而是执行下面的代码创建一个bean。

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {

    //如果bean类型是UserServiceImpl,则该bean由开发者自己的代码创建
    if(beanClass.equals(UserServiceImpl.class)) {
        UserService userService = new UserServiceImpl();
        return userService;
    }

    return null;
}

一旦该bean由上面的自定义代码段创建,那么下面的[2],[3]就不会被调用了。spring框架这么处理的目的很简单,就是如果开发者需要自己实例化一个业务bean,那么就在这里将初始化的工作一并处理了,无需再其它方法里面去做实例化。如果运行过程中去掉上面的自定义代码段,那么下面的[2]一定会执行。

[2] postProcessAfterInstantiation方法:调用本方法主要是spring创建某个业务bean之后,给开发者一个介入的机会进行自定义的一些业务处理。除此之外,返回值的true和false直接决定了[3]方法是否执行。

[3] postProcessPropertyValues方法:如果[2]中的方法返回的是true,那么本方法就会被调用,开发者可以再此处初始化一些自己的属性。

总的来说,这个接口的几个方法重点归为两组接口:postProcessBeforeInstantiation方法,postProcessAfterInstantiation方法是一组;postProcessBeforeInitialization方法和postProcessAfterInitialization方法是一组。第一组是spring在实例化某个bean之前和实例化某个bean之后,给开发者一个介入的机会,用于做某些自定义的业务处理;第二组是spring在初始化某个bean之前和初始化某个bean之后,给开发者一个介入的机会,用于做某些自定义的业务处理。注意前面的区别,第一组是实例化,第二组是初始化。


2. InstantiationAwareBeanPostProcessor接口的基本使用

第一步:创建一个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 {

    public String ip;

    public String port;

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getPort() {
        return port;
    }

    public void setPort(String port) {
        this.port = port;
    }

    @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);

        System.out.println("ip: " + ip);
        System.out.println("port: " + port);

        return user;
    }

}

第三步:创建一个实现InstantiationAwareBeanPostProcessor接口的实现类如下:

@Component
public class GlobalInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {

        //测试一:开发者自己实例化UserServiceImpl这个bean,不要让spring通过反射的方式创建。
        if(beanClass.equals(UserServiceImpl.class)) {
            UserService userService = new UserServiceImpl();
            System.out.println("address1" + userService);
            return userService;
        }

        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {

        //测试二:spring通过反射的方式创建UserServiceImpl这个bean,然后返回一个true或者false。
        //返回true的意思是告诉spring,需要调用下面的postProcessPropertyValues方法做进一步的处理。
        //返回false的意思是告诉spring,不需要再调用下面的postProcessPropertyValues方法做处理了。
        if(bean instanceof UserServiceImpl) {
            return true;
        }

        return false;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

        //测试二:如果在上面的方法里面返回了true,那么本方法会被调用,开发者可以做一些自定义的业务处理。
        //举例来说:比如说spring服务启动后需要将该服务部署的机器的ip地址和端口注入到某个bean中去,那么
        //就可以用下面的代码段做处理。
        if(bean instanceof UserServiceImpl) {
            MutablePropertyValues mpvs = (MutablePropertyValues) pvs;
            mpvs.addPropertyValue(new PropertyValue("ip", "192.168.1.110"));
            mpvs.addPropertyValue(new PropertyValue("port", "8080"));
        }

        return pvs;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        //在本方法内主要是三种用法:一个是对bean做自定义的一些初始化或者修改的工作;一个是返回一个bean的代理对象;
        // 一个是创建一个全新的bean,替换spring创建的bean。至于哪种用法,完全由开发者自己业务需求决定。
        System.out.println("Execute postProcessBeforeInitialization.");

        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        //再本方法内主要是三种用法:一个是对bean做自定义的一些初始化或者修改的工作;一个是返回一个bean的代理对象;
        // 一个是创建一个全新的bean,替换spring创建的bean。至于哪种用法,完全由开发者自己业务需求决定。
        System.out.println("Execute postProcessAfterInitialization.");

        return bean;
    }
}

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

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

第五步:开始下面的测试。注意:第三步中的测试一和测试二是互斥的,做测试的时候选择测试一需要注释测试二的代码,选择测试二需要注释测试一的代码。

    ClassPathXmlApplicationContext cac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    UserService userService = cac.getBean(UserService.class);
    System.out.println("address2" + userService);

运行上述测试一所对应的测试代码,控制台会打印如下的日志

address1com.minesoft.tutorial.service.UserServiceImpl@3b2cf7ab
address2com.minesoft.tutorial.service.UserServiceImpl@3b2cf7ab

两个相同的内存地址表明postProcessBeforeInstantiation中创建的bean和后面通过getBean方法拿到的就是同一个bean。也就说明了UserServiceImpl这个bean是开发者自己创建的,而不是spring创建的。

    ClassPathXmlApplicationContext cac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    UserService userService = cac.getBean(UserService.class);
    userService.findUserById(100L);

运行上述测试二的所对应的测试代码,控制台会打印如下的日志:

ip: 192.168.1.110
port: 8080

说明UserServiceImpl的ip和port属性都被成功的初始化了。


更多知识请关注公众号

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

评论 抢沙发

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

九零后大叔的技术博客

联系我们联系我们

感谢您的支持

支付宝扫一扫打赏

微信扫一扫打赏