写在之前
最近没事在浏览Spring官网,简单写一些相关的笔记,这篇文章整理Spring自定义Bean。并不包所有技术点,只是记录有收获的内容,例如从背景知识了解到SpringFramework5.1开始,Spring需要JDK8+,并为JDK11LTS提供开箱即用的支持
Spring框架提供了许多接口,可以用来定制bean的性质
1.自定义Bean行为
从Spring2.5开始,您有三种控制bean生命周期行为的选项:
- InitializingBean和DisposableBean回调接口
- 自定义init和destroy方法
- @PostConstruct和@PreDestroy注释
1.1Bean初始化回调
Spring的 InitalizingBean接口允许bean在容器设置了bean的所有必要属性后执行执行初始化工作,InitalizingBean接口仅有一个afterPropertiesSet方法,在Spring初始化后,执行完所有属性设置方法(setXxx)后将调用afterPropertiesSet
package org.springframework.beans.factory;
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
例如
ExampleBean继承了接口InitalizingBean,并可在afterPropertiesSet方法中自定义一些特殊处理,XML中并不需要做特殊配置
public class InitExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
// do some initialization work
}
}
<bean id="initExampleBean" class="examples.InitExampleBean"/>
Spring虽然可以通过InitializingBean完成一个bean初始化后对这个bean的回调,但是这种方式要求bean实现Spring提供的 InitializingBean接口。这个bean的代码就和Spring耦合到一起了。通常情况下不鼓励bean直接实现InitializingBean,可以使用Spring提供的init-method的功能来执行一个bean 子定义的初始化方法。
public class ExampleBean {
public void init() {
// do some initialization work
}
}
<!-- init-method 设置初始化方法-->
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
Spring 可以通过注解@PostConstruct来声明初始化方法,@PostConstruct只能修饰一个非惊呆他的void方法
public class CachingMovieLister {
@PostConstruct
public void init() {
//do something
}
}
注意: 如果InitializingBean和init-method可以一起使用,Spring会先处理InitializingBean再处理init-method。
1.2Bean销毁回调
Spring的 DisposableBean接口允许bean在容器中销毁时回调,DisposableBean接口仅有一个destory方法,该方法在BeanFactory在销毁单例时调用,此接口的异常只会被记录在日志中不会抛出,保证其他bean可以释放它们的资源
package org.springframework.beans.factory;
public interface DisposableBean {
void destroy() throws Exception;
}
和 InitializingBean相似, 并不建议使用继承DisposableBean接口实现销毁时的自定义操作。 因为它会将Bean的代码和Spring代码耦合在一起,建议使用destroy-method属性,例如
public class ExampleBean {
public void cleanup() {
// do some destruction work
}
}
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
Spring 可以通过注解@PreDestroy来声明销毁方法,@PreDestroy只能修饰一个非惊呆他的void方法
public class CachingMovieLister {
@PreDestroy
public void clearMovieCache() {
// do some clear
}
}
这样,destroy-method和@PreDestroy不会将Bean代码和Spring代码耦合在一起
1.3默认初始化和销毁方法
初始化和销毁方法回调时,您通常使用init()、initialize()、dispose()等名称编写方法。一般情况下方法的名称在整个项目中都是标准化的,开发人员使用相同的方法名称并确保一致性。这样就可以设置默认的初始化或者销毁方法
public class DefaultBlogService implements BlogService {
private BlogDao blogDao;
public void setBlogDao(BlogDao blogDao) {
this.blogDao = blogDao;
}
public void init() {
if (this.blogDao == null) {
throw new IllegalStateException("The [blogDao] property must be set.");
}
}
}
配置顶层<beans>元素属性上存在默认的init-method属性,Spring IoC容器将bean类上名为init的方法识别为初始化方法回调。在创建和组装bean时,如果bean类有这样的方法,则会在适当的时候调用它
<beans default-init-method="init">
<bean id="blogService" class="com.something.DefaultBlogService">
<property name="blogDao" ref="blogDao" />
</bean>
</beans>
bean类已经具有与约定不同的回调方法,则可以通过使用<bean>本身的init-method="init"方法来覆盖默认方法
2.执行顺序
如果为一个bean配置了多个生命周期机制,并且每个机制都配置了不同的方法名,那么每个配置的方法都会按照本说明后面列出的顺序运行
2.1初始化Bean方法先后顺序
- @PostConstruct注释的方法
- InitializingBean回调接口定义的afterPropertiesSet()
- 自定义配置的init()方法
2.2销毁Bean方法先后顺序
- @PreDestroy注释的方法
- destroy(),由DisposableBean回调接口定义
- 自定义配置的destroy()方法