Spring default-autowire

There are three main ways to use default-autowire: constructor, byName, byType

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 will instantiate a globally unique LongPullingService object, pullingService, and pass it to longPullingService through Constructor. This pullingService may be referenced by multiple TaskServiceImpl, and its fields may be modified by multiple TaskServiceImpl. Note, for example

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 refers to the pullingService, and the object pullingService is injected through setPullingService

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

byType:

Type refers to the LongPullingService type, and the pullingService will be injected according to the parameter type matching in the set method. If there are two objects of type LongPullingService, an error is reported during injection because it is not known whether it is pullingServiceA or pullingServiceB: org.springframework.beans.factory.NoUniqueBeanDefinitionException

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

 

Both byName and byType must explicitly declare the set method, otherwise they cannot be injected.

 

Here we analyze autowireByType and autowireByName, which are in the AbstractAutowireCapableBeanFactory class

If it is byType, the method setLongPullingService will be set according to LongPullingService. No matter your custom setLongPullingServiceB will not work, it will only be set according to the type.

<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;
}

If it is byName, longPullingServiceB will be extracted, but the beanDefition=longPullingServiceB object cannot be found. This judgment is completed by the following two methods. If it is not found, go to parentBeanFactory to find it. If not found, then setting longPullingServiceA fails, longPullingServiceA = null

@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);
}

So how is autowireByName implemented, and its entry is in populateBean of AbstractAutowireCapableBeanFactory

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;
}

Here, different methods will be selected according to AUTOWIRE_BY_TYPE || AUTOWIRE_BY_NAME. For autowire-by-name, first get the attribute name that needs to be injected from the current bean through the reflection mechanism, and then use this attribute name to apply to the container for a bean with the same name.

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);			
		}
    }
}

First, look for the bean from the storage class AbstractBeanFactory of the IOC container. If it is not found, continue to look for it from the parent container. This involves recursive calls to find beans.

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)));
}

Secondly, getBean(propertyName), the implementation of this interface is to trigger dependency injection, which involves operations such as doGetBean-->doCreateBean, and finally returns the instantiated object, that is, bean=LongPullingService@1846.

Finally, registerDependentBean registers the mapping relationship between the dependencies of longPullingServiceA and the dependent objects

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);
	}
}

At this point, the longPullServiceA object in taskServiceA is still NULL, and the assignment is completed in the applyPropertyValues ​​stage.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325527818&siteId=291194637