@Autowired的实现类是AutowiredAnnotationBeanPostProcessor
@Resource的实现类是CommonAnnotationBeanPostProcessor,也是分两个步骤
- 解析注入点
- 注入点注入
CommonAnnotationBeanPostProcessor
找注入点
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
//找注入点
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#findResourceMetadata
private InjectionMetadata findResourceMetadata(String beanName, Class<?> clazz, @Nullable 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);
}
//构建注入点
metadata = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
private InjectionMetadata buildResourceMetadata(Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
//遍历字段
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//@WebServiceRef
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {...}
//@EJB
else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {...}
//@Resource
else if (field.isAnnotationPresent(Resource.class)) {
//@Autowired遇到静态字段不会抛异常,但是@Resource会
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, field, null));
}
}
});
//遍历方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
//@WebServiceRef
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {...}
//@EJB
else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {...}
//@Resource
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
//@Autowired遇到静态方法不会抛异常,但是@Resource会
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
//@Resource标记的方法,要求方法参数必须有且只有1个
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
@Resource注解,标记的字段、方法注入点类型都是:ResourceElement(其中方法要求入参必须有且只有一个)
且相比于@Autowired,@Resource遇到静态字段、方法会抛异常。
注入点注入
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
org.springframework.beans.factory.annotation.InjectionMetadata#inject
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
//遍历每个注入点进行依赖注入
for (InjectedElement element : elementsToIterate) {
//此时InjectedElement就是ResourceElement
element.inject(target, beanName, pvs);
}
}
}
ResourceElement的inject方法,并没有自己实现,用的是其父类的
org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement#inject
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
//反射赋值
//getResourceToInject找到注入的值
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
//反射赋值
//getResourceToInject找到注入的值
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {...}
}
}
getResourceToInject实现在ResourceElement自己
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.ResourceElement#getResourceToInject
@Resource可以指定name和type属性
private class ResourceElement extends LookupElement {
private final boolean lazyLookup;
//看getResourceToInject方法之前,先看下构造做了什么:
//member:字段或方法
public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
super(member, pd);
Resource resource = ae.getAnnotation(Resource.class);
//@Resource注解上的name和type属性
String resourceName = resource.name();
Class<?> resourceType = resource.type();
//使用@Resource时没有指定具体的name,那么isDefaultName=true
//代表使用默认的名字,默认的名字就是field的name,或setXxx()中的xxx
this.isDefaultName = !StringUtils.hasLength(resourceName);
if (this.isDefaultName) {
//field的name
resourceName = this.member.getName();
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
//方法的话,取setXxx()中的xxx
resourceName = Introspector.decapitalize(resourceName.substring(3));
}
}
//指定了具体的name,则进行占位符填充
else if (embeddedValueResolver != null) {
resourceName = embeddedValueResolver.resolveStringValue(resourceName);
}
//@Resource除开可以指定name,还可以指定type,type默认为Object
//!=Object.class 相当于自己定义了type
if (Object.class != resourceType) {
//1.如果指定了type,则验证一下和field的类型 或 set方法的第一个参数类型是否和所指定的resourceType匹配
checkResourceType(resourceType);
}
else {
// No resource type specified... check field/method.
// 没有指定的话自动获取类型
resourceType = getResourceType();
}
this.name = (resourceName != null ? resourceName : "");
//lookupType、mappedName和ejb有关
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());
}
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
//懒加载,则会先创建一个代理对象注入
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
//2.获取需要注入的对象
getResource(this, requestingBeanName));
}
}
创建一个代理对象注入,和@Autowired差不多
1. 验证type指定的类型和注入点的类型是否匹配
org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement#checkResourceType
protected final void checkResourceType(Class<?> resourceType) {
if (this.isField) {
Class<?> fieldType = ((Field) this.member).getType();
if (!(resourceType.isAssignableFrom(fieldType) || fieldType.isAssignableFrom(resourceType))) {
throw new IllegalStateException("Specified field type [" + fieldType +
"] is incompatible with resource type [" + resourceType.getName() + "]");
}
}
else {
//注意,方法的时候,只会和方法第一个入参类型进行判断(事先校验过了,方法只允许有且只有1个参数)
Class<?> paramType =
(this.pd != null ? this.pd.getPropertyType() : ((Method) this.member).getParameterTypes()[0]);
if (!(resourceType.isAssignableFrom(paramType) || paramType.isAssignableFrom(resourceType))) {
throw new IllegalStateException("Specified parameter type [" + paramType +
"] is incompatible with resource type [" + resourceType.getName() + "]");
}
}
}
2. 获取需要注入的对象
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#getResource
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
// JNDI lookup to perform?
String jndiName = null;
if (StringUtils.hasLength(element.mappedName)) {...}
else if (this.alwaysUseJndiLookup) {...}
if (jndiName != null) {...}
// Regular resource autowiring
if (this.resourceFactory == null) {...}
//根据LookupElement从BeanFactory找到合适的Bean对象
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;
//判断工厂是不是支持自动注入的工厂,默认Bean工厂就是实现这个接口的
if (factory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
DependencyDescriptor descriptor = element.getDependencyDescriptor();
//假设@Resource中没有指定name,并且field的name 或 setXxx()的xxx不存在对应的Bean
//那么则根据field类型或方法参数类型从BeanFactory中查找
//fallbackToDefaultTypeMatch:回退到默认类型匹配,默认true
//element.isDefaultName:是否是默认的名字,@Resource中没有指定name,则是true
if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
//根据类型去找Bean
resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
if (resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
}
}
else {
//2.1 根据名字解析Bean,底层也是getBean
resource = beanFactory.resolveBeanByName(name, descriptor);
autowiredBeanNames = Collections.singleton(name);
}
}
else {
//直接根据名字获取Bean
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)) {
//记录requestingBeanName依赖autowiredBeanName
//为给定bean注册一个依赖bean,以便在销毁给定bean之前销毁。
beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
}
}
}
return resource;
}
- @Resource中没有指定name并且默认的name(字段名 或 setXxx的xxx名)工厂中没有对应的Bean,才会根据类型找Bean
- @Resource如果指定了name,只会根据name找Bean
所以@Resource注解是先byName再byType
2.1 根据名字找Bean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeanByName
public Object resolveBeanByName(String name, DependencyDescriptor descriptor) {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
//getBean
return getBean(name, descriptor.getDependencyType());
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
总结
- 如果没有指定name,先根据属性、方法的名字找Bean,找不到,再根据类型去找
- 如果指定了name,只会根据名字找Bean
- @Resouce注解不是Spring提供的,java规范提供的。
Spring支持@Resouce的意义:能让任何支持@Resouce注解的框架,都能无缝替换Spring,源码不用改。