@Resource注解和@Autowired注解是咱们使用Spring的两大利器,用来进行属性注入。这篇文章来简单分析下@Resource的原理
很简单的啦,譬如如下:
@Service
public class TestService {
@Resource
ResourceLockDAO testDao;
}
Spring的生态代码过程中,在推断出类的构造方法,且根据构造方法创建实例之后,就进行了该bean的注入点查询过程。
详见AbstractAutowireCapableBeanFactory的doCreateBean方法中的applyMergedBeanDefinitionPostProcessors,看源码么,点进去!!
/**
* Apply MergedBeanDefinitionPostProcessors to the specified bean definition,
* invoking their {@code postProcessMergedBeanDefinition} methods.
* @param mbd the merged bean definition for the bean
* @param beanType the actual type of the managed bean instance
* @param beanName the name of the bean
* @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
*/
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);
}
}
}
可以看到循环调用了所有BeanPostProcessor,找到MergedBeanDefinitionPostProcessor子类,调用其postProcessMergedBeanDefinition方法,此处不累赘,我直接说了,调用的CommonAnnotationBeanPostProcessor的对应方法。细心的你可能会发现,还有个叫AutowiredAnnotationBeanPostProcessor的类也有该方法,从类名,聪明的你应该猜到,这个类的该方法是为了处理@Autowired注解。
废话不多说,咱们来看看@Resource注解查询
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
咱们主要看findResourceMetadata方法
private InjectionMetadata findResourceMetadata(String beanName, final 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(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 处理属性上的@Resource注解
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
// 如果有@WebServiceRef注解,也处理
}
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
// 如果有@EJB注解也处理
}
else if (field.isAnnotationPresent(Resource.class)) {
// 如果加了@Resource注解的field是static的,那就直接报错
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
// 把field包装一下加入到currElements里面
currElements.add(new ResourceElement(field, field, null));
}
}
});
//处理方法上的@Resource注解
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
//查找该方法的桥接方法
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
//判断桥接方法和method的方法签名是否相同
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
// 处理@WebServiceRef注解
}
else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
// 处理@EJB注解
}
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
// 静态方法如果加了@Resource注解,则报错
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
Class<?>[] paramTypes = method.getParameterTypes();
// 此处还限定了加了@Resource注解的方法必须只有一个入参
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);
// 把field和method区分开后,封装成InjectionMetaData返回findResourceMetadata方法
return new InjectionMetadata(clazz, elements);
}
在findResourceMetadata方法中,会把该InjectionMetadata放入到injectionMetadataCache中。
结构如下图:
回到AbstractAutowireCapableBeanFactory的doCreateBean方法,在设置了SingletonFactory之后,会调用populateBean方法,这个方法就是我们的属性注入方法。
populate方法执行分为几种情况:
1. 调用BeanPostProcessor类的postProcessAfterInstantiation,如果有一个返回了false,那么就会停止这个bean的属性注入。目前默认全是true,这是框架留给程序员的一个扩展点
2. 判断当前的mbd(merged bean definition)设置的自动注入mode,不过一般情况下,我们都不会设置,无非是byName或者byType
3. 查看当前的mbd有么有设置propertyValues,如果设置了,就拿上进入到最重要的实际注入逻辑
遍历所有的BeanPostProcessor,判断是不是InstantiationAwareBeanPostProcessor,然后再调用其postProcessProperties方法。聪明的你一定又猜到了此处我们实际调用的CommonAnnotationBeanPostProcessor的postProcessProperties方法。看源码吧
@Override
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;
}
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) {
// log
element.inject(target, beanName, pvs);
}
}
}
获取该mbd的所有注入点,for循环调用InjectMetadata的inject方法:
/**
* Either this or {@link #getResourceToInject} needs to be overridden.
*/
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();
}
}
}
如果是属性(field)的话,最终会调用ResourceElement的getResourceToInject方法:
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
如果加了@Lazy注解,那么先给返回一个代理对象。否则调用:
/**
* Obtain the resource object for the given name and type.
* @param element the descriptor for the annotated field/method
* @param requestingBeanName the name of the requesting bean
* @return the resource object (never {@code null})
* @throws NoSuchBeanDefinitionException if no corresponding target resource found
*/
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
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);
}
可以看到最终应该会进入autowireResource方法:
/**
* Obtain a resource object for the given name and type through autowiring
* based on the given factory.
* @param factory the factory to autowire against
* @param element the descriptor for the annotated field/method
* @param requestingBeanName the name of the requesting bean
* @return the resource object (never {@code null})
* @throws NoSuchBeanDefinitionException if no corresponding target resource found
*/
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Object resource;
Set<String> autowiredBeanNames;
String name = element.name;
if (factory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
DependencyDescriptor descriptor = element.getDependencyDescriptor();
// 如果@Resource没有配置name属性,且对应name的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");
}
}
else {
// 此处代表要注入的某个依赖已经被解析过了或者@Resource配置了name属性,就直接拿了用
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;
}
上面这处的resolveDependency方法就显得很重要了,这个方法是为了根据依赖的属性名找到依赖的bean
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
// 此处只有使用了@Qualifier注解的bean才有意义
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// 如果需要注入的类型是List,Array,Map,在此处进行处理
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 此处map的value既有可能是Class的对象,也有可能是bean,多数时候是Class的对象,非Class对象是因为注入的是
//applicationContext、BeanFactory等属性
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(descriptor.getResolvableType(), 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;
}
}
// 根据属性名获取对应的class
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();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// 大多数情况此处的判断都是true,那么就根据instanceCandidate去容器中查找或者创建bean
// 不过如果注入的属性是ApplicationContext之类的,为false,此时的instanceCandidate就是一个已经直接可用的bean
if (instanceCandidate instanceof Class) {
// resolveCandidate方法具体内容就是BeanFactory.getBean
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
返回的Object,最终会在InjectionMetadata类的inject方法中通过反射,要么是调用field.set,要么是调用method.invoke。
所以可以看到@Resource注解并不是大家传统意义说的先byName后byType。下次咱们分析@Autowired注解的源码,并进行对比。点击这里查看@Autowired注解的原理分析和两者的对比。