Spring注解驱动开发(二)

注解可以简化配置,提高效率

The Spring Framework provides a comprehensive programming and configuration model for modern Java-based enterprise applications - on any kind of deployment platform.

声明周期@Bean指定初始化和销毁方法

Bean的生命周期

Bean的创建、初始化和销毁是由容器帮我们管理的

我们可以自定义初始化和销毁方法,容器在进行到当前生命周期的时候来调用我买自定义的初始化和销毁方法

构造(对象创建)

​ 单实例: 在容器启动的时候创建

​ 多实例: 在每次获取的时候创建对象

指定初始化方法

初始化:对象创建完成后,并赋值化,调用初始化方法

销毁:单实例是在容器关闭的时候销毁,多实例容器不会管理这个Bean,容器不会调用销毁方法

编写一个Car类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* @Author: cuzz
* @Date: 2018/9/23 21:20
* @Description:
*/
public class Car {

public Car () {
System.out.println("car constructor...");
}

public void init() {
System.out.println("car...init...");
}

public void destroy() {
System.out.println("car...destroy...");
}
}

在xml中我们可以指定init-methoddestroy-method方法,如

1
<bean id="car" class="com.cuzz.bean.Car" init-method="init" destroy-method="destroy"></bean>

使用注解我们可以

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @Author: cuzz
* @Date: 2018/9/24 12:49
* @Description: 配置类
*/
@Configuration
public class MainConfigOfLifecycle {

@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car() {
return new Car();
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* @Author: cuzz
* @Date: 2018/9/24 13:00
* @Description:
*/
public class IOCTestLifeCycle {

@Test
public void test01() {
// 创建ioc容器
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MainConfigOfLifecycle.class);
System.out.println("容器创建完成...");
// 关闭容器
System.out.println("--->开始关闭容器");
applicationContext.close();
System.out.println("--->已经关闭容器");
}
}

可以看出先创建car,再调用init方法,在容器关闭时销毁实例

1
2
3
4
5
6
car constructor...
car...init...
容器创建完成...
--->开始关闭容器
car...destroy...
--->已经关闭容器

在配置数据源的时候,有很多属性赋值,销毁的时候要把连接给断开

生命周期InitializingBean和DisposableBean

InitializingBean

可以通过Bean实现InitializingBean来定义初始化逻辑,是设置好所有属性会调用afterPropertiesSet()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface InitializingBean {

/**
* Invoked by a BeanFactory after it has set all bean properties supplied
* (and satisfied BeanFactoryAware and ApplicationContextAware).
* <p>This method allows the bean instance to perform initialization only
* possible when all bean properties have been set and to throw an
* exception in the event of misconfiguration.
* @throws Exception in the event of misconfiguration (such
* as failure to set an essential property) or if initialization fails.
*/
void afterPropertiesSet() throws Exception;

}

DisposableBean

可以通过Bean实现DisposableBean来定义销毁逻辑,会调用destroy()方法

1
2
3
4
5
6
7
8
9
10
11
public interface DisposableBean {

/**
* Invoked by a BeanFactory on destruction of a singleton.
* @throws Exception in case of shutdown errors.
* Exceptions will get logged but not rethrown to allow
* other beans to release their resources too.
*/
void destroy() throws Exception;

}

例子

编写一个Cat类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* @Author: cuzz
* @Date: 2018/9/24 13:36
* @Description:
*/
public class Cat implements InitializingBean, DisposableBean{

public Cat() {
System.out.println("cat constructor...");
}


@Override
public void afterPropertiesSet() throws Exception {
System.out.println("cat...init...");
}

@Override
public void destroy() throws Exception {
System.out.println("cat...destroy...");
}

}

测试

1
2
3
4
5
6
cat constructor...
cat...init...
容器创建完成...
--->开始关闭容器
cat...destroy...
--->已经关闭容器

生命周期@PostContruct和@PreDestroy注解

@PostContruct在Bean创建完成并且属性赋值完成,来执行初始化

@PreDestroy在容器销毁Bean之前通知我们进行清理工作

编写一个Dog类,并把他注入到配置类中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @Author: cuzz
* @Date: 2018/9/24 14:03
* @Description:
*/
public class Dog {

public Dog() {
System.out.println("dog constructor...");
}

@PostConstruct
public void postConstruct() {
System.out.println("post construct...");
}

@PreDestroy
public void preDestroy() {
System.out.println("pre destroy...");
}
}

测试结果

1
2
3
4
5
6
dog constructor...
post construct...
容器创建完成...
--->开始关闭容器
pre destroy...
--->已经关闭容器

生命周期BeanPostProscessor后置处理器

我们先看看源码,解释的很清楚,BeanPostProscessor 中postProcessBeforeInitialization方法会在每一个bean对象的初始化方法调用之前回调;postProcessAfterInitialization方法会在每个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
/**
* Factory hook that allows for custom modification of new bean instances,
* e.g. checking for marker interfaces or wrapping them with proxies.
*
* <p>ApplicationContexts can autodetect BeanPostProcessor beans in their
* bean definitions and apply them to any beans subsequently created.
* Plain bean factories allow for programmatic registration of post-processors,
* applying to all beans created through this factory.
*
* <p>Typically, post-processors that populate beans via marker interfaces
* or the like will implement {@link #postProcessBeforeInitialization},
* while post-processors that wrap beans with proxies will normally
* implement {@link #postProcessAfterInitialization}.
*/
public interface BeanPostProcessor {

/**
* Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
* The returned bean instance may be a wrapper around the original.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
*/
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

/**
* Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
* The returned bean instance may be a wrapper around the original.
* <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
* instance and the objects created by the FactoryBean (as of Spring 2.0). The
* post-processor can decide whether to apply to either the FactoryBean or created
* objects or both through corresponding {@code bean instanceof FactoryBean} checks.
* <p>This callback will also be invoked after a short-circuiting triggered by a
* {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
* in contrast to all other BeanPostProcessor callbacks.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
* @see org.springframework.beans.factory.FactoryBean
*/
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

编写一个MyBeanPostProcessor实现BeanPostProcessor接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @Author: cuzz
* @Date: 2018/9/24 14:21
* @Description: 后置处理器,初始化前后进行处理工作
*/
public class MyBeanPostProcessor implements BeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("--->postProcessBeforeInitialization..." + beanName +"==>" + bean);
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("--->postProcessAfterInitialization..." + beanName +"==>" + bean);
return bean;
}
}

添加到配置中

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class MainConfigOfLifecycle {

@Bean
public Cat cat() {
return new Cat();
}

@Bean
public MyBeanPostProcessor myBeanPostProcessor() {
return new MyBeanPostProcessor();
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
--->postProcessBeforeInitialization...org.springframework.context.event.internalEventListenerProcessor==>org.springframework.context.event.EventListenerMethodProcessor@1dc67c2
--->postProcessAfterInitialization...org.springframework.context.event.internalEventListenerProcessor==>org.springframework.context.event.EventListenerMethodProcessor@1dc67c2
--->postProcessBeforeInitialization...org.springframework.context.event.internalEventListenerFactory==>org.springframework.context.event.DefaultEventListenerFactory@2bd765
--->postProcessAfterInitialization...org.springframework.context.event.internalEventListenerFactory==>org.springframework.context.event.DefaultEventListenerFactory@2bd765
cat constructor...
--->postProcessBeforeInitialization...cat==>com.cuzz.bean.Cat@1d3b207
cat...init...
--->postProcessAfterInitialization...cat==>com.cuzz.bean.Cat@1d3b207
容器创建完成...
--->开始关闭容器
cat...destroy...
--->已经关闭容器

在实例创建之前后创建之后会被执行

生命周期BeanPostProcessor原理

通过debug到populateBean,先给属性赋值在执行initializeBean方法

1
2
3
4
5
6
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}

initializeBean方法时,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {


Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 执行before方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
...
try {
// 执行初始化
invokeInitMethods(beanName, wrappedBean, mbd);
}

if (mbd == null || !mbd.isSynthetic()) {
// 执行after方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

Spring底层对BeanPostProcessor的使用

Bean赋值、注入其他组件、@Autowired、生命周期注解功能、@Async等等都使用到了BeanPostProcessor这个接口的实现类,很重要

总结

Bean 的初始化顺序

  1. 首先执行 bean 的构造方法
  2. BeanPostProcessor 的 postProcessBeforeInitialization 方法
  3. InitializingBean 的 afterPropertiesSet 方法
  4. @Bean 注解的 initMethod方法
  5. BeanPostProcesso r的 postProcessAfterInitialization 方法
  6. DisposableBean 的 destroy 方法
  7. @Bean注解的 destroyMethod 方法
-------------本文结束感谢您的阅读-------------

本文标题:Spring注解驱动开发(二)

文章作者:cuzz

发布时间:2018年09月24日 - 23:09

最后更新:2019年07月16日 - 19:07

原始链接:http://blog.cuzz.site/2018/09/24/Spring注解驱动开发(二)/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

请博主吃包辣条
0%