上一篇文章spring源码系列-Bean的创建流程中,我们抽丝剥茧的去分析bean的创建流程,终于揭开了spring创建bean的“黑幕”,我们对spring中bean的创建流程有了大概的了解。但是我们很少会直接用BeanFactory.getBean的方式去获取进而使用Bean,常规操作一般是基于注解注入,如@Autowired,@Resource等。那么这些注解是如何做依赖注入的?幕后又有哪些操作,是“人性的扭曲,还是道德的沦丧”,下面我们一起走进依赖注入(IOC/DI)的世界。本文可以分为以下几个板块
- 前言
- spring的依赖注入
2.1 什么是依赖注入
2.2 依赖注入的常见方式
2.3 整体bean的创建流程
2.4 三种注入方式
2.4.1 set注入
2.4.1.1 set注入的使用方法
2.4.1.2 set注入源码分析
2.4.2 构造器注入
2.4.2.1 构造器注入的使用方法
2.4.2.2 构造器注入源码分析
2.4.3 注解注入
2.4.3.1 @Autowired
2.4.3.2 @Resouce- 总结
1. 前言
在分析源码之前,我们先思考几个小问题。
到底什么是依赖注入?spring中又是如何实现依赖注入的?
依赖注入的方式有哪些?有哪些异同
@Autowired和@Resource有哪些区别?field用@Autowired或者@Resource注入的时候可以没有set方法吗?@Autowired或者@Resource 注入的field修饰符可以是private吗?如果要注入的类有多个实现会怎么样?注入的field名称和容器中配置的bean的name必须保持一致吗?
-
循环依赖怎么处理?为什么不能处理基于构造器的循环依赖?为什么可以处理基于field的循环依赖?
那么我们就带着这些问题,溯源spring依赖注入的内幕。
2. spring的依赖注入
2.1 什么是依赖注入
那么到底什么是spring的依赖注入呢?再说这个概念之前我们先说下以下IOC和DI
-
IOC(Inversion Of Controller)即控制反转,意思是控制权的转向。以前我们需要依赖的时候,我们自己会去创建依赖。而用了spring之后,我们需要依赖的时候,我们会去请求spring的容器,由spring容器去给我们注入依赖
。 -
DI(Dependency Injection)即依赖注入,依赖注入其实是IOC在spring中的具体表现
。
spring的依赖注入其实是我们实例化bean时,初始化依赖并注入的过程。
2.2 依赖注入的常见方式
那么spring中常用的依赖注入方式有哪些呢?
方式 | 优点 | 缺点 |
---|---|---|
set注入 | 1. 便于查看依赖关系 。2. 单例模式下可以解决循环依赖 |
1.需要额外增加配置和set方法。2. 不能保证注入完整性 |
构造器注入 | 1.具有set方式的优点。2. 且可以保证注入的完整性(spring 不会把空的属性注入到构造器中) |
1. 需要额外配置。2.需要相应的构造器。3.无法解决循环依赖 |
注解注入 | 1. 简洁,无需多余的方法。2. 基于field注解注入,单例模式下能解决循环依赖 |
1. 依赖关系不明显。2. 如果是基于field用注解依赖注入,则不能保证变量初始化的状态是否正确(可能注入一个空的依赖)。3.如果是基于构造器注入,则无法解决循环依赖。 |
2.3 整体bean的创建流程
再说依赖注入之前,我们先回顾下spring 整体bean的创建流程,依赖注入也是创建bean中的一部分。spring根据不同scope创建bean时,要经历以下几个过程
1. 处理MethodOverrides
2. 实例化的前置处理
3. 根据不同的策略实例化bean,并包装成beanWapper
4. 提前暴露beanFactory
5. 属性填充
6. 调用初始化方法,即各种处理器
7. 注册销毁相关方法
2.4 三种注入方式
直入正题,分析下三种注入方式的实现原理。set注入,构造器注入,注解注入
2.4.1 set注入
set注入,顾名思义通过添加set方法进行注入。是最基础,最原始的注入方式。
2.4.1.1 set注入的使用方法
- 添加set 方法
public class ServiceAImpl implements ServiceA {
private ServiceB serviceB;
@Override
public void methodA() {
serviceB.methodB();
}
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
public class ServiceBImpl implements ServiceB {
@Override
public void methodB() {
System.out.println("methodB");
}
}
- 配置xml
<bean id="serviceA" class="onlyspring.ioc.ServiceAImpl">
<property name="serviceB" ref="serviceB"/>
</bean>
<bean id="serviceB" class="onlyspring.ioc.ServiceBImpl"/>
通过以上配置便可以正常的在被注入的类中获取要注入的属性了。那么set注入究竟是怎么注入的?为什么要有set方法呢?
2.4.1.2 set注入源码分析
上面我们提到了spring创建bean的过程,其中set注入发生在阶段5,即属性填充时
,大致流程如下:
1. 容器初始化的时候,解析配置文件得到BeanDefinition。
2. 实例化的时候,通过反射使用无参构造器实例化bean。
3. 根据当前BeanDefinition中的PropertyValues。做属性填充。
4. 属性填充时依次调用BeanFactory.getBean做依赖的初始化。
5. 调用set方法设置属性值。
1.容器初始化的时候,解析配置文件得到BeanDefinition
//初始化容器
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
解析bean属性
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
得到List<PropertyValue> propertyValueList;
public void parsePropertyElement(Element ele, BeanDefinition bd) {
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
当前步骤发生在容器初始化时,spring 会加载配置文件,并解析所有配置的bean,并放入缓存。
2. 实例化的时候,通过反射使用无参构造器实例化bean
在步骤1中,我们完成了容器初始化的配置文件解析,那么接下来就要进行bean的创建
,bean的创建本身是实例化bean,并初始化的过程
。那么实例化要用到哪种策略(调哪个构造函数,有参的还是无参的?有参的具体调用哪个构造方法)
?源码如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Need to determine the constructor...
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
set注入并不会走构造器注入,所以在这里会通过反射调用无参构造方法进行bean的实例化
。
3. 根据当前BeanDefinition中的PropertyValues,做属性填充
bean实例化完成后,此时的bean仅仅是一个空的Object,各种属性未赋值,还无法使用。那么接下来就会发生属性的填充。set注入毫无例外也是这个时候进行的
。源码如下:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) {
if (!pvs.isEmpty()) {
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;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
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;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
applyPropertyValues(beanName, mbd, bw, pvs);
}
4. 属性填充时依次调用BeanFactory.getBean做依赖的初始化。
在步骤3中,在做属性填充的时候,发现有些依赖未初始化,那么此时需要做依赖初始化
,依赖的初始化流程其实就是再走一遍BeanFacotry.getBean的流程
。源码如下
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs == null || pvs.isEmpty()) {
return;
}
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
5. 调用set方法设置属性值
步骤4后,我们已经初始化了相应的依赖,此时对于依赖注入最后要做的就是通过反射调用set方法进行注入
。源码如下:
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
public void setValue(final Object object, Object valueToApply) throws Exception {
final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
this.pd.getWriteMethod());
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
writeMethod.setAccessible(true);
return null;
}
});
}
else {
writeMethod.setAccessible(true);
}
}
final Object value = valueToApply;
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
writeMethod.invoke(object, value);
return null;
}
}, acc);
}
catch (PrivilegedActionException ex) {
throw ex.getException();
}
}
else {
writeMethod.invoke(getWrappedInstance(), value);
}
}
}
看完set注入的源码,我们看下如下case。
ServiceA里有个ServiceB属性,配置如下:
<bean id="serviceA" class="example.autowired.normal.ServiceA">
<property name="serviceB" ref="serviceB"/>
</bean>
<bean id="serviceB" class="example.autowired.normal.ServiceB"/>
case1如下(set方法名为setSeviceB):
public class ServiceA {
private ServiceB serviceB;
public void setSeviceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
public void test(){
System.out.println(serviceB.tx());
}
}
case2如下(set方法名为setserviceB):
public class ServiceA {
private ServiceB serviceB;
public void setserviceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
public void test(){
System.out.println(serviceB.tx());
}
}
case3 如下(set方法名为setser):
public class ServiceA {
private ServiceB serviceB;
public void setser(ServiceB serviceB) {
this.serviceB = serviceB;
}
public void test(){
System.out.println(serviceB.tx());
}
}
问: case1 和 case2 和 case3 哪种能够注入呢?
答:case1 能正常注入(常规操作),case2能正常注入(WTF?),case3无法注入
解:1:一般来说spring 会在setProperty之前,解析当前类的所有public方法(不包括从父类继承的方法)。2.然后判断当前类是否以set或者get 或者is开头,然后解析成PropertyDescriptor数组,且会放入缓存中,其中key 为 首字母小写(setMethodName.substring(3)),value 就是解析到PropertyDescriptor(含有对set方法的引用)。3.set注入的时候会根据当前propertyName(xml 中配置,和类中的filedname 相同)去缓存中取对应的PropertyDescriptor,取不到就无法完成注入。所以propertyName 必须 equal 首字母小写(setMethodName.substring(3))。
源码如下:
解析method部分
// Apply some reflection to the current class.
// First get an array of all the public methods at this level
Method methodList[] = getPublicDeclaredMethods(beanClass);
// Now analyze each method.
for (int i = 0; i < methodList.length; i++) {
Method method = methodList[i];
if (method == null) {
continue;
}
// skip static methods.
int mods = method.getModifiers();
if (Modifier.isStatic(mods)) {
continue;
}
String name = method.getName();
Class<?>[] argTypes = method.getParameterTypes();
Class<?> resultType = method.getReturnType();
int argCount = argTypes.length;
PropertyDescriptor pd = null;
if (name.length() <= 3 && !name.startsWith(IS_PREFIX)) {
// Optimization. Don't bother with invalid propertyNames.
continue;
}
try {
if (argCount == 0) {
if (name.startsWith(GET_PREFIX)) {
// Simple getter
pd = new PropertyDescriptor(this.beanClass, name.substring(3), method, null);
} else if (resultType == boolean.class && name.startsWith(IS_PREFIX)) {
// Boolean getter
pd = new PropertyDescriptor(this.beanClass, name.substring(2), method, null);
}
} else if (argCount == 1) {
if (int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {
pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, method, null);
} else if (void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {
// Simple setter
pd = new PropertyDescriptor(this.beanClass, name.substring(3), null, method);
if (throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
} else if (argCount == 2) {
if (void.class.equals(resultType) && int.class.equals(argTypes[0]) && name.startsWith(SET_PREFIX)) {
pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, null, method);
if (throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
}
} catch (IntrospectionException ex) {
// This happens if a PropertyDescriptor or IndexedPropertyDescriptor
// constructor fins that the method violates details of the deisgn
// pattern, e.g. by having an empty name, or a getter returning
// void , or whatever.
pd = null;
}
if (pd != null) {
// If this class or one of its base classes is a PropertyChange
// source, then we assume that any properties we discover are "bound".
if (propertyChangeSource) {
pd.setBound(true);
}
addPropertyDescriptor(pd);
}
}
首字母转小写部分
PropertyDescriptor(Class<?> bean, String base, Method read, Method write) throws IntrospectionException {
if (bean == null) {
throw new IntrospectionException("Target Bean class is null");
}
setClass0(bean);
setName(Introspector.decapitalize(base));
setReadMethod(read);
setWriteMethod(write);
this.baseName = base;
}
存放cache 部分
PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
if (Class.class == beanClass &&
("classLoader".equals(pd.getName()) || "protectionDomain".equals(pd.getName()))) {
// Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those
continue;
}
if (logger.isTraceEnabled()) {
logger.trace("Found bean property '" + pd.getName() + "'" +
(pd.getPropertyType() != null ? " of type [" + pd.getPropertyType().getName() + "]" : "") +
(pd.getPropertyEditorClass() != null ?
"; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
}
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
this.propertyDescriptorCache.put(pd.getName(), pd);
}
2.4.2 构造器注入
构造器注入,即通过构造函数进行注入。需要在类中添加相应的构造方法。
2.4.2.1 构造器注入的使用方法
- 添加构造函数
public class ServiceA {
private ServiceB serviceB;
public ServiceA(ServiceB serviceB){
this.serviceB=serviceB;
}
public void test(){
System.out.println(serviceB.tx());
}
}
public class ServiceB {
String tx(){
return "ConServiceB test";
}
}
- 配置xml
<bean id="conServiceA" class="example.autowired.cons.ServiceA">
<constructor-arg ref="conServiceB"/>
</bean>
<bean id="conServiceB" class="example.autowired.cons.ServiceB"/>
通过以上配置便可以通过构造器注入了。构造器注入与set注入的最大区别就是构造器注入无法解决循环依赖的问题,那么构造器注入到底是如何生效的?为什么又无法解决循环依赖呢?
2.4.2.2 构造器注入源码分析
上面我们提到了spring创建bean的过程,其中构造器注入发生在阶段3,即选择不同的实例化策略时
,大致流程如下:
1. 容器初始化的时候,解析配置文件得到BeanDefinition。
2. 实例化的时候,BeanDefinition的constructorArgumentValues不为空,决定进行构造器注入。
3. 实例化构造器依赖的相关属性。
4. 调用相关构造器进行实例化,完成构造器注入。
1.容器初始化的时候,解析配置文件得到BeanDefinition
//初始化容器
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
解析bean属性
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
得到ConstructorArgumentValues constructorArgumentValues;
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(indexAttr)) {
try {
int index = Integer.parseInt(indexAttr);
if (index < 0) {
error("'index' cannot be lower than 0", ele);
}
else {
try {
this.parseState.push(new ConstructorArgumentEntry(index));
Object value = parsePropertyValue(ele, bd, null);
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
error("Ambiguous constructor-arg entries for index " + index, ele);
}
else {
bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
}
}
finally {
this.parseState.pop();
}
}
}
catch (NumberFormatException ex) {
error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
}
}
else {
try {
this.parseState.push(new ConstructorArgumentEntry());
Object value = parsePropertyValue(ele, bd, null);
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
}
finally {
this.parseState.pop();
}
}
}
当前步骤发生在容器初始化时,spring 会加载配置文件,并解析所有配置的bean,并放入缓存。
2. 实例化的时候,BeanDefinition的constructorArgumentValues不为空,决定进行构造器注入。
doCreateBean的时候先进行bean的实例化
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
mbd.hasConstructorArgumentValues()不为空,即配置文件中存在 constructor-arg 属性。那么需要调用构造器进行注入
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
3. 调用构造器注入前,进行依赖的初始化。
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
Object resolvedValue =
valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
ConstructorArgumentValues.ValueHolder resolvedValueHolder =
new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
初始化的过程其实就是getBean的过程
Object bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
return bean;
4. 调用构造器进行实例化。
在步骤3中,我们已经实例化了调用构造器所需依赖,那么接下来就可以将该参数传给构造器,通过反射调用构造器进行注入了
。当然调用构造器之前有一个构造器解析并选择的过程,无非就是根据参数类型和参数位置已经排序来选择
。
选择构造器的过程
for (Constructor<?> candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
if (paramTypes.length < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
try {
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (this.beanFactory.logger.isTraceEnabled()) {
this.beanFactory.logger.trace(
"Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<UnsatisfiedDependencyException>();
}
causes.add(ex);
continue;
}
}
else {
// Explicit arguments given -> arguments length must match exactly.
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this constructor if it represents the closest match.
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<Constructor<?>>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
调用构造器进行注入的过程
beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner,
final Constructor<?> ctor, Object... args) {
if (bd.getMethodOverrides().isEmpty()) {
if (System.getSecurityManager() != null) {
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
ReflectionUtils.makeAccessible(ctor);
return null;
}
});
}
return BeanUtils.instantiateClass(ctor, args);
}
else {
return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
}
}
2.4.3 注解注入
注解注入,顾名思义就是通过注解进行注入。这种注入方式不用做xml配置,是我们最常使用的注入方式。而最常用的注入的注解无非说就是@Autowired和@Resource。
2.4.3.1 @Autowired
2.4.3.1.1 @Autowired使用方法
- 注入属性
public class ServiceA {
@Autowired
ServiceB serviceB;
public String test(){
return serviceB.tb();
}
}
public interface ServiceB {
String tb();
}
public class ServiceBImplOne implements ServiceB{
@Override
public String tb() {
return "ServiceBImplOne";
}
}
- 配置xml
<context:annotation-config/>
<bean id="sa" class="example.autowired.auto.ServiceA"/>
<bean id="s1" class="example.autowired.auto.ServiceBImplOne"></bean>
或者配置包自动扫描
<context:component-scan base-package="example.*"/>
@Component
public class ServiceA {
@Autowired
ServiceB serviceB;
public String test(){
return serviceB.tb();
}
}
@Component
public class ServiceBImplOne implements ServiceB{
@Override
public String tb() {
return "ServiceBImplOne";
}
}
值得注意的是,以上两种都可以让当前bean受spring管理
。且使用的时候不能再使用BeanFactory,而是要使用ApplicationContext
,因为BeanFactory初始化容器的时候并不会提取并注册BeanPostProcessor,而注解注入依赖的就是BeanPostProcessor,包括我们熟知的aop,Transaction都是基于各种BeanPostProcessor实现的
,这也是我们在前几篇文章中说的,如果要实使用这些功能,就必须用ApplicationContext的原因。当然你也可以选择使用BeanPostProcessor,然后自己去注册BeanPostProcessor,但是便捷性不如ApplicationContext。
public static void main(String[] args) {
//初始化容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
ServiceA serviceA = (ServiceA) applicationContext.getBean("sa");
System.out.println(serviceA.test());
}
2.4.3.1.2 @Autowired源码
上面我们提到了spring 创建bean的流程,@Autowired生效的过程大致分为两步,解析InjectionMetadata,注入属性。其中解析InjectionMetadata 发生在步骤3和步骤4之间,applyMergedBeanDefinitionPostProcessors被调用时。而注入属性则发生在步骤5,属性填充时。大致流程如下:
1. 容器初始化的时候,解析配置文件得到BeanDefinition。
2. 创建bean的时候,调用无参构造方法实例化bean。
3. 调用applyMergedBeanDefinitionPostProcessors 动态改变RootBeanDefinition,且调用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition,解析得到InjectionMetadata,并将其放入缓存。更新RootBeanDefinition的externallyManagedConfigMembers属性。
4. 属性填充时,调用AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues做属性填充。
1.容器初始化的时候,解析配置文件得到BeanDefinition
//初始化容器
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
解析bean属性,得到BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
当前步骤发生在容器初始化时,spring 会加载配置文件,并解析所有配置的bean,并放入缓存。
2. 创建bean的时候,调用无参构造方法实例化bean。
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// Need to determine the constructor...
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
3. 解析InjectionMetadata。
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
调用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition 解析InjectionMetadata。
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
"] for autowiring metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
do {
final LinkedList<InjectionMetadata.InjectedElement> currElements =
new LinkedList<InjectionMetadata.InjectedElement>();
ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
}
});
ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterTypes().length == 0) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
其中解析InjectionMetadata的方式为:利用反射遍历当前class的field和method,如果发现出现@Autowired,则将其解析为InjectionMetadata。并将InjectionMetadata 放入缓存中,其中缓存的key 为beanName,值为InjectionMetadata。
4. 调用InjectionMetadata.inject做属性注入
开始填充属性
populateBean(beanName, mbd, instanceWrapper);
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
调用AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues做属性填充
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
初始化相关依赖,将field设置为可访问,为field 赋值。
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName)) {
if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
分析了Autowired的源码后,我们来看下思考如下case
case1 私有属性能否注入:
public class ServiceA {
@Autowired
private ServiceB serviceB;
public String test(){
return serviceB.tb();
}
}
public class ServiceBImplOne implements ServiceB{
@Override
public String tb() {
return "ServiceBImplOne";
}
}
<bean id="sa" class="example.autowired.auto.ServiceA"/>
<bean id="s1" class="example.autowired.auto.ServiceBImplOne"/>
case2 两个同类型的bean 能否注入:
public class ServiceA {
@Autowired
private ServiceB serviceB;
public String test(){
return serviceB.tb();
}
}
public class ServiceBImplOne implements ServiceB{
@Override
public String tb() {
return "ServiceBImplOne";
}
}
public class ServiceBImplTwo implements ServiceB{
@Override
public String tb() {
return "ServiceBImplTwo";
}
}
<bean id="sa" class="example.autowired.auto.ServiceA"/>
<bean id="s1" class="example.autowired.auto.ServiceBImplOne"/>
<bean id="s2" class="example.autowired.auto.ServiceBImplTwo"/>
case3 两个相同类型的 bean,且fieldName.equal(beanName):
public class ServiceA {
@Autowired
private ServiceB s1;
public String test(){
return s1.tb();
}
}
public class ServiceBImplOne implements ServiceB{
@Override
public String tb() {
return "ServiceBImplOne";
}
}
public class ServiceBImplTwo implements ServiceB{
@Override
public String tb() {
return "ServiceBImplTwo";
}
}
<bean id="sa" class="example.autowired.auto.ServiceA"/>
<bean id="s1" class="example.autowired.auto.ServiceBImplOne"/>
<bean id="s2" class="example.autowired.auto.ServiceBImplTwo"/>
问:case1 能正确注入吗?
答:能。因为注入的时候无论filed是否私有,都会利用反射将其置为可访问,从而直接为其赋值
。
问:case2 能正确注入吗?
答:不能。因为@Autowired注入的时候,初始化依赖的时候,先是根据类型去查,查到两个同类型的bean,再根据fieldName去匹配,如果beanName.equal(fieldName),则取命中的bean注入,否则报错NoUniqueBeanDefinitionException
。
问:case3 能正确注入吗?
答:能。
查询依赖相关源码如下:
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
查找所有example.autowired.auto.ServiceB 类型的bean,并且实例化
protected Map<String, Object> findAutowireCandidates(
String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = this.resolvableDependencies.get(autowiringType);
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
根据查找结果进行处理。如果查找的结果数量为1,则直接取查找到的bean实例做为待注入的参数值。如果查找的结果数量>1,则继续根据filedName做完全匹配,如果未匹配到结果则报错,如果匹配到结果,则直接取查找到的bean实例做为待注入的参数值
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(type, matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
流程图如下:
2.4.3.2 @Resouce
上面我们看了@Autowired的源码,接下来我们分析下@Resource的源码。@Resource的装配流程跟@Autowired,不同的地方在于依赖的查找策略上。大致流程如下:
1. 容器初始化的时候,解析配置文件得到BeanDefinition。
2. 创建bean的时候,调用无参构造方法实例化bean。
3. 调用applyMergedBeanDefinitionPostProcessors 动态改变RootBeanDefinition,且调用CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition,解析得到InjectionMetadata,并将其放入缓存。更新RootBeanDefinition的externallyManagedConfigMembers属性。
4. 属性填充时,调用CommonAnnotationBeanPostProcessor.postProcessPropertyValues做属性填充。
可以看到,整个装配的套路跟@Autowired是类似的,不同之处在于调用不同的BeanPostProcessor,从而实现不同的依赖查找策略。那么这个依赖查找策略究竟有什么不同呢?或许我们能从源码里找到不同,这里我们重点看下依赖查找的过程。
- 属性填充时,调用InjectionMetadata.inject做属性注入
public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
Collection<InjectedElement> elementsToIterate =
(this.checkedElements != null ? this.checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : elementsToIterate) {
if (debug) {
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
- 通过反射为属性赋值时,获取属性值
protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
- 如果指定的name 属性,那么根据name 和类型去查找bean。
protected Object autowireResource(BeanFactory factory, LookupElement element, String requestingBeanName)
throws BeansException {
Object resource;
Set<String> autowiredBeanNames;
String name = element.name;
if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&
factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<String>();
resource = ((AutowireCapableBeanFactory) factory).resolveDependency(
element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
}
else {
resource = factory.getBean(name, element.lookupType);
autowiredBeanNames = Collections.singleton(name);
}
if (factory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
for (String autowiredBeanName : autowiredBeanNames) {
if (beanFactory.containsBean(autowiredBeanName)) {
beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
}
}
}
return resource;
}
- 未指定name属性,则使用autowired 一样的查找策略。
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(type, matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
可以看到@Autowired的区别主要在于是否指定name,以及 type 属性。
注解 | 查找过程 | 不同点 |
---|---|---|
@Autowired |
1. 根据class,查找所有类型的bean。 2. 查找不到,根据required属性,决定是否抛出NoSuchBeanDefinitionException。 3. 查找的到,且只查找一个,则使用该bean做属性注入。 4. 查找到不止一个,则根据条件做精确筛选唯一,未筛选到抛出NoUniqueBeanDefinitionException。 5. 筛选到唯一,则使用唯一的bean做属性注入。
|
不会根据name做查找。 |
@Resource |
1. 如果配置了name,根据name查找特定name和type类型(未指定则使用默认type)的bean做属性注入。 2. 如果未配置name,根据class,查找所有类型的bean。 3. 查找不到,根据required属性,决定是否抛出NoSuchBeanDefinitionException。 4. 查找的到,且只查找一个,则使用该bean做属性注入。 5. 查找到不止一个,则根据条件做精确筛选唯一,未筛选到抛出NoUniqueBeanDefinitionException。 6. 筛选到唯一,则使用唯一的bean做属性注入。 |
先根据name做查找,找不到则使用autowired一样的策略。 |
3 总结
本篇文章中,总结了spring 几种依赖注入的方式,并着重分析了@Autowired和@Resource的区别。虽然大部分情况下,@Autowired和@Resource都基本一致。但是本着打破砂锅问到底的烦人精神,我们还是浅析了部分源码。希望本篇文章能在各位同学被面试官灵魂拷问的时候起到帮助。
下一篇文章,我们会分析spring的核心容器,ApplicationContext,我们下篇文章见。。。。