面试了才知道初始化Bean不仅只有new那么简单

2023-03-07 09:30:47 浏览数 (1)

闲聊

哈喽,大家好,我是Java小面。前面我们讲了面试时实例化Bean的几种方法《以后面试别再说你只会用@Autowired实例化Bean了》,那么对应不可或缺的还有初始化Bean,接下来我们会讨论它的下一步操作Bean的初始化。

以下是我罗列的三种方式

Bean初始化(Initialization)

  1. @PostConstruct 标注方法
  2. 实现InitializatingBean接口的afterPropertiesSet()方法
  3. 自定义初始化方法
    1. xml配置
    2. Java API
    3. Java注解

学习新知识,我们要抱着问题去学习。

这三种方式都可以共存且不会冲突,那么问题来了,如果三种方式都存在,它们的执行顺序又会是怎样的?

@PostConstruct 标注方法

所有我们来讲解一下如果使用@PostConstruct 标注方法来初始化Bean

一、首先我们先创建一个初始化对象

代码语言:javascript复制
/**
 * @author Java面试教程
 * @date 2022-11-22 21:37
 */
public interface UserFactory {
    
}

/**
 * @author Java面试教程
 * @date 2022-11-22 21:37
 */
public class DefaultUserFactory implements UserFactory{

    //基于@PostConstruct注解
    @PostConstruct
    public void init(){
        System.out.println("DefaultUserFactory 初始化中...");
    }

}

二、把UserFactroy注册为bean

代码语言:javascript复制
@Configuration
public class Demo {

    @Bean
    public UserFactory createUserFactory(){
        return new DefaultUserFactory();
    }

}

这里使用@Configuration是为了初始化的时候使用applicationContext.register(Demo.class),让程序把@Bean扫描到然后把Bean注册进去。

三、初始化Bean

代码语言:javascript复制
@Configuration
public class Demo {
    public static void main(String[] args)
    {
        //创建BeanFactory容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        
        //注册当前类,主要目的是获取@Bean
        applicationContext.register(Demo.class);
        
        //启动应用上下文
        applicationContext.refresh();

        //依赖查找
        UserFactory bean = applicationContext.getBean(UserFactory.class);

        //关闭应用上下文
        applicationContext.close();

    }

    @Bean
    public UserFactory createUserFactory(){
        return new DefaultUserFactory();
    }

}

运行的是@PostConstruct这个方法会被自动回调,打印出我们设置好的内容。

代码语言:javascript复制
Connected to the target VM, address: '127.0.0.1:52103', transport: 'socket'
DefaultUserFactory 初始化中...
Disconnected from the target VM, address: '127.0.0.1:52103', transport: 'socket'

自定义初始化

为了区分不同的初始化,我们这里定义一个方法来执行

代码语言:javascript复制
public interface UserFactory {

    void initUserFactory();

}

/**
 * @author Java面试教程
 * @date 2022-11-22 21:37
 */
public class DefaultUserFactory implements UserFactory{

    //基于@PostConstruct注解
    @PostConstruct
    public void init(){
        System.out.println("DefaultUserFactory 初始化中...");
    }
    
    public void initUserFactory(){
        System.out.println("自定义初始化方法 initUserFactory()...");
    }
    

}

这里我们自定义一个initUserFactory方法,然后把方法名放到@Bean注解中。

代码语言:javascript复制
@Configuration
public class Demo {
    public static void main(String[] args)
    {
        //创建BeanFactory容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        //注册当前类,主要目的是获取@Bean
        applicationContext.register(Demo.class);
        
        //启动应用上下文
        applicationContext.refresh();

        //依赖查找
        UserFactory bean = applicationContext.getBean(UserFactory.class);

        //关闭应用上下文
        applicationContext.close();

    }

    @Bean(initMethod = "initUserFactory")
    public UserFactory createUserFactory(){
        return new DefaultUserFactory();
    }

}

这样就会打印出来两个初始化方法的内容

代码语言:javascript复制
Connected to the target VM, address: '127.0.0.1:53619', transport: 'socket'
DefaultUserFactory 初始化中...
自定义初始化方法 initUserFactory()...
Disconnected from the target VM, address: '127.0.0.1:53619', transport: 'socket'

实现InitializatingBean接口的afterPropertiesSet()方法

我们要去实现Spring它自己的一个接口,通过覆盖InitializatingBean接口的afterPropertiesSet方法。

代码语言:javascript复制
public class DefaultUserFactory implements UserFactory, InitializingBean {

    //基于@PostConstruct注解
    @PostConstruct
    public void init(){
        System.out.println("DefaultUserFactory 初始化中...");
    }

    public void initUserFactory(){
        System.out.println("自定义初始化方法 initUserFactory()...");
    }

    @Override
    public void afterPropertiesSet() throws Exception
    {
        System.out.println("InitializingBean的afterPropertiesSety()...");
    }
}

运行后发现,三种方式共存且存在一定顺序

代码语言:javascript复制
Connected to the target VM, address: '127.0.0.1:54298', transport: 'socket'
DefaultUserFactory 初始化中...
InitializingBean的afterPropertiesSety()...
自定义初始化方法 initUserFactory()...
Disconnected from the target VM, address: '127.0.0.1:54298', transport: 'socket'

它们的优先级:@PostConstruct注解 > 实现InitializatingBean接口的afterPropertiesSet()方法 > 自定义方法初始化

它们的顺序在任何spring版本都不会变化的。

结束语

关于Bean的实例化和初始化,现在业务开发中或许已经用不到了,但是如果你的目标是深耕于Java领域的话,那么以后难免涉及框架的二次开发,那么Bean的实例化和初始化就有必要提前的好好了解一下。

0 人点赞