文章目录
Spring的IOC容器的属性注入
本文只分析属性的注入,根据源码分析AbstractAutowireCapableBeanFactory的populateBean方法
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
// 到这步的时候,bean 实例化完成(通过工厂方法或构造方法),但是还没开始属性设值,
// InstantiationAwareBeanPostProcessor 的实现类可以在这里对 bean 进行状态修改,
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 如果mbd不是合成的 && 存在InstantiationAwareBeanPostProcessor,则遍历处理InstantiationAwareBeanPostProcessor
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 如果返回 false,代表不需要进行后续的属性设值,也不需要再经过其他的 BeanPostProcessor 的处理
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
// 如果continueWithPropertyPopulation为false,则跳过之后的属性填充
if (!continueWithPropertyPopulation) {
return;
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 解析自动装配模式为AUTOWIRE_BY_NAME和AUTOWIRE_BY_TYPE(用于注入)
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
// 解析autowireByName的注入
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// 通过类型装配。复杂一些
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
// 解析autowireByType的注入
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// BeanFactory是否注册过InstantiationAwareBeanPostProcessors
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否需要依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
// 注册过InstantiationAwareBeanPostProcessors 或者 需要依赖检查
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
//获取出对象的所有set get方法
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
// 应用后置处理器InstantiationAwareBeanPostProcessor
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 这里有个非常有用的 BeanPostProcessor
// 进到这里: AutowiredAnnotationBeanPostProcessor
// 对采用 @Autowired、@Value、@Resource 注解的依赖进行设值,
if(logger.isInfoEnabled()){
logger.info("调用InstantiationAwareBeanPostProcessor的实例:"+bp.getClass().getSimpleName()+"的postProcessPropertyValues方法," +
"\n说明:AutowiredAnnotationBeanPostProcessor对采用 @Autowired、@Value 注解的依赖进行设值");
}
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
// 依赖检查,对应depends-on属性
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
if (pvs != null) {
// 将所有PropertyValues中的属性填充到bean中
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
- 解析自动装配模式为AUTOWIRE_BY_NAME和AUTOWIRE_BY_TYPE(需要放入三方的bean到Spring容器中时,这时候没办法使用注解)要注入的属性
- @Autowired、@Value、@Resource注解解析,反射注入属性
- 步骤1以及XML配置文件中属性注入
构造方法有参注入
根据名称注入
最佳实践
使用注解:
@Bean(autowire = Autowire.BY_NAME)
public AutoWireTestService2 autoWireTestService2() {
return new AutoWireTestService2();
}
public class AutoWireTestService2 {
private HelloService helloService;
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
}
使用XML:
源码解析
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 寻找bw中需要依赖注入的属性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
// 校验是否存在beanName=propertyName的bean实例或者BeanDefinition
if (containsBean(propertyName)) {
// 获取propertyName的bean实例对象
Object bean = getBean(propertyName);
// 将属性名和属性值添加到pvs
pvs.add(propertyName, bean);
// 注册依赖关系到缓存(beanName依赖propertyName)
registerDependentBean(propertyName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
"' by name: no matching bean found");
}
}
}
}
- 得到需要依赖注入的属性:获取实例化的Bean中,写入属性值的方法(set方法)不为空 && pd不是从依赖性检查中排除的bean属性 && pd不包含在pvs里&& pd的属性类型不是“简单”属性(基础类型、枚举、Number等)的属性。
- 其中要注入的属性名称是:例如setXXX方法-setNam的名称是nam,根据nam从容器中获取Bean。
- 根据要注入的属性名称从Spring容器中获取要注入的Bean。
- 将要注入的属性加入到pvs中,之后再反射注入
分析要依赖注入的属性
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
Set<String> result = new TreeSet<>();
// 拿到mdb的属性值
PropertyValues pvs = mbd.getPropertyValues();
// 拿到bw的PropertyDescriptors
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
// 遍历bw的PropertyDescriptors
for (PropertyDescriptor pd : pds) {
// pd用于写入属性值的方法不为空 && pd不是从依赖性检查中排除的bean属性 && pd不包含在pvs里
// && pd的属性类型不是“简单”属性(基础类型、枚举、Number等)
// isSimpleProperty: 判断属性是不是“简单”属性
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
// 符合条件,则添加pd的name到result中,例如setNam的名称是nam
result.add(pd.getName());
}
}
return StringUtils.toStringArray(result);
}
其中PropertyDescriptor中存放的是类中的setXXX、getXXX以及isXXX方法(暂不分析)
小结
- set方法的例如setNam的名称是nam,根据名称从Spring容器中获取要注入的属性,该属性需要有set方法且属性类型不是简单类型,如果容器中没有该属性的bean时,则不注入该属性。
- 得到需要依赖注入的属性:获取实例化的Bean中,写入属性值的方法(set方法)不为空 && pd不是从依赖性检查中排除的bean属性 && pd不包含在pvs里&& pd的属性类型不是“简单”属性(基础类型、枚举、Number等)的属性。
- 其中要注入的属性名称是:例如setXXX方法-setNam的名称是nam,根据nam从容器中获取Bean。
- 根据要注入的属性名称从Spring容器中获取要注入的Bean,如果容器中没有该属性的bean时,则不注入该属性。
- 将要注入的属性加入到pvs中,之后再反射注入
根据类型注入
最佳实践
@Bean(autowire = Autowire.BY_TYPE)
public static AutoWireTestService3 autoWireTestService3() {
return new AutoWireTestService3();
}
public class AutoWireTestService3 {
private HelloService helloService;
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
}
Mybatis与Spring整合的时候,在MapperFactoryBean实例类中注入SqlSessionFactory
在BeanDefinition中设置注入方式是根据类型注入
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
String beanClassName = definition.getBeanClassName();
LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + beanClassName + "' mapperInterface");
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
// 设置有参构造的入参是 要注入接口的全类名
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
// 设置BeanClass为mapperFactoryBean
definition.setBeanClass(this.mapperFactoryBeanClass);
definition.getPropertyValues().add("addToConfig", this.addToConfig);
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
LOGGER.warn(() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
LOGGER.warn(() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
// 设置根据类型注入
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
}
设置注入类型是根据类型注入
MapperFactoryBean集成SqlSessionDaoSupport类,SqlSessionDaoSupport中有setSqlSessionFactory方法,在Spring容器中能根据SqlSessionFactory类型找到类型匹配的类,所以注入SqlSessionFactory
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);
}
}
源码解析
分析根据类型注入的源码
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// 寻找bw中需要依赖注入的属性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
// 遍历所有需要依赖注入的属性
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don't try autowiring by type for type Object: never makes sense,
// even if it technically is a unsatisfied, non-simple property.
if (Object.class != pd.getPropertyType()) {
// 获取指定属性的set方法,封装成MethodParameter(必须有set方法才能通过属性来注入)
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
// 将MethodParameter的方法参数索引信息封装成DependencyDescriptor
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 解析当前属性所匹配的bean实例,并把解析到的bean实例的beanName存储在autowiredBeanNames中
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
// 如果找到了依赖的bean实例,将属性名和bean实例放到pvs中
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
// 注册依赖关系,beanName依赖autowiredBeanName
registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
- 得到需要依赖注入的属性:获取实例化的Bean中,写入属性值的方法(set方法)不为空 && pd不是从依赖性检查中排除的bean属性 && pd不包含在pvs里&& pd的属性类型不是“简单”属性(基础类型、枚举、Number等)的属性。
- 其中要注入的属性名称是:例如setXXX方法-setNam的名称是nam,根据nam从容器中获取Bean。
- 调用resolveDependency先根据要注入的属性类型存在多个再根据名称从Spring容器中获取要注入的Bean。
- 将要注入的属性加入到pvs中,之后再反射注入
详细分析resolveDependency
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// 通用类注入的处理
// 如有必要,请获取延迟解析代理
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// 解析依赖关系,返回的result为创建好的依赖对象的bean实例
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
继续分析doResolveDependency
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,