Spring default-autowire

default-autowire 主要使用有三種方式:constructor、byName、byTypejava

constructor:

// 在applicationContext.xml中添加
//<bean id="pullingService" class="com.xiude.diamond.service.LongPullingService"></bean>
public class TaskServiceImpl implements TaskService {

    LongPullingService longPullingService;

    public TaskServiceImpl(LongPullingService service){
        this.longPullingService = service;
    }

    @Override
    public void setLongPullName(String longPullServiceName) {
        longPullingService.setName(longPullServiceName);
    }

    @Override
    public void displayName() {
        System.out.println(longPullingService.getName());
    }
}

Spring會將實例化一個全局惟一的LongPullingService對象pullingService,經過Constructor傳入給longPullingService。這個pullingService可能被多個TaskServiceImpl引用,其字段可能會被多個TaskServiceImpl修改,須要注意,例如spring

TaskService serviceA = (TaskService)context.getBean("taskService");
serviceA.setLongPullName("serviceA");
serviceA.displayName();  //輸出結果:serviceA
TaskService serviceB = (TaskService)context.getBean("taskService");
serviceB.setLongPullName("serviceB"); //全局惟一的LongPullService中Name被修改了
serviceA.displayName(); //輸出結果:serviceB

byName:

Name指的是pullingService,經過setPullingService將對象pullingService注入app

<bean id="pullingService" class="com.xiude.diamond.service.LongPullingService"></bean>
public void setPullingService(LongPullingService service) {
    this.longPullingService = service;
}

byType:

Type指的是LongPullingService這個類型,會根據set方法中的參數類型匹配將pullingService注入。若是存在兩個LongPullingService類型的對象,注入時由於不知道具體是pullingServiceA仍是pullingServiceB報錯:org.springframework.beans.factory.NoUniqueBeanDefinitionExceptionide

<bean id="pullingServiceA" class="com.xiude.diamond.service.LongPullingService"></bean>
<bean id="pullingServiceB" class="com.xiude.diamond.service.LongPullingService"></bean>pullingServiceA

 

byName、byType都必須顯式聲明set方法,不然沒法注入的。ui

 

這裏分析下autowireByType、autowireByName,它們在AbstractAutowireCapableBeanFactory類this

若是是byType,會根據LongPullingService 設置方法setLongPullingService,不管你自定義的setLongPullingServiceB都不會管用的,它只按照類型來setspa

<bean id="longPullingServiceA" class="com.xiude.diamond.service.LongPullingService">
    <property name="name" value="BUFFON"/>
</bean>
LongPullingService longPullingServiceA;
public void setLongPullingServiceB(LongPullingService service) {
    this.longPullingServiceA = service;
}

若是是byName,會提取出longPullingServiceB,可是找不到beanDefition=longPullingServiceB對象,這個判斷是下面兩個方法完成,若是沒找到,去parentBeanFactory找。都沒找到則設置longPullingServiceA失敗,longPullingServiceA = nullcode

@Override
public boolean containsBeanDefinition(String beanName) {
	Assert.notNull(beanName, "Bean name must not be null");
	return this.beanDefinitionMap.containsKey(beanName);
}

@Override
public boolean containsSingleton(String beanName) {
	return this.singletonObjects.containsKey(beanName);
}

那麼autowireByName是如何實現的,其入口在AbstractAutowireCapableBeanFactory的populateBeanorm

if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
	mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
	MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

	// Add property values based on autowire by name if applicable.
	if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
		autowireByName(beanName, mbd, bw, newPvs);
	}

	// Add property values based on autowire by type if applicable.
	if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
		autowireByType(beanName, mbd, bw, newPvs);
	}
	pvs = newPvs;
}

這裏會根據AUTOWIRE_BY_TYPE || AUTOWIRE_BY_NAME選擇不一樣的方法,對於autowire-by-name,首先經過反射機制從當前Bean中獲得須要注入的屬性名,而後使用這個屬性名向容器申請與之同名的Bean。xml

protected void autowireByName(
	String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    //獲取到longPullingServiceA
	String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
	for (String propertyName : propertyNames) {
		if (containsBean(propertyName)) {
              //從AbstractBeanFactory中獲取Bean對象,若是Bean沒有實例化,createBean
			Object bean = getBean(propertyName);
			pvs.add(propertyName, bean);
			registerDependentBean(propertyName, beanName);			
		}
    }
}

首先向IOC容器的存儲類AbstractBeanFactory查找該Bean,若是沒有找到,從父容器中繼續尋找。這裏涉及到遞歸調用尋找Bean。

public boolean containsBean(String name) {
	String beanName = transformedBeanName(name);
    //從DefaultSingletonBeanRegistry中查找,ConcurrentHashMap<String, Object> singletonObjects負責存儲bean name --> bean instance 的映射;
//DefaultListableBeanFactory中含有ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap
	if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {
		return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
	}
	// Not found -> check parent.
	BeanFactory parentBeanFactory = getParentBeanFactory();
	return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name)));
}

其次getBean(propertyName),這個接口是的實現就是觸發依賴注入,涉及到doGetBean-->doCreateBean等操做,最後會返回實例化對象,即bean=LongPullingService@1846。

最後registerDependentBean註冊longPullingServiceA的依賴與被依賴對象 之間映射關係

public void registerDependentBean(String beanName, String dependentBeanName) {
	// A quick check for an existing entry upfront, avoiding synchronization...
	String canonicalName = canonicalName(beanName);
   //taskServiceA中使用了longPullServiceA,因此dependentBeans含有taskServiceA,例如longPullServiceA--taskServiceA
   //dependentBeanMap存儲bean -- 依賴該bean的其餘bean
	Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
	if (dependentBeans != null && dependentBeans.contains(dependentBeanName)) {
		return;
	}
	// No entry yet -> fully synchronized manipulation of the dependentBeans Set
	synchronized (this.dependentBeanMap) {
		dependentBeans = this.dependentBeanMap.get(canonicalName);
		if (dependentBeans == null) {
			dependentBeans = new LinkedHashSet<String>(8);
			this.dependentBeanMap.put(canonicalName, dependentBeans);
		}
		dependentBeans.add(dependentBeanName);
	}
       //dependenciesForBeanMap存儲taskServiceA--longPullServiceA 的映射
	synchronized (this.dependenciesForBeanMap) {
		Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
		if (dependenciesForBean == null) {
			dependenciesForBean = new LinkedHashSet<String>(8);
			this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
		}
		dependenciesForBean.add(canonicalName);
	}
}

走到這一步,taskServiceA中的longPullServiceA對象依舊爲NULL,賦值在applyPropertyValues階段完成。

相關文章
相關標籤/搜索