初始化Bean

廖雪峰
资深软件开发工程师,业余马拉松选手。

在创建Bean实例的过程中,我们已经完成了强依赖的注入。下一步,是根据Setter方法和字段完成弱依赖注入,接着调用用@PostConstruct标注的init方法,就完成了所有Bean的初始化。

这一步相对比较简单,因为只涉及到查找依赖的@Value@Autowired,然后用反射完成调用即可:

public AnnotationConfigApplicationContext(Class<?> configClass, PropertyResolver propertyResolver) {
    ...

    // 通过字段和set方法注入依赖:
    this.beans.values().forEach(def -> {
        injectBean(def);
    });

    // 调用init方法:
    this.beans.values().forEach(def -> {
        initBean(def);
    });
}

使用Setter方法和字段注入时,要注意一点,就是不仅要在当前类查找,还要在父类查找,因为有些@Autowired写在父类,所有子类都可使用,这样更方便。注入弱依赖代码如下:

// 在当前类及父类进行字段和方法注入:
void injectProperties(BeanDefinition def, Class<?> clazz, Object bean) {
    // 在当前类查找Field和Method并注入:
    for (Field f : clazz.getDeclaredFields()) {
        tryInjectProperties(def, clazz, bean, f);
    }
    for (Method m : clazz.getDeclaredMethods()) {
        tryInjectProperties(def, clazz, bean, m);
    }
    // 在父类查找Field和Method并注入:
    Class<?> superClazz = clazz.getSuperclass();
    if (superClazz != null) {
        // 递归调用:
        injectProperties(def, superClazz, bean);
    }
}

// 注入单个属性
void tryInjectProperties(BeanDefinition def, Class<?> clazz, Object bean, AccessibleObject acc) {
    ...
}

弱依赖注入完成后,再循环一遍所有的BeanDefinition,对其调用init方法,完成最后一步初始化:

void initBean(BeanDefinition def) {
    // 调用init方法:
    callMethod(def.getInstance(), def.getInitMethod(), def.getInitMethodName());
}

处理@PreDestroy方法更简单,在ApplicationContext关闭时遍历所有Bean,调用destroy方法即可。

可以从GitHubGitee下载源码。

GitHub



Comments

Loading comments...