Spring中到底有几种依赖注入的方式?
-
手动注入
a)set方式注入
<bean name="userService" class="com.gax.service.UserService"><property name="orderService" ref="orderService"/> </bean>
b)构造方法注入
<bean name="userService" class="com.gax.service.UserService"><constructor‐arg index="0" ref="orderService"/> </bean>
-
自动注入
a)XML的autowire自动注入
b) @Autowired注解的自动注入
属性填充部分源码:
/*** Populate the bean instance in the given BeanWrapper with the property values* from the bean definition.* @param beanName the name of the bean* @param mbd the bean definition for the bean* @param bw the BeanWrapper with bean instance*/
@SuppressWarnings("deprecation") // for postProcessPropertyValues
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.// 实例化之后,属性设置之前if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);int resolvedAutowireMode = mbd.getResolvedAutowireMode();if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {// MutablePropertyValues是PropertyValues具体的实现类MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}// Add property values based on autowire by type if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}pvs = newPvs;}boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);PropertyDescriptor[] filteredPds = null;if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {// 这里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,会直接给对象中的属性赋值// AutowiredAnnotationBeanPostProcessor内部并不会处理pvs,直接返回了PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}}if (needsDepCheck) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}checkDependencies(beanName, mbd, filteredPds, pvs);}// 如果当前Bean中的BeanDefinition中设置了PropertyValues,那么最终将是PropertyValues中的值,覆盖@Autowiredif (pvs != null) {applyPropertyValues(beanName, mbd, bw, pvs);}
}/*** Fill in any missing property values with references to* other beans in this factory if autowire is set to "byName".* @param beanName the name of the bean we're wiring up.* Useful for debugging messages; not used functionally.* @param mbd bean definition to update through autowiring* @param bw the BeanWrapper from which we can obtain information about the bean* @param pvs the PropertyValues to register wired objects with*/
protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {// 当前Bean中能进行自动注入的属性名String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);// 遍历每个属性名,并去获取Bean对象,并设置到pvs中for (String propertyName : propertyNames) {if (containsBean(propertyName)) {Object bean = getBean(propertyName);pvs.add(propertyName, bean);// 记录一下propertyName对应的Bean被beanName给依赖了registerDependentBean(propertyName, beanName);if (logger.isTraceEnabled()) {logger.trace("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");}}}
}/*** Abstract method defining "autowire by type" (bean properties by type) behavior.* <p>This is like PicoContainer default, in which there must be exactly one bean* of the property type in the bean factory. This makes bean factories simple to* configure for small namespaces, but doesn't work as well as standard Spring* behavior for bigger applications.* @param beanName the name of the bean to autowire by type* @param mbd the merged bean definition to update through autowiring* @param bw the BeanWrapper from which we can obtain information about the bean* @param pvs the PropertyValues to register wired objects with*/
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);// 当前Bean中能进行自动注入的属性名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()) {MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);// Do not allow eager init for type matching in case of a prioritized post-processor.// eager表示立即初始化,表示在根据类型查找Bean时,允不允许进行Bean的创建,如果当前bean实现了PriorityOrdered,那么则不允许// 为什么不允许,因为我自己是PriorityOrdered,是优先级最高的,不能有比我创建得更早的boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);// 根据类型找到的结果Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);if (autowiredArgument != null) {pvs.add(propertyName, autowiredArgument);}for (String autowiredBeanName : autowiredBeanNames) {registerDependentBean(autowiredBeanName, beanName);if (logger.isTraceEnabled()) {logger.trace("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);}}
}/*** Return an array of non-simple bean properties that are unsatisfied.* These are probably unsatisfied references to other beans in the* factory. Does not include simple properties like primitives or Strings.* @param mbd the merged bean definition the bean was created with* @param bw the BeanWrapper the bean was created with* @return an array of bean property names* @see org.springframework.beans.BeanUtils#isSimpleProperty*/
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {Set<String> result = new TreeSet<>();PropertyValues pvs = mbd.getPropertyValues();PropertyDescriptor[] pds = bw.getPropertyDescriptors();// 什么样的属性能进行自动注入?// 1.该属性有对应的set方法// 2.没有在ignoredDependencyTypes中// 3.如果该属性对应的set方法是实现的某个接口中所定义的,那么接口没有在ignoredDependencyInterfaces中// 4.属性类型不是简单类型,比如int、Integer、int[]for (PropertyDescriptor pd : pds) {if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&!BeanUtils.isSimpleProperty(pd.getPropertyType())) {result.add(pd.getName());}}return StringUtils.toStringArray(result);
}
XML的autowire自动注入
<bean id="userService" class="com.gax.service.UserService" autowire="byType"/>
// Bean的自动注入模式包括:byType、byName、constructor、default、no
注意:上面这种写法Spring会自动给所有属性赋值,不需要在属性上添加@Autowired注解,但是需要属性对应的set方法
get方法的定义: 方法参数个数为0个,并且(方法名字以"get"开头或者方法名字以"is"开头并且方法的返回类型为boolean)
set方法的定义:方法参数个数为1个,并且(方法名字以"set"开头并且方法返回类型为void)
在创建Bean的过程-填充属性时,Spring会去解析当前类,把当前类的所有方法都解析出来,解析每个方法得到对应的PropertyDescriptor
对象(属性描述器)
public class PropertyDescriptor extends FeatureDescriptor
{// get方法对应返回值类型,set方法对应唯一参数类型private Reference<? extends Class<?>> propertyTypeRef;// get方法的Method对象的引用private final MethodRef readMethodRef = new MethodRef();// set方法的Method对象的引用private final MethodRef writeMethodRef = new MethodRef();private Reference<? extends Class<?>> propertyEditorClassRef;private boolean bound;private boolean constrained;// The base name of the method name which will be prefixed with the// read and write method. If name == "foo" then the baseName is "Foo"private String baseName;// set方法的名字private String writeMethodName;// get方法的名字private String readMethodName;... ...
}
Spring通过byName自动填充属性流程:
1、找到所有set方法所对应的XXX部分的名字
(public void setXXX(XXX xxx){ ... ...})
2、根据XXX部分的名字去获取bean
Spring通过byType自动填充属性流程:
1、获取到set方法中的唯一参数的类型,并且根据该类型去容器中获取bean
(public void setXXX(XXX xxx){ ... ...})
2、如果找到多个会报错
Spring通过constructor自动填充属性流程:因为推断构造方法,所以只考虑一个有参构造方法的情况
1、利用构造方法的参数信息从Spring容器中去找bean
2、找到bean之后作为参数传给构造方法,从而实例化得到一个bean对象,并完成属性赋值
(属性赋值的代码得程序员来写,this.XXX = XXX)
构造方法注入相当于byType+byName,普通的byType是根据set方法中的参数类型去找bean,找到多个会报错,而constructor就是通过构造方法中的参数类型去找bean,如果找到多个会根据参数名确定。
no,表示关闭autowire
default,表示默认值,<bean> 标签可以定义在<beans>里面,此时设置<bean>的autowire属性为default,就会去使用<beans>标签中设置的注入方式,作为默认
为什么平时都是用的@Autowired注解?而没有用XML自动注入方式呢?
官方描述:
Essentially, the @Autowired annotation provides the same capabilities as described in Autowiring Collaborators but with more fine‐grained control and wider applicability
翻译:从本质上讲,@Autowired注解提供了与autowire相同的功能,但是拥有更细粒度的控制和更广泛的适用性。
XML中的autowire控制的是整个bean的所有属性,而@Autowired注解是直接写在某个属性、某个set方法、某个构造方法上的。
@Autowired注解的自动注入
@Autowired注解,是byType和byName的结合
@Autowired注解可以写在:
1、属性上:先根据属性类型去找Bean,如果找到多个再根据属性名确定一个
2、构造方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
3、set方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
底层用到:属性注入、set方法注入、构造方法注入