1. Краткое введение в аннотацию @Resource
Свойства, отмеченные аннотацией @Resource, по умолчанию вводятся в соответствии с ByName, который предоставляется J2EE.
Если мы хотим инъектировать по ByType, то код должен быть написан так:
public class LaController {
//按类型注入
@Resource(type=LaService.class)
private LaService laService;
}
Если в интерфейсе LaService есть два класса реализации, и оба класса реализации будут сканироваться Spring, во время инъекции будет сообщено об ошибке: вложенное исключение
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.netty.use.nettyuse.service.LaService' available: expected single matching bean but found 2: la2ServiceImpl,laServiceImpl
type также может быть классом реализации, например:
public class LaController {
//按类型注入
@Resource(type=La2ServiceImpl.class)
private LaService laService;
}
Таким образом, будет внедрен экземпляр La2ServiceImpl, и указанная выше ошибка не появится.
2. Подробное объяснение исходного кода инъекции
код для
Метод populateBean класса AbstractAutowireCapableBeanFactory
//是否有实例化相关的BeanPostProcessor
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
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);
}
}
InstantiationAwareBeanPostProcessor имеет класс реализации под названием CommonAnnotationBeanPostProcessor, который присваивает значения свойствам, помеченным @Resource.
1. Найдите все аннотированные свойства @Resource
Используйте отражение Java, чтобы найти все поля в классе, а затем определить, отмечена ли аннотация @Resource в атрибуте
if(field.isAnnotationPresent(Resource.class))
Если условие истинно, 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 = ae.getAnnotation(Resource.class);
//属性名字
String resourceName = resource.name();
//属性的类型
Class<?> resourceType = resource.type();
this.isDefaultName = !StringUtils.hasLength(resourceName);
if (this.isDefaultName) {
resourceName = this.member.getName();
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
resourceName = Introspector.decapitalize(resourceName.substring(3));
}
}
else if (embeddedValueResolver != null) {
resourceName = embeddedValueResolver.resolveStringValue(resourceName);
}
if (Object.class != resourceType) {
checkResourceType(resourceType);
}
else {
// No resource type specified... check field/method.
resourceType = getResourceType();
}
this.name = (resourceName != null ? resourceName : "");
this.lookupType = resourceType;
String lookupValue = resource.lookup();
this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());
Lazy lazy = ae.getAnnotation(Lazy.class);
this.lazyLookup = (lazy != null && lazy.value());
}
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
}
Наконец, все ResourceElements, созданные из атрибутов, аннотированных аннотациями @Resource в этом классе, будут помещены в LinkedList. Наконец, объект метаданных внедрения (InjectionMetadata) будет упакован.
2. Внедрение значения атрибута @Resource
Теперь, когда у нас есть все свойства @Resource, мы можем перебрать эти свойства и внедрить их.
Основной принцип внедрения свойств = отражение + метод getBean.
Метод getBean получает объект Bean, а затем вызывает метод set Field для присвоения значений свойствам. Давайте посмотрим на фрагмент кода:
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}