1. 程式人生 > >深入研究Spring-IoC:原始碼分析依賴注入

深入研究Spring-IoC:原始碼分析依賴注入

1.前言

對於容器建立的過程已經闡述過一遍了,下面是依賴注入的問題。Spring提供的依賴注入的方法主要由兩種:一種是通過getBean的方法;另一種是通過註解@Autowaire。

需要指出的是依賴注入的過程是使用者第一次向ioc容器索要Bean的時候開始生產的,也可以通過設定BeanDefinition的lazy-init屬性來體現例項化。

2.分析

執行程式碼:

 HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService"
);

getBean方法實現類是AbstractBeanFactory:

    @Override
    public Object getBean(String name) throws Exception {
        BeanDefinition beanDefinition = beanDefinitionMap.get(name);
        if (beanDefinition == null) {
            throw new IllegalArgumentException("No bean named " + name + " is defined"
); } Object bean = beanDefinition.getBean(); if (bean == null) { //核心程式碼 bean = doCreateBean(beanDefinition); bean = initializeBean(bean, name); beanDefinition.setBean(bean); } return bean; }

在其中關鍵是doCreateBean(beanDefinition)方法,

    protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
        //例項化beanDefinition
        Object bean = createBeanInstance(beanDefinition);
        beanDefinition.setBean(bean);
        //增加屬性
        applyPropertyValues(bean, beanDefinition);
        return bean;
    }
protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
        return beanDefinition.getBeanClass().newInstance();
    }

呼叫applyPropertyValues方法:

protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(this);
        }
        //屬性注入的核心程式碼
        for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
            Object value = propertyValue.getValue();
            if (value instanceof BeanReference) {
                BeanReference beanReference = (BeanReference) value;
                value = getBean(beanReference.getName());
            }

            try {
                Method declaredMethod = bean.getClass().getDeclaredMethod(
                        "set" + propertyValue.getName().substring(0, 1).toUpperCase()
                                + propertyValue.getName().substring(1), value.getClass());
                declaredMethod.setAccessible(true);

                declaredMethod.invoke(bean, value);
            } catch (NoSuchMethodException e) {
                Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
                declaredField.setAccessible(true);
                declaredField.set(bean, value);
            }
        }
    }

3.總結

依賴注入的過程中,getBean是一個起點,之後呼叫createBean方法,根據BeanDefinition定義生產Bean和屬性注入。

其中例項化bean的過程可以採用CGLIB進行。CGLIB是常用的位元組碼.class生成器類庫,提供了一些列api來提供生成和轉換Java位元組碼的功能。

在IOC容器中,提供了SimpleInstantiationStrategy類生產Bean,它提供了兩種方式,一種是BeanUtils,它是JVM的反射機制。另一種就是CGLIB的方式。