@Resource注解底层工作流程图
@Resource自动注入
@Resource实现的子类是CommonAnnotationBeanPostProcessor。和@Autowired一样,CommonAnnotationBeanPostProcessor也是先执行postProcessMergedBeanDefinition方法,后续再执行postProcessProperties。而postProcessMergedBeanDefinition同样时先找注入点然后缓存起来,postProcessProperties把缓存的注入点找出来进行依赖注入处理。
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
//获取找到的注入点(被@resource标记的属性或者方法)
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
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);
}
//在注入点 被@resource标记的
//核心方法
metadata = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
private InjectionMetadata buildResourceMetadata(final 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<>();
//在do while中遍历字段 调用lambda表达式
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//不用管
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
currElements.add(new WebServiceRefElement(field, field, null));
}
else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, field, null));
}
//找到被@resource标记的字段 加入到currElements这个集合中
else if (field.isAnnotationPresent(Resource.class)) {
//如果@resource标记的是静态资源 会抛异常
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
//构造ResourceElement 构造的时候回解析@resource的属性值 比如name type 和 有没有懒加载
currElements.add(new ResourceElement(field, field, null));
}
}
});
//在do while中遍历方法 调用lambda表达式
//也是寻找被@resource标记的方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
}
else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
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);
}
这部分和@Autowired差不多,通过反射获取到bean的属性和方法,通过判断有没有@Resource注解,有的话判断一些其他条件,然后把符合的封装一层缓存起来。
到了属性填充阶段执行postProcessProperties
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//获取找到的注入点(被@resource标记的属性或者方法)
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
//属性注入 调用的是InjectedElement的inject
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);
// getResourceToInject 核心方法 通过属性找到对应的bean
// 调的是ResourceElement的getResourceToInject
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
//通过方法参数找到对应的bean
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
这部分流程就是拿到之前缓存的注入点开始注入。判断是不是懒加载,如果是懒加载生成代理类。如果不是懒加载,判断容器是否存在注入点名字的bean或者@Resource有没有指定name属性,如果满足其中一个条件,会执行getBean(name)方法获取bean。如果不满足就和@Autowired现根据类型找bean,再根据name确定bean。
依赖注入总结
- 先根据spring的自动注入就是@Bean(autowire = Autowire,BY_TYPE) 进行判断。这个方法已经过期,一般不会触发这个判断,可以忽略。
- 在BeanDefinition后置处理的时候开始找注入点,对于被 @Autowired、@Value、@Inject、@Resource注解标记的方法或属性
- 属性填充阶段开始属性注入,找出之前缓存的注入点,处理@Value、再处理@Autowired
- @Autowired先根据类型在容器和父容器中找到符合类型的bean的名称,通过一个责任链模式(涉及@Qualifier的处理)去过滤不符合的bean的名称,
- 如果只有一个bean就直接返回,如果找到多个bean,判断@Primary 在判断@Priority 。如果还有多个在根据名称筛选唯一一个。
- 然后根据筛选处来的beanName实例化bean,通过反射赋值给目标对象。
- 如果注入点上标注的注解是@Resource,判断容器是否存在注入点名字的bean或者@Resource有没有指定name属性。如果满足其中一个条件,会执行getBean(name)方法获取bean。
- 如果不满足上述条件,就执行和@Autowired一样的逻辑