@Resource 的注入原理分析

前言:上一篇 @Autowired 的注入原理分析 讲了@Autowired的注入是由AutowiredAnnotationBeanPostProcessor完成的,而@Resource 的注入过程是由 CommonAnnotationBeanPostProcessor  完成的。

 

是Spring中用于处理JavaEE5中常用注解(主要是EJB相关的注解)和Java6中关于JAX-WS相关的注解,可以处理PostConstruct、@PreDestroy等Bean生命周期相关事件的注解,该后置处理最核心的是处理@Resource注解,同时还可以处理JAX-WS相关的注解,按照

 准备以下代码:

@Service
public class BeanC {
    @Resource
    private BeanD beanD;
    
}

 

@Service
public class BeanD {
}

xml文件:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:content="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <content:component-scan base-package="com.spring.day_1.bean"/>


</beans>

xml工厂(没有@Resource的处理功能的)

 

public class xmlBeanFactory {

    public static void main(String[] args) {

        XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("xmlBeanFactory.xml"));

        BeanC beanc = (BeanC) beanFactory.getBean("beanC");

        System.out.println("stop");


    }

目录结构:

debug后查看beanC;

 

修改代码:

public class xmlBeanFactory {

    public static void main(String[] args) {

        XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("xmlBeanFactory.xml"));

        CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor = new CommonAnnotationBeanPostProcessor();

        commonAnnotationBeanPostProcessor.setResourceFactory(beanFactory);

        commonAnnotationBeanPostProcessor.setBeanFactory(beanFactory);

        beanFactory.addBeanPostProcessor(commonAnnotationBeanPostProcessor);

        BeanA beanA = (BeanA) beanFactory.getBean("beanA");

        BeanB beanB = (BeanB) beanFactory.getBean("beanB");

        BeanC beanc = (BeanC) beanFactory.getBean("beanC");

        System.out.println("stop");


    }


}

 

现在就注入成功了。

过程分析:

关于postProcessPropertyValues 这个方法的执行时机可以参考spring-postProcessor的执行时机 这篇文章

 

public PropertyValues postProcessPropertyValues(
      PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
    //找出@Resource 的filed 和 method
   InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
   try {
     //注入属性值,与AutowiredAnnotationBeanPostProcessor中处理相同  
      metadata.inject(bean, beanName, pvs);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
   }
   return pvs;
}

 

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) {
   LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
   Class<?> targetClass = clazz;

   do {
      final LinkedList<InjectionMetadata.InjectedElement> currElements =
            new LinkedList<>();

      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 (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
            if (Modifier.isStatic(field.getModifiers())) {
               throw new IllegalStateException("@EJB annotation is not supported on static fields");
            }
            currElements.add(new EjbRefElement(field, field, null));
         }
         else if (field.isAnnotationPresent(Resource.class)) {
            // 不能是static 修饰的 filed
            if (Modifier.isStatic(field.getModifiers())) {
               throw new IllegalStateException("@Resource annotation is not supported on static fields");
            }
            if (!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))) {
            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 (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
               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)) {
                //同样不能是static的
               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 (!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 new InjectionMetadata(clazz, elements);
}
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()) {
      boolean debug = logger.isDebugEnabled();
      for (InjectedElement element : elementsToIterate) {
         if (debug) {
            logger.debug("Processing injected element of bean '" + beanName + "': " + element);
         }
         element.inject(target, beanName, 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();
      }
   }
}
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
   return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
         getResource(this, requestingBeanName));
}
protected Object getResource(LookupElement element, @Nullable String requestingBeanName) throws BeansException {
   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 BeansException {

   Object resource;
   Set<String> autowiredBeanNames;
   String name = element.name;

   if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&
         factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {
      autowiredBeanNames = new LinkedHashSet<>();
      resource = ((AutowireCapableBeanFactory) factory).resolveDependency(
            element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
      if (resource == null) {
         throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
      }
   }
   else {
      resource = factory.getBean(name, element.lookupType);
       //使用autowiring自动依赖注入装配,通过给定的名称和类型从资源容器获取Bean对象  
      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;
}

 

注入过程和@Autowired差不多。

 

结束。

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值