玖叶教程网

前端编程开发入门

Spring扩展接口InitializingBean和DisposableBean

在Spring中有两个扩展接口InitializingBean和DisposableBean。在开发时也算是经常使用的。这里我们依次来学习一下。

InitializingBean

InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法。

那么你可能会想,如果给实现了该接口的类中定义一个init-method方法,会怎么样呢?这里我们写个例子来看一下:

public class CustomService implements InitializingBean {
    
    @Override    
   public void afterPropertiesSet() throws Exception {
        System.out.println("CustomService afterPropertiesSet................");
    }

    public void initMethod(){
        System.out.println("initMethod==============");
    }

}
@Bean(initMethod = "initMethod")
public CustomService customService(){
    return new CustomService();
}

当我们启动项目时,会依次打印:

CustomService afterPropertiesSet................

initMethod==============

由结果可看出,在spring初始化bean的时候,如果该bean是实现了InitializingBean接口,

并且同时指定了init-method,系统则是先调用afterPropertiesSet方法,然后在调用init-method中指定的方法。

源码分析

这里查看一下源码,执行入口是在AbstractApplicationContext类的refresh()方法中的finishBeanFactoryInitialization()方法,里面会调用getBean(),然后getBean()又会调用doCreateBean(),这中间的调用过程这里不多说,大家可以跟踪一下代码看一下。我们直接看doCreateBean()方法,在AbstractAutowireCapableBeanFactory类中:

在这里会调用一个initializeBean()方法,我们看下该方法:

在它里面又会调用invokeInitMethods()方法,我们点开看一下:

//这里的beanName主要用于debug模式方便调试
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
      throws Throwable {

   boolean isInitializingBean = (bean instanceof InitializingBean);
   //判断该bean如果实现了InitializingBean接口,则直接调用bean实现的afterPropertiesSet()方法
   if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
      if (logger.isDebugEnabled()) {
         logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
      }
      if (System.getSecurityManager() != null) {
         try {
            AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
               @Override               
                public Object run() throws Exception {
                  ((InitializingBean) bean).afterPropertiesSet();
                  return null;
               }
            }, getAccessControlContext());
         }
         catch (PrivilegedActionException pae) {
            throw pae.getException();
         }
      }
      else {
         //直接调用afterPropertiesSet
         ((InitializingBean) bean).afterPropertiesSet();
      }
   }

   if (mbd != null) {
      String initMethodName = mbd.getInitMethodName();
     //判断是否指定了init-method方法,如果指定了init-method方法,则再调用指定的init-method
      if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
        //进一步查看该方法的源码,可以发现init-method方法中指定的方法是通过反射实现
         invokeCustomInitMethod(beanName, bean, mbd);
      }
   }
}

从源码看出,执行完afterPropertiesSet()方法后,又会判断如果指定了init-method方法,就接着执行init-method()方法,我们看下invokeCustomInitMethod()方法里的执行过程:

从源码中可以看出,是通过反射来执行init-method的。


DisposableBean

DisposableBean接口为bean销毁时提供了方法,可以在bean销毁前做一些处理。

使用和InitializingBean接口很相似,先看一个示例代码:

public class CustomService implements DisposableBean {
    @Override    
    public void destroy() throws Exception {
        System.out.println("CustomService destroy..................");
    }

   public void destroyMethod(){
        System.out.println("destoryMethod=============");
    }
}
@Bean(destroyMethod = "destroyMethod")
public CustomService customService(){
    return new CustomService();
}

当bean消耗时,打印如下:

CustomService destroy..................

destoryMethod=============


源码分析

关于DisposableBean接口的源码,我们也可以大致看一下,在AbstractApplicationContext类的doClose()方法中,会调用destroyBeans()方法,我们追踪下来发现执行到了DefaultSingletonBeanRegistry类的destroySingletons()方法:


继续执行,在destroySingleton()方法里面会获取DisposableBean类型的bean:

然后调用destroyBean()方法,在这里面就会执行DisposableBean实现类的destroy方法了:



总结

1、spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中同过init-method指定,两种方式可以同时使用(也可以使用注解@Bean中的initMethod参数来指定)。

2、实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率相对来说要高点。但是init-method方式消除了对spring的依赖。

3、如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言