InitializingBean是一个接口,它定义了一个afterPropertiesSet方法
public interface InitializingBean {
/**
* Invoked by the containing {@code BeanFactory} after it has set all bean properties
* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
* This method allows the bean instance to perform validation of its overall
* configuration and final initialization when all bean properties have been set.
* @throws Exception in the event of misconfiguration (such as failure to set an
* essential property) or if initialization fails for any other reason
*/
void afterPropertiesSet() throws Exception;
}
init-method,一般我们在bean中会定义相关的初始化方法,希望spring容器初始bean时,调用我们定义的初始化方法,而这个方法我们一般会通过在xml配置bean时通过init-method标签来指定对应的初始化方法,或者是现在流行的注解式开发,通过@Bean(initMethod=“xxx”)指定对应的初始化方法。
@Configuration
public class MainConfigOfLifeCycle {
@Bean(initMethod="init")
public Car car(){
return new Car();
}
}
继续通过AbstractAutowireCapableBeanFactory中初始化bean的源码中,了解一下InitializingBean和init-method的作用执行时机。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
//调用调用此方法进行部分Aware接口的回调
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//调用后置处理器的前置方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//调用初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//调用后置处理器的后置方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
可以看到在bean的初始化过程中,执行完Aware扩展和BeanPostProcessor扩展的前置处理后,调用了初始化方法invokeInitMethods
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
//如果当前bean实现了InitializingBean
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//直接调用afterPropertiesSet
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
//获取bean的初始化方法,也就init-method指定的方法
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//使用反射机制调用init-method指定的方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
可以看到这个方法里面,首先是判断当前bean时候实现了InitializingBean接口,是的话,调用其afterPropertiesSet方法,接着获取该bean init-method指定的初始化方法,然后通过反射的方式调用指定的初始化方法。因此我们可以总结InitializingBean和init-method的作用其实就是在bean初始化的时候,可以调用自定义的初始化方法,对bean进行额外的初始化扩展。
通过上面的分析,InitializingBean和init-method可以说是具有一样的作用,那它们之间的区别是什么呢,可以看到InitializingBean是一个接口,想要使用它的bean必须继承它,因此,使用InitializingBean是对bean具有侵入性的。而使用init-method,使我们通过标签或者注解的方式去指定,这样的方式是没有侵入性。但是由于前面分析init-method是通过反射的方式去调用初始化方法,因此相对于InitializingBean来说性能会比较差。一般情况下,我们更倾向使用没有侵入性的方式,也就是init-method来做初始化方法。
实现InitializingBean接口中的afterPropertiesSet方法。
@Component
public class Cat implements InitializingBean,DisposableBean {
public Cat(){
System.out.println("cat constructor...");
}
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat...destroy...");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat...afterPropertiesSet...");
}
}
定义了init方法
public class Car {
public Car(){
System.out.println("car constructor...");
}
public void init(){
System.out.println("car ... init...");
}
public void detory(){
System.out.println("car ... detory...");
}
}
1,@ComponentScan配置扫描将Cat由spring容器管理
2,@Bean(initMethod=“init”,destroyMethod=“detory”)配置bean Car并指定初始化方法为init
@ComponentScan("spring.annotation.pobean.lifecycle")
@Configuration
public class MainConfigOfLifeCycle {
@Bean(initMethod="init",destroyMethod="detory")
public Car car(){
return new Car();
}
}
编写单元测试,创建容器
public class IOCTest_LifeCycle {
@Test
public void test01(){
//1、创建ioc容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成...");
//关闭容器
applicationContext.close();
}
}