闲聊
哈喽,大家好,我是Java小面。前面我们讲了面试时实例化Bean的几种方法《以后面试别再说你只会用@Autowired实例化Bean了》,那么对应不可或缺的还有初始化Bean,接下来我们会讨论它的下一步操作Bean的初始化。
以下是我罗列的三种方式
Bean初始化(Initialization)
- @PostConstruct 标注方法
- 实现InitializatingBean接口的afterPropertiesSet()方法
- 自定义初始化方法
- xml配置
- Java API
- 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的实例化和初始化就有必要提前的好好了解一下。