一.@Resource注解简单介绍
@Resource注解标注的属性默认按照ByName进行注入,由J2EE提供
如果我们想按照ByType注入,代码要这样写:
public class LaController {
//按类型注入
@Resource(type=)
private LaService laService;
}
复制代码
如果LaService接口存在两个实现类,且两个实现类都会被spring扫描到,在注入的时候就会报错:nested exception is
: No qualifying bean of type '' available: expected single matching bean but found 2: la2ServiceImpl,laServiceImpl
type也可以是实现类class,例如:
public class LaController {
//按类型注入
@Resource(type=)
private LaService laService;
}
复制代码
这样就会注入La2ServiceImpl实例,就不会出现上面的报错了。
二.注入源码详解
代码定位到
AbstractAutowireCapableBeanFactory类的populateBean方法
//是否有实例化相关的BeanPostProcessor
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = ();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, );
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//调用处理属性值的方法
pvs = (pvs, filteredPds, (), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
复制代码
InstantiationAwareBeanPostProcessor有一个实现类叫做CommonAnnotationBeanPostProcessor,这个类会对@Resource标注的属性进行赋值。
1.找到所有的@Resource标注的属性
利用java反射,找到类中所有的Fields,然后判断属性上是否标记了@Resource注解
if(())
复制代码
如果条件成立,就会构建一个ResourceElement出来。我们来看下ResourceElement类
private class ResourceElement extends LookupElement {
private final boolean lazyLookup;
//构造函数
public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
super(member, pd);
Resource resource = ();
//属性名字
String resourceName = ();
//属性的类型
Class<?> resourceType = ();
= !(resourceName);
if () {
resourceName = ();
if ( instanceof Method && ("set") && () > 3) {
resourceName = ((3));
}
}
else if (embeddedValueResolver != null) {
resourceName = (resourceName);
}
if ( != resourceType) {
checkResourceType(resourceType);
}
else {
// No resource type specified... check field/method.
resourceType = getResourceType();
}
= (resourceName != null ? resourceName : "");
= resourceType;
String lookupValue = ();
= ((lookupValue) ? lookupValue : ());
Lazy lazy = ();
= (lazy != null && ());
}
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return ( ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
}
复制代码
最后会将这个类中所有标注有@Resource注解的属性构造出来的ResourceElement都放到LinkedList中。最终会包装出一个注入元数据(InjectionMetadata)对象出来。
2.@Resource属性值注入
既然我们拿到了所有@Resource属性,那么循环对这些属性注入就可以了。
属性注入核心原理=反射+getBean方法。
getBean方法获取Bean对象,然后调用Field的set方法,对属性进行赋值。我们看下代码片段:
if () {
Field field = (Field) ;
(field);
(target, getResourceToInject(target, requestingBeanName));
}