關於spring的自動注入
spring里面可以設置BeanDefinition自動注入類型,默認為AUTOWIRE_NO(不進行自動注入)。mybatis里面的掃描接口生成MapperFactoryBean的時候設置了
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
他這里是為了按類型自動注入SqlSessionFactory或者SqlSessionTemplate。
spring構造bean的時候會進行填充屬性,調用了如下方法:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw);
內部有一段邏輯:
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;
}
前面MapperFactoryBean的BeanDefinition已經設置成AUTOWIRE_BY_TYPE,所以會調用autowireByType方法,該方法內部邏輯為獲取當前bean的所有PropertyDescriptor,並且過濾出包含有WriteMethod的PropertyNames。
獲取一個bean的PropertyDescriptor示例代碼如下:
public class IntrospectorTest {
/**
* PropertyDescriptor依賴字段的set和get方法
* 沒有對應的set和get方法則沒有對應的read和write方法
*
* 依賴於set和get方法,跟具體的字段名沒關系
*
* @throws IntrospectionException
*/
@Test
public void testPropertyDescriptors() throws IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(IntrospectorTest.class);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
if (pd.getName().equals("class")) {
continue;
}
System.out.println(pd.getName());
System.out.println(pd.getReadMethod());
System.out.println(pd.getWriteMethod());
System.out.println("********");
}
}
public void setName(String name){}
}
然后從獲取的PropertyNames迭代,獲取相應WriteMethod的入參類型,並從spring容器獲取相應類型的Bean,如果獲取到設置到MutablePropertyValues里。
最后調用方法:
applyPropertyValues(beanName, mbd, bw, pvs);
迭代MutablePropertyValues的PropertyValue,內部最終調用構造Bean的setXxx方法進行注入。
總結:spring的PropertyValues注入都是通過setXxx方法設置,比如xml配置的property或者BeanDefinition的getPropertyValues().add(key,value)方法。