Bean的生命周期

前言

讲解Bean的生命周期之前,要先了解一下IOC的基础原理。重点在Refresh方法。可以查看这个博客。我觉得写的很详细了。

我再对其做一个Bean的生命周期的补充

生命周期

  1. 构造函数
  2. 参数的注入,依赖注入
  3. 调用实现*Aware的接口的方法,顺序依次是:BeanNameAware、BeanFactoryAware、ApplicationContextAware
  4. 调用实现BeanPostProcessor接口的初始化方法
  5. 调用bean的初始化方法,initMethod(注解@PostConstruct)
  6. 调用接口InitializingBean的afterPropertiesSet方法
  7. 调用BeanPostProcessor的初始化之后的方法
  8. Bean的销毁

基本就这些步骤

网上还有更多的详细步骤,有兴趣的可以自己去了解一哈,我有时间也会在总结一下

在我们使用Bean的时候。如果对Bean进行增强扩展。其实这些就已经足够。还有很多Bean的生命周期的调用Spring自己在处理的过程中的内部使用,不推荐我们去继承或者实现使用

实际使用

其实在正常的情况第一步和第二步感觉已经足够,为什么还有后面这么多步骤?其实全部都是为了Bean的增强处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
@Component
@Setter
@Getter
@ToString
@Slf4j
public class BeanDemo implements BeanNameAware, BeanFactoryAware, ApplicationContextAware , InitializingBean {

private BeanDemo2 beanDemo2;

@Autowired
public void setBeanDemo2(BeanDemo2 beanDemo2) {
this.beanDemo2 = beanDemo2;
log.warn("BeanDemo 的注入!");
}

private String name = "name";

private String age = "age";


static {
log.warn("BeanDemo的静态方法");
}

{
log.warn("BeanDemo的构造方法");
}

public BeanDemo() {
log.warn("BeanDemo的无参构造函数");
}


@Override
public void setBeanName(String name) {
this.name = name;
log.warn("调用 BeanNameAware 方法,name={}",name);
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.warn("调用 BeanFactoryAware 方法,beanFactory={}",beanFactory);
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
beanDemo2 = null;
log.warn("调用 ApplicationContextAware 方法,注入ApplicationContext ");
}

@Override
public void afterPropertiesSet() throws Exception {
log.warn("调用 afterPropertiesSet 方法");
}

@PostConstruct
public void initMethod(){
log.warn("调用 initMethod 初始化方法 ");
}

@PreDestroy
public void destroyMethod(){
log.warn("调用 destroyMethod 销毁方法 ");
}
}
@Component
@Slf4j
public class MyBeanPostProcessor implements BeanPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof BeanDemo){
log.warn("调用BeanPostProcessor 的初始化之前方法,Bean={}",bean.toString());
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof BeanDemo) {
log.warn("调用BeanPostProcessor 的初始化之后方法,Bean={}", bean.toString());
}
return bean;
}
}

这是一个普通的Bean。当我们创建这个Bean的时候日志打印

1
2
3
4
5
6
7
8
9
10
11
WARN 7428 --- [           main] com.duteliang.webbase.bean.BeanDemo      : BeanDemo的静态方法
WARN 7428 --- [ main] com.duteliang.webbase.bean.BeanDemo : BeanDemo的构造方法
WARN 7428 --- [ main] com.duteliang.webbase.bean.BeanDemo : BeanDemo的无参构造函数
WARN 7428 --- [ main] com.duteliang.webbase.bean.BeanDemo : BeanDemo 的注入!
WARN 7428 --- [ main] com.duteliang.webbase.bean.BeanDemo : 调用 BeanNameAware 方法,name=beanDemo
WARN 7428 --- [ main] com.duteliang.webbase.bean.BeanDemo : 调用 BeanFactoryAware 方法
WARN 7428 --- [ main] com.duteliang.webbase.bean.BeanDemo : 调用 ApplicationContextAware 方法,注入ApplicationContext
WARN 7428 --- [ main] c.d.webbase.bean.MyBeanPostProcessor : 调用 BeanPostProcessor 的初始化之前方法,Bean=BeanDemo(beanDemo2=null, name=beanDemo, age=age)
WARN 7428 --- [ main] com.duteliang.webbase.bean.BeanDemo : 调用 initMethod 初始化方法
WARN 7428 --- [ main] com.duteliang.webbase.bean.BeanDemo : 调用 afterPropertiesSet 方法
WARN 7428 --- [ main] c.d.webbase.bean.MyBeanPostProcessor : 调用 BeanPostProcessor 的初始化之后方法,Bean=BeanDemo(beanDemo2=null, name=beanDemo, age=age)

Aware接口

Aware用的并不多,我再工作中并没有发现使用的时候。有使用场景的时候在补充吧

BeanPostProcessor 接口

BeanPostProcessor就是一个比较实用的东西
你可以拿它去修改一些框架的Bean,如果Bean有时候并不如满足你的要求,但是你又不想去重写他整个部分只为修改一小部分(尤其是一些框架内部的bean)。你就可以使用它来对Bean进行增强处理
你可以拿它去对你的Bean添加代理,对Bean做一些监控。

初始化方法 @PostConstruct

也比较实用,你可以在启动的时候对你的Bean做一些资源处理。可以在此加入你的逻辑

afterPropertiesSet

这个倒是用的不多,可以去检验Bean的参数?

FactoryBean的使用

这里稍微讲解一下FactoryBean的部分

FactoryBean顾名思义其实就是一个Bean。可以理解为一个特殊的Bean。注意别把他和BeanFactory搞混了就行

直接看看这货的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component // 可以不写该注解,直接在xml中配置
public class MyFactoryBean implements FactoryBean<MyBean> {
@Override
public MyBean getObject() throws Exception {
// 加入你的复杂的逻辑判断
return new MyBean();
}

@Override
public Class<MyBean> getObjectType() {
return MyBean.class;
}
}

上面就是FactoryBean的使用,可以理解为他相当于实际Bean的代理类。

这货有什么实际用处了?本人在开发中,其实主要在XMl时代是个神器可以解决很多普通xml无法解决的问题。

举个例子:比如我在实际开发中,redis,mongodb的连接。尤其环境的不一致,公司开发由于机器不够可能用的单机。云上生产环境肯定是用了副本集或者分片。在连接代码肯定是不一样的。xml很难去解决这个问题(当然你在xml中开启注解扫描,直接使用@Configuration也可以,为了统一性。有时候不会做)。

这时候FactoryBean的作用就来了。你可以在XMl中配置FactoryBean。在其代码中直接通过对配置的参数自动选择使用单机或者副本集或者分片等等。

不过现在新项目采用SpringBoot以后xml基本被抛弃,使用代码创建Bean本身灵活性就很大,这种问题也不存在。后面倒是没怎么用过了。