(造轮子)手写Spring框架-Bean的初始化和销毁方法

133 阅读2分钟

Bean的初始化和销毁方法

代码地址:WangChao-ly/chao-spring at init-and-destroy-method (github.com)

建议订阅博主专栏,从下到上系统手写spring源码,体会其中过程!

在spring中,定义bean的初始化和销毁方法有三种方法:

  • 在xml文件中制定init-method和destroy-method
  • 继承自InitializingBean和DisposableBean
  • 在方法上加注解PostConstruct和PreDestroy

第三种通过BeanPostProcessor实现,在扩展篇中实现,本节只实现前两种。

针对第一种在xml文件中指定初始化和销毁方法的方式,在BeanDefinition中增加属性initMethodName和destroyMethodName。

初始化方法在AbstractAutowireCapableBeanFactory#invokeInitMethods执行。DefaultSingletonBeanRegistry中增加属性disposableBeans保存拥有销毁方法的bean,拥有销毁方法的bean在AbstractAutowireCapableBeanFactory#registerDisposableBeanIfNecessary中注册到disposableBeans中。

为了确保销毁方法在虚拟机关闭之前执行,向虚拟机中注册一个钩子方法,查看AbstractApplicationContext#registerShutdownHook(非web应用需要手动调用该方法)。当然也可以手动调用ApplicationContext#close方法关闭容器。

到此为止,bean的生命周期如下:

image.png

初始化部分

  1. 通过xml加载初始化方法和销毁方法,在BeanDefinition中新增initMethodName和destroyMethodName,读取xml文件时候,获取这两个值,并且通过set方法注入到BeanDefinition中,这里代表着BeanDefinition处理完毕,下面是获取Bean时候处理的问题。
protected void doLoadBeanDefinitions(InputStream inputStream){
    Document document = XmlUtil.readXML(inputStream);
    Element root = document.getDocumentElement();
    NodeList childNodes = root.getChildNodes();
    for(int i=0;i<childNodes.getLength();i++){
        if(childNodes.item(i) instanceof Element){
            if(BEAN_ELEMENT.equals(((Element)childNodes.item(i)).getNodeName())){
                Element bean = (Element)childNodes.item(i);
                String id = bean.getAttribute(ID_ATTRIBUTE);
                String name = bean.getAttribute(NAME_ATTRIBUTE);
                String className = bean.getAttribute(CLASS_ATTRIBUTE);
                String initMethodName = bean.getAttribute(INIT_METHOD_ATTRIBUTE);
                String destroyMethodName = bean.getAttribute(DESTROY_METHOD_ATTRIBUTE);

                Class<?> clazz = null;
                try{
                    clazz = Class.forName(className);
                } catch (ClassNotFoundException e) {
                    throw new BeansException("Cannot find class [" + className + "]");
                }
                //id优于name
                String beanName = StrUtil.isNotEmpty(id)?id:name;
                if(StrUtil.isEmpty(beanName)){
                    //如果id和name都为空,将类名的第一个字母转为小写后作为bean的名称
                    beanName = StrUtil.lowerFirst(clazz.getSimpleName());
                }

                BeanDefinition beanDefinition = new BeanDefinition(clazz,new PropertyValues());
                //设置初始和结束方法名
                beanDefinition.setInitMethodName(initMethodName);
                beanDefinition.setDestroyMethodName(destroyMethodName);

                for(int j=0;j<bean.getChildNodes().getLength();j++){
                    if(bean.getChildNodes().item(j) instanceof Element){
                        if(PROPERTY_ELEMENT.equals(((Element)bean.getChildNodes().item(j)).getNodeName())){
                            //解析property标签
                            Element property = (Element) bean.getChildNodes().item(j);
                            String nameAttribute = property.getAttribute(NAME_ATTRIBUTE);
                            String valueAttribute = property.getAttribute(VALUE_ATTRIBUTE);
                            String refAttribute = property.getAttribute(REF_ATTRIBUTE);

                            if(StrUtil.isEmpty(nameAttribute)){
                                throw new BeansException("The name attribute cannot be null or empty");
                            }

                            Object value = valueAttribute;
                            if(StrUtil.isNotEmpty(refAttribute)){
                                value = new BeanReference(refAttribute);
                            }
                            PropertyValue propertyValue = new PropertyValue(nameAttribute, value);
                            beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
                        }
                    }
                }
                if(getRegistry().containsBeanDefinition(beanName)){
                    //beanName不能重名
                    throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
                }
                //注册BeanDefinition
                getRegistry().registerBeanDefinition(beanName,beanDefinition);
            }
        }
    }
}
  1. 新建两个接口,一个是InitializingBean另一个是DisposableBean,实现了这两个接口的类,被标识为有初始化方法和有销毁方法的类,在我们进行createBean的时候会被用到。
  2. 在执行bean的初始化方法时,我们通过判断bean类型是不是InitializingBean来调用其定义的方法,然后通过在读取xml文件注入的initMethodName方法名,通过反射找到该方法,然后调用执行。
/**
 * 执行bean的初始化方法
 * @param beanName
 * @param bean
 * @param beanDefinition
 * @throws Throwable
 */
protected void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
    if(bean instanceof InitializingBean){
        ((InitializingBean) bean).afterPropertiesSet();
    }
    String initMethodName = beanDefinition.getInitMethodName();
    if(StrUtil.isNotEmpty(initMethodName)){
        //获取beanDefinition类中的initMethodName方法
        Method initMethod = ClassUtil.getPublicMethod(beanDefinition.getBeanClass(), initMethodName);
        if(initMethod == null){
            throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
        }
        //执行初始化方法
        initMethod.invoke(bean);
    }
}
  1. 注册有销毁方法的bean,即bean继承自DisposableBean或有自定义的销毁方法,将这些元素注册到一个特殊的map中,到时候销毁时候,针对该map中的bean进行销毁操作。
protected void registerDisposableBeanIfNecessary(String beanName,Object bean,BeanDefinition beanDefinition){
    if(bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())){
        registerDisposableBean(beanName,new DisposableBeanAdapter(bean,beanName,beanDefinition));
    }
}

其中DisposableBeanAdapter类是DisposableBean接口的具体实现类,用来注册到map中,然后提供具体的销毁方法。

private Map<String, Object> singletonObjects = new HashMap<>();

public void registerDisposableBean(String beanName,DisposableBean bean){
    disposableBeans.put(beanName,bean);
}

销毁部分

  1. 在AbstractApplicationContext类中定义一个钩子,用来容器销毁时,自动释放销毁bean,然后提供close方法用来手动释放。
@Override
public void close(){
    doClose();
}

protected void doClose(){
    destroyBeans();
}

/**
 * 调用容器中销毁bean的方法
 */
protected void destroyBeans(){
    getBeanFactory().destroySingletons();
}

@Override
public void registerShutdownHook(){
    Thread shutDownHook = new Thread(){
        @Override
        public void run() {
            doClose();
        }
    };
    Runtime.getRuntime().addShutdownHook(shutDownHook);
}
  1. ConfigurableListableBeanFactory接口继承了ConfigurableBeanFactory接口,我们在ConfigurableBeanFactory接口中定义void destroySingletons()方法,提供给上一步进行调用,具体的实现类在DefaultSingletonBeanRegistry中,该类负责单例bean的注册和销毁工作。
public void destroySingletons(){
    ArrayList<String> beanNames = new ArrayList<>(disposableBeans.keySet());
    for(String beanName:beanNames){
        DisposableBean disposableBean = disposableBeans.remove(beanName);
        try{
            disposableBean.destroy();
        }catch (Exception e) {
            throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
        }
    }
}

总结:

初始化:就是在创建时候,将初始化方法和销毁方法名set到BeanDefinition中,然后在执行bean的初始化方法,调用afterPropertiesSet和自定义的初始化方法,再将提供了销毁功能的类加入到Map中。

销毁:就是将加入到销毁的map中的元素全部移除,然后调用它的destroy方法。