「这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战」
Resource-CommonAnnotationBeanPP
resource注解的两个可选值:
- name = "?"
- type = ?.class
其实结构是一样的:
-
找注入点(加了@Resource的)
- 这里,在findResourceMetadata里调用的buildMetadata里,如果解析到static字段被@Resource注解了,就会报错,而autowired的不会,而是直接返回。
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
这里的metadata中的Element的实现类是ResourceElement:
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();
//如果这里的resource的名字有一个set,那么名字就是从set方法里截取的
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);
}
//Object是type的默认值,这里会检查一下是否匹配
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 lazy = ae.getAnnotation(Lazy.class);
this.lazyLookup = (lazy != null && lazy.value());
}
-
字段属性注入
- 这里的inject,是通过父类来实现的
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
//这里就可以发现其实两个自动注入的PP是类似的
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable 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();
}
}
}
//而这里的getResourceToInject的实现在子类里:
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
//这里就能看到lazy的作用了:构造代理对象,和autowired的类似
//接下来就是getResource
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
//jndi,ejb相关
if (StringUtils.hasLength(element.mappedName)) {
return this.jndiFactory.getBean(element.mappedName, element.lookupType);
}
if (this.alwaysUseJndiLookup) {
return this.jndiFactory.getBean(element.name, element.lookupType);
}
if (this.resourceFactory == null) {
throw new NoSuchBeanDefinitionException(element.lookupType,
"No resource factory configured - specify the 'resourceFactory' property");
}
//正常其实就是直接到这里
return autowireResource(this.resourceFactory, element, requestingBeanName);
}
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Object resource;
Set<String> autowiredBeanNames;
String name = element.name;
//default的BF就是这个类的
if (factory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
DependencyDescriptor descriptor = element.getDependencyDescriptor();
//@Resource查找bean的核心逻辑都在这里
//这里isDefaultname,指的就是没有配,name就是属性名字的值
//就会去bean工厂中,查看是否有bean,如果没有就会resolve,和上面的方法就是相同的
//fallbackToDefaultTypeMatch,指的是之前是否通过class类型可以找到对应的bean
if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
if (resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
}
}
//这里就是上面包括了这个bean,或者注解写了name,有的话就直接从BF里获取
else {
resource = beanFactory.resolveBeanByName(name, descriptor);
autowiredBeanNames = Collections.singleton(name);
}
}
else {
resource = factory.getBean(name, element.lookupType);
autowiredBeanNames = Collections.singleton(name);
}
if (factory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
for (String autowiredBeanName : autowiredBeanNames) {
if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
}
}
}
return resource;
}
总结
依赖注入IOC选择步骤:
@Autowired
private Object resource;
-
先根据类型找bean
-
筛选:
-
candidate=true?
-
是否是泛型?
-
Qualifier?(@Qualifier,可以修饰bean,如果有的话,那么对应的@Autowired如果指明了相同的名字,会优先选择通过该注解指定的同名bean)
-
Primary是否有?
-
Priority从小到大?
-
名字
-
- autowire和resource的差别:
- autowired:
- 静态变量autowired,会直接跳过
- 先根据类型查找,再根据名字查找
- Spring提供的
- resource:
- 静态变量resource,会报错
- 先根据名字查找,再根据类型查找
- javax提供的
- autowired: