Spring对注解(Annotation)处理源码分析2——解析和注入注解配置的资源

1.类内部的注解,如:@Autowire、@Value、@Required、@Resource以及EJB和WebSerivce相关的注解,是容器对Bean对象实例化和依赖注入时,通过容器中注册的Bean后置处理器处理这些注解的。

2.Spring中处理注解的Bean后置处理器:

当使用Spring的注解功能时,在Spring配置文件中添加如下配置开启Spring的注解处理器:

[xhtml] 
view plain
copy

  1. <context:annotation-config>  
  2. < context:component-scan >  

 

 

上面的配置将隐式地向Spring容器注册、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor以及这4个专门用于处理注解的Bean后置处理器。

下面将具体介绍这4个注解后置处理器。

:

是Spring容器专门处理配置了自动依赖注入装配相关注解(@Autowire、@Value以及其他JSR-330注解)的Bean后置处理器,其主要功能源码如下:

(1).的构造方法:

AutowiredAnnotationBeanPostProcessor只有一个的构造方法,其源码如下:

[java] 
view plain
copy

  1. public AutowiredAnnotationBeanPostProcessor() {  
  2.         //后置处理器将处理@Autowire注解  
  3.         this.autowiredAnnotationTypes.add(Autowired.class);  
  4.         //后置处理器将处理@Value注解  
  5.         this.autowiredAnnotationTypes.add(Value.class);  
  6.         //获取当前类的类加载器  
  7.         ClassLoader cl = AutowiredAnnotationBeanPostProcessor.class.getClassLoader();  
  8.         try {  
  9.             //后置处理器将处理javax.inject.Inject JSR-330注解  
  10.             this.autowiredAnnotationTypes.add((Class<? extends Annotation>) cl.loadClass(“javax.inject.Inject”));  
  11.             logger.info(“JSR-330 ‘javax.inject.Inject’ annotation found and supported for autowiring”);  
  12.         }  
  13.         catch (ClassNotFoundException ex) {  
  14.             // JSR-330 API not available – simply skip.  
  15.         }  
  16.     }   

 

 

(2).为指定类选择其合适的构造方法:

容器对指定类进行自动依赖注入装配(autowiring)时,容器需要对Bean调用合适的构造方法创建实例对象,AutowiredAnnotationBeanPostProcessor为指定类选择相应的构造方法,源码如下:

[java] 
view plain
copy

  1. //为自动依赖注入装配Bean选择合适的构造方法  
  2. public Constructor[] determineCandidateConstructors(Class beanClass, String beanName) throws BeansException {  
  3.         //首先从容器的缓存中查找是否有指定Bean的构造方法  
  4.         Constructor[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);  
  5.         //容器缓存中没有给定类的构造方法  
  6.         if (candidateConstructors == null) {  
  7.             //线程同步以确保容器中数据一致性  
  8.             synchronized (this.candidateConstructorsCache) {  
  9.                 candidateConstructors = this.candidateConstructorsCache.get(beanClass);  
  10.                 if (candidateConstructors == null) {  
  11.                     //通过JDK反射机制,获取指定类的中所有声明的构造方法  
  12.                     Constructor[] rawCandidates = beanClass.getDeclaredConstructors();  
  13.                     //存放候选构造方法的集合  
  14.                     List<Constructor> candidates = new ArrayList<Constructor>(rawCandidates.length);  
  15.                     //autowire注解中required属性指定的构造方法  
  16.                     Constructor requiredConstructor = null;  
  17.                     //默认的构造方法  
  18.                     Constructor defaultConstructor = null;  
  19.                     //遍历所有的构造方法,检查是否添加了autowire注解,以及是否  
  20. //指定了required属性  
  21.                     for (Constructor<?> candidate : rawCandidates) {  
  22.                         //获取指定类中所有关于autowire的注解(Annotation)  
  23.                         Annotation annotation = findAutowiredAnnotation(candidate);  
  24.                         //如果指定类中有关于antowire的注解  
  25.                         if (annotation != null) {  
  26.                             //如果antowire注解中指定了required属性  
  27.                             if (requiredConstructor != null) {  
  28.                                 throw new BeanCreationException(“Invalid autowire-marked constructor: “ + candidate +  
  29.                                         “. Found another constructor with ‘required’ Autowired annotation: “ +  
  30.                                         requiredConstructor);  
  31.                             }  
  32.                             //如果autowire注解的参数列表为空  
  33.                             if (candidate.getParameterTypes().length == 0) {  
  34.                                 throw new IllegalStateException(  
  35.                                         “Autowired annotation requires at least one argument: “ + candidate);  
  36.                             }  
  37.                             //获取autowire注解中required属性值  
  38.                             boolean required = determineRequiredStatus(annotation);  
  39.                             //如果获取到autowire注解中required的属性值  
  40.                             if (required) {  
  41.                                 //如果候选构造方法集合不为空  
  42.                                 if (!candidates.isEmpty()) {  
  43.                                     throw new BeanCreationException(  
  44.                                             “Invalid autowire-marked constructors: “ + candidates +  
  45.                                             “. Found another constructor with ‘required’ Autowired annotation: “ +  
  46.                                             requiredConstructor);  
  47.                                 }  
  48.                             //当前的构造方法就是required属性所配置的构造方法  
  49.                                 requiredConstructor = candidate;  
  50.                             }  
  51.                             //将当前的构造方法添加到哦啊候选构造方法集合中  
  52.                             candidates.add(candidate);  
  53.                         }  
  54.                        //如果类中没有autowire的相关注解,并且构造方法参数列表为空  
  55.                         else if (candidate.getParameterTypes().length == 0) {  
  56.                             //当前的构造方法是默认构造方法  
  57.                             defaultConstructor = candidate;  
  58.                         }  
  59.                     }  
  60.                     //如果候选构造方法集合不为空  
  61.                     if (!candidates.isEmpty()) {  
  62.                     //如果所有的构造方法都没有配置required属性,且有默认构造方法  
  63.                         if (requiredConstructor == null && defaultConstructor != null) {  
  64.                             //将默认构造方法添加到候选构造方法列表  
  65.                             candidates.add(defaultConstructor);  
  66.                         }  
  67.                         //将候选构造方法集合转换为数组  
  68.                         candidateConstructors = candidates.toArray(new Constructor[candidates.size()]);  
  69.                     }  
  70.                     //如果候选构造方法集合为空,则创建一个空的数组  
  71.                     else {  
  72.                         candidateConstructors = new Constructor[0];  
  73.                     }  
  74.                     //将类的候选构造方法集合存放到容器的缓存中  
  75.                     this.candidateConstructorsCache.put(beanClass, candidateConstructors);  
  76.                 }  
  77.             }  
  78.         }  
  79.         //返回指定类的候选构造方法数组,如果没有返回null  
  80.         return (candidateConstructors.length > 0 ? candidateConstructors : null);  
  81.     }   

 

 

(3).AutowiredAnnotationBeanPostProcessor对方法和属性的依赖注入:

当Spring容器对配置了autowire相关注解的Bean进行依赖注入时,后置处理器对属性和对象进行自动注入处理,源码如下:

[java] 
view plain
copy

  1. //处理类中的属性  
  2.     public PropertyValues postProcessPropertyValues(  
  3.             PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {  
  4.         //获取指定类中autowire相关注解的元信息  
  5.         InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());  
  6.         try {  
  7.             //对Bean的属性进行自动注入  
  8.             metadata.inject(bean, beanName, pvs);  
  9.         }  
  10.         catch (Throwable ex) {  
  11.             throw new BeanCreationException(beanName, “Injection of autowired dependencies failed”, ex);  
  12.         }  
  13.         return pvs;  
  14.     }  
  15. //处理对象的注入  
  16.     public void processInjection(Object bean) throws BeansException {  
  17.         //获取给定Bean的Class对象  
  18.         Class<?> clazz = bean.getClass();  
  19.         //获取给定类中autowire相关注解元信息  
  20.         InjectionMetadata metadata = findAutowiringMetadata(clazz);  
  21.         try {  
  22.             //对Bean对象进行自动注入  
  23.             metadata.inject(bean, nullnull);  
  24.         }  
  25.         catch (Throwable ex) {  
  26.             throw new BeanCreationException(“Injection of autowired dependencies failed for class [“ + clazz + “]”, ex);  
  27.         }  
  28.     }  
  29. //获取给定类的autowire相关注解元信息  
  30. private InjectionMetadata findAutowiringMetadata(Class clazz) {  
  31.         //首先从容器中查找是否有给定类的autowire相关注解元信息  
  32.         InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);  
  33.         if (metadata == null) {  
  34.             synchronized (this.injectionMetadataCache) {  
  35.                 metadata = this.injectionMetadataCache.get(clazz);  
  36.                 if (metadata == null) {  
  37.                     //解析给定类autowire相关注解元信息  
  38.                     metadata = buildAutowiringMetadata(clazz);  
  39.                     //将得到的给定类autowire相关注解元信息存储在容器缓存中  
  40.                     this.injectionMetadataCache.put(clazz, metadata);  
  41.                 }  
  42.             }  
  43.         }  
  44.         return metadata;  
  45.     }  
  46.     //解析给定类autowire相关注解元信息  
  47.     private InjectionMetadata buildAutowiringMetadata(Class clazz) {  
  48.         //创建一个存放注解元信息的集合  
  49.         LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();  
  50.         Class<?> targetClass = clazz;  
  51.         //递归遍历当前类及其所有基类,解析全部注解元信息  
  52.         do {  
  53.             //创建一个存储当前正在处理类注解元信息的集合  
  54.             LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();  
  55.             //利用JDK反射机制获取给定类中所有的声明字段,获取字段上的注解信息  
  56.             for (Field field : targetClass.getDeclaredFields()) {  
  57.                 //获取给定字段上的注解  
  58.                 Annotation annotation = findAutowiredAnnotation(field);  
  59.                 if (annotation != null) {  
  60.                     //如果给定字段是静态的(Static),则直接遍历下一个字段                 if (Modifier.isStatic(field.getModifiers())) {  
  61.                         if (logger.isWarnEnabled()) {  
  62.                             logger.warn(“Autowired annotation is not supported on static fields: “ + field);  
  63.                         }  
  64.                         continue;  
  65.                     }  
  66.                     //判断注解的required属性值是否有效  
  67.                     boolean required = determineRequiredStatus(annotation);  
  68.                     //将当前字段元信息封装,添加在返回的集合中  
  69.                     currElements.add(new AutowiredFieldElement(field, required));  
  70.                 }  
  71.             }  
  72.             //利用JDK反射机制获取给定类中所有的声明方法,获取方法上的注解信息  
  73.             for (Method method : targetClass.getDeclaredMethods()) {  
  74.                 //获取给定方法上的所有注解  
  75.                 Annotation annotation = findAutowiredAnnotation(method);  
  76.                 if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {  
  77.                     //如果方法是静态的,则直接遍历下一个方法  
  78.                     if (Modifier.isStatic(method.getModifiers())) {  
  79.                         if (logger.isWarnEnabled()) {  
  80.                             logger.warn(“Autowired annotation is not supported on static methods: “ + method);  
  81.                         }  
  82.                         continue;  
  83.                     }  
  84.                     //如果方法的参数列表为空  
  85.                     if (method.getParameterTypes().length == 0) {  
  86.                         if (logger.isWarnEnabled()) {  
  87.                             logger.warn(“Autowired annotation should be used on methods with actual parameters: “ + method);  
  88.                         }  
  89.                     }  
  90.                     //判断注解的required属性值是否有效  
  91.                     boolean required = determineRequiredStatus(annotation);  
  92.                 //获取当前方法的属性描述符,即方法是可读的(readable)getter方法,  
  93. //还是可写的(writeable)setter方法  
  94.                     PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);  
  95.                     //将方法元信息封装添加到返回的元信息集合中  
  96.                     currElements.add(new AutowiredMethodElement(method, required, pd));  
  97.                 }  
  98.             }  
  99.             //将当前类的注解元信息存放到注解元信息集合中  
  100.             elements.addAll(0, currElements);  
  101.             //获取给定类的父类  
  102.             targetClass = targetClass.getSuperclass();  
  103.         }  
  104.         //如果给定类有基类,并且基类不是Object,则递归获取其基类的元信息  
  105.         while (targetClass != null && targetClass != Object.class);  
  106.         return new InjectionMetadata(clazz, elements);  
  107.     }  
  108. //获取给定对象的autowire相关注解  
  109. private Annotation findAutowiredAnnotation(AccessibleObject ao) {  
  110.         //遍历所有autowire相关的注解:@Autowire、@Value以及JSR-330等  
  111.         for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {  
  112.             //获取给定对象上的指定类型的注解  
  113.             Annotation annotation = ao.getAnnotation(type);  
  114.             if (annotation != null) {  
  115.                 return annotation;  
  116.             }  
  117.         }  
  118.         return null;  
  119.     }  

 

 

(4).AutowiredAnnotationBeanPostProcessor对字段和方法的注入:

a.AutowiredAnnotationBeanPostProcessor对字段的注入是通过AutowiredFieldElement类的inject方法实现的,源码如下:

[java] 
view plain
copy

  1. //对字段进行注入  
  2. protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {  
  3.             //获取注入元素对象  
  4.             Field field = (Field) this.member;  
  5.             try {  
  6.                 Object value;  
  7.                 //如果当前对象在容器中被缓存  
  8.                 if (this.cached) {  
  9.                     //根据Bean名称解析缓存中的字段值  
  10.                     value = resolvedCachedArgument(beanName, this.cachedFieldValue);  
  11.                 }  
  12.                 //如果当前对象没有被容器缓存  
  13.                 else {  
  14.                     //创建一个字段依赖描述符  
  15.                     DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);  
  16.                     Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);  
  17.                     //获取容器中的类型转换器  
  18.                     TypeConverter typeConverter = beanFactory.getTypeConverter();  
  19.                     //根据容器中Bean定义,解析指定的依赖关系,获取依赖对象  
  20.                     value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);  
  21.                     //线程同步,确保容器中数据一致性  
  22.                     synchronized (this) {  
  23.                         //如果当前对象没有被容器缓存  
  24.                         if (!this.cached) {  
  25.                         //获取到了当前对象的依赖对象,并且required属性为true  
  26.                             if (value != null || this.required) {  
  27.                                 this.cachedFieldValue = descriptor;  
  28.                                 //为指定Bean注册依赖Bean  
  29.                                 registerDependentBeans(beanName, autowiredBeanNames);  
  30.                                 if (autowiredBeanNames.size() == 1) {  
  31.                                     String autowiredBeanName = autowiredBeanNames.iterator().next();  
  32.                                     //如果容器中有指定名称的Bean对象  
  33.                                     if (beanFactory.containsBean(autowiredBeanName)) {  
  34.                                     //依赖对象类型和字段类型匹配,默认按类型注入  
  35.                                         if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {  
  36.                                             //创建一个依赖对象的引用,同时缓存  
  37.                                             this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName);  
  38.                                         }  
  39.                                     }  
  40.                                 }  
  41.                             }  
  42.                         //如果获取的依赖关系为null,且获取required属性为false  
  43.                             else {  
  44.                                 //将字段值的缓存设置为null  
  45.                                 this.cachedFieldValue = null;  
  46.                             }  
  47.                             //容器已经对当前字段的值缓存  
  48.                             this.cached = true;  
  49.                         }  
  50.                     }  
  51.                 }  
  52.                 //如果字段依赖值不为null  
  53.                 if (value != null) {  
  54.                     //显式使用JDK的反射机制,设置自动的访问控制权限为允许访问  
  55.                     ReflectionUtils.makeAccessible(field);  
  56.                     //为Bean对象的字段设置值  
  57.                     field.set(bean, value);  
  58.                 }  
  59.             }  
  60.             catch (Throwable ex) {  
  61.                 throw new BeanCreationException(“Could not autowire field: “ + field, ex);  
  62.             }  
  63.         }  
  64.     }  

 

 

b.AutowiredAnnotationBeanPostProcessor对字段的注入是通过AutowiredMethodElement类的inject方法实现的,源码如下:

[java] 
view plain
copy

  1. //对方法进行注入  
  2. protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {  
  3.             //如果属性被显式设置为skip,则不进行注入  
  4.             if (checkPropertySkipping(pvs)) {  
  5.                 return;  
  6.             }  
  7.             //获取注入元素对象  
  8.             Method method = (Method) this.member;  
  9.             try {  
  10.                 Object[] arguments;  
  11.                 //如果容器对当前方法缓存  
  12.                 if (this.cached) {  
  13.                     //获取缓存中指定Bean名称的方法参数  
  14.                     arguments = resolveCachedArguments(beanName);  
  15.                 }  
  16.                 //如果没有缓存  
  17.                 else {  
  18.                     //获取方法的参数列表  
  19.                     Class[] paramTypes = method.getParameterTypes();  
  20.                     //创建一个存放方法参数的数组  
  21.                     arguments = new Object[paramTypes.length];  
  22.                     DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];  
  23.                     Set<String> autowiredBeanNames = new LinkedHashSet<String>(paramTypes.length);  
  24.                     //获取容器的类型转换器  
  25.                     TypeConverter typeConverter = beanFactory.getTypeConverter();  
  26.                     for (int i = 0; i < arguments.length; i++) {  
  27.                         //创建方法参数对象  
  28.                         MethodParameter methodParam = new MethodParameter(method, i);  
  29.                     //解析方法的输入参数和返回值类型   GenericTypeResolver.resolveParameterType(methodParam, bean.getClass());  
  30.                         //为方法参数创建依赖描述符  
  31.                         descriptors[i] = new DependencyDescriptor(methodParam, this.required);  
  32.                         //根据容器中Bean定义解析依赖关系,获取方法参数依赖对象  
  33.                         arguments[i] = beanFactory.resolveDependency(  
  34.                                 descriptors[i], beanName, autowiredBeanNames, typeConverter);  
  35.                     //如果容器解析的方法参数为null,且方法required属性为false  
  36.                         if (arguments[i] == null && !this.required) {  
  37.                             //设置方法的参数列表为null  
  38.                             arguments = null;  
  39.                             break;  
  40.                         }  
  41.                     }  
  42.                     //线程同步,以确保容器中数据一致性  
  43.                     synchronized (this) {  
  44.                         //如果当前方法没有被容器缓存  
  45.                         if (!this.cached) {  
  46.                             //如果方法的参数列表不为空  
  47.                             if (arguments != null) {  
  48.                                 //为容器中缓存方法参数的对象赋值  
  49.                                 this.cachedMethodArguments = new Object[arguments.length];  
  50.                                 for (int i = 0; i < arguments.length; i++) {  
  51.                                     this.cachedMethodArguments[i] = descriptors[i];  
  52.                                 }  
  53.                                 //为指定Bean注册依赖Bean  
  54.                                 registerDependentBeans(beanName, autowiredBeanNames);  
  55.                                 //如果依赖对象集合大小等于方法参数个数  
  56.                                 if (autowiredBeanNames.size() == paramTypes.length) {  
  57.                                     Iterator<String> it = autowiredBeanNames.iterator();  
  58.                                     //为方法参数设置依赖对象  
  59.                                     for (int i = 0; i < paramTypes.length; i++) {  
  60.                                         String autowiredBeanName = it.next();  
  61.                                         //如果容器中存在指定名称的Bean对象  
  62.                                         if (beanFactory.containsBean(autowiredBeanName)) {  
  63.                                             //如果参数类型和依赖对象类型匹配  
  64.                                             if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {  
  65.     //创建一个依赖对象的引用,复制给方法相应的参数                                this.cachedMethodArguments[i] = new RuntimeBeanReference(autowiredBeanName);  
  66.                                             }  
  67.                                         }  
  68.                                     }  
  69.                                 }  
  70.                             }  
  71.                     //如果方法参数列表为null,则设置容器对该方法参数的缓存为null  
  72.                             else {  
  73.                                 this.cachedMethodArguments = null;  
  74.                             }  
  75.                             //设置容器已经对该方法缓存  
  76.                             this.cached = true;  
  77.                         }  
  78.                     }  
  79.                 }  
  80.                 //如果方法参数依赖对象不为null  
  81.                 if (arguments != null) {  
  82.                     //使用JDK的反射机制,显式设置方法的访问控制权限为允许访问  
  83.                     ReflectionUtils.makeAccessible(method);  
  84.                     //调用Bean的指定方法  
  85.                     method.invoke(bean, arguments);  
  86.                 }  
  87.             }  
  88.             catch (InvocationTargetException ex) {  
  89.                 throw ex.getTargetException();  
  90.             }  
  91.             catch (Throwable ex) {  
  92.                 throw new BeanCreationException(“Could not autowire method: “ + method, ex);  
  93.             }  
  94.         }  

 

 

beanFactory.resolveDependency和registerDependentBeans方法我们在Spring容器依赖注入源码分析中已经分析过,这里就不再具体分析。

后置处理器主要解析autowire相关的注解,即@Autowire、@Value等。

 

4.

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

(1).静态初始化块和构造函数:

[java] 
view plain
copy

  1. //WebService关于JAX-WS的相关注解  
  2. private static Class<? extends Annotation> webServiceRefClass = null;  
  3. //EJB相关的注解  
  4. private static Class<? extends Annotation> ejbRefClass = null;  
  5.     //静态初始化块  
  6.     static {  
  7.         //获取当前类的类加载器  
  8.         ClassLoader cl = CommonAnnotationBeanPostProcessor.class.getClassLoader();  
  9.         try {  
  10.             //使用类加载器加载WebService相关的类  
  11.             webServiceRefClass = (Class) cl.loadClass(“javax.xml.ws.WebServiceRef”);  
  12.         }  
  13.         catch (ClassNotFoundException ex) {  
  14.             webServiceRefClass = null;  
  15.         }  
  16.         try {  
  17.             //使用类加载器加载EJB相关的类  
  18.             ejbRefClass = (Class) cl.loadClass(“javax.ejb.EJB”);  
  19.         }  
  20.         catch (ClassNotFoundException ex) {  
  21.             ejbRefClass = null;  
  22.         }  
  23.     }   
  24. //构造方法  
  25. public CommonAnnotationBeanPostProcessor() {  
  26.         setOrder(Ordered.LOWEST_PRECEDENCE – 3);  
  27.         //设置初始的注解类型为@PostConstruct  
  28.         setInitAnnotationType(PostConstruct.class);  
  29.         //设置消耗的注解为@ PreDestroy  
  30.         setDestroyAnnotationType(PreDestroy.class);  
  31.         //当使用@Resource注解时,忽略JAX-WS的资源类型  
  32.         ignoreResourceType(“javax.xml.ws.WebServiceContext”);  
  33.     }  

 

 

从CommonAnnotationBeanPostProcessor的静态初始化块和构造方法可以看出该后置处理器主要处理EJB和WebService相关的注解,以及Bean生命周期事件的相关注解。

 

(2).CommonAnnotationBeanPostProcessor对属性值的查找:

CommonAnnotationBeanPostProcessor对普通属性的处理与AutowiredAnnotationBeanPostProcessor的处理基本相同,不同在于查找属性值的方法不同,通过autowire相关注解的required配置获取依赖的属性值,则通过对@Resource注解的解析获取属性的值,CommonAnnotationBeanPostProcessor获取属性值的主要源码:

[java] 
view plain
copy

  1. //处理属性值  
  2. public PropertyValues postProcessPropertyValues(  
  3.             PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {  
  4.         //获取@Resource注解中配置的属性值元数据  
  5.         InjectionMetadata metadata = findResourceMetadata(bean.getClass());  
  6.         try {  
  7.             //注入属性值,与AutowiredAnnotationBeanPostProcessor中处理相同  
  8.             metadata.inject(bean, beanName, pvs);  
  9.         }  
  10.         catch (Throwable ex) {  
  11.             throw new BeanCreationException(beanName, “Injection of resource dependencies failed”, ex);  
  12.         }  
  13.         return pvs;  
  14.     }  
  15.     //获取@Resource注解中配置的属性值元数据  
  16.     private InjectionMetadata findResourceMetadata(final Class clazz) {  
  17.         //首先从容器缓存中查找  
  18.         InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);  
  19.         //缓存中没有给定类的注解元信息数据  
  20.         if (metadata == null) {  
  21.             //线程同步,以确保容器中数据一致  
  22.             synchronized (this.injectionMetadataCache) {  
  23.                 metadata = this.injectionMetadataCache.get(clazz);  
  24.                 if (metadata == null) {  
  25.                     //创建一个用于存放注解元数据的集合  
  26.                     LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();  
  27.                     Class<?> targetClass = clazz;  
  28.                     //递归地的解析给定类及其所有基类的注解元信息  
  29.                     do {  
  30.                         //创建一个存放当前类注解元数据的集合  
  31.                         LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();  
  32.                        //遍历给定类中所有的字段,查找符合的注解  
  33.                         for (Field field : targetClass.getDeclaredFields()) {  
  34.                             //如果字段上配置了WebService相关的注解  
  35.                             if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {  
  36.                                 //如果字段是静态的,则注解对静态字段无效  
  37.                                 if (Modifier.isStatic(field.getModifiers())) {  
  38.                                     throw new IllegalStateException(“@WebServiceRef annotation is not supported on static fields”);  
  39.                                 }  
  40.                         //如果字段不是静态,则将当前字段封装为WebService引用元素  
  41.                                 currElements.add(new WebServiceRefElement(field, null));  
  42.                             }  
  43.                             //如果当前字段上配置了EJB相关的注解  
  44.                             else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {  
  45.                                 if (Modifier.isStatic(field.getModifiers())) {  
  46.                                     throw new IllegalStateException(“@EJB annotation is not supported on static fields”);  
  47.                                 }  
  48.                                 //将当前字段封装为EJB引用元素  
  49.                                 currElements.add(new EjbRefElement(field, null));  
  50.                             }  
  51.                             //如果当前字段上配置了@Resource注解  
  52.                             else if (field.isAnnotationPresent(Resource.class)) {  
  53.                                 if (Modifier.isStatic(field.getModifiers())) {  
  54.                                     throw new IllegalStateException(“@Resource annotation is not supported on static fields”);  
  55.                                 }  
  56.                 //如果当前自动的类型不再被忽略的Resource类型中,  
  57. //则将当前字段封装为资源元素  
  58.                                 if (!ignoredResourceTypes.contains(field.getType().getName())) {  
  59.                                     currElements.add(new ResourceElement(field, null));  
  60.                                 }  
  61.                             }  
  62.                         }  
  63.                         //遍历给定类中的所有方法,查找相关的注解  
  64.                         for (Method method : targetClass.getDeclaredMethods()) {  
  65.                             //如果方法上配置了WebService相关的注解  
  66.                             if (webServiceRefClass != null && method.isAnnotationPresent(webServiceRefClass) &&                     method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {  
  67.                                 //如方法是静态的,则注解不支持静态方法  
  68.                                 if (Modifier.isStatic(method.getModifiers())) {  
  69.                                     throw new IllegalStateException(“@WebServiceRef annotation is not supported on static methods”);  
  70.                                 }  
  71.                                 //如果方法参数个数不等于1  
  72.                                 if (method.getParameterTypes().length != 1) {  
  73.                                     throw new IllegalStateException(“@WebServiceRef annotation requires a single-arg method: “ + method);  
  74.                                 }  
  75.                                 //获取方法的属性描述  
  76.                                 PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);  
  77.                         //将当前方法对象和方法属性描述封装为WebService引用元素  
  78.                                 currElements.add(new WebServiceRefElement(method, pd));  
  79.                             }  
  80.                             //如果方法上配置了EJB相关的注解  
  81.                             else if (ejbRefClass != null && method.isAnnotationPresent(ejbRefClass) &&  
  82.                                     method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {  
  83.                                 if (Modifier.isStatic(method.getModifiers())) {  
  84.                                     throw new IllegalStateException(“@EJB annotation is not supported on static methods”);  
  85.                                 }  
  86.                                 if (method.getParameterTypes().length != 1) {  
  87.                                     throw new IllegalStateException(“@EJB annotation requires a single-arg method: “ + method);  
  88.                                 }  
  89.                                 PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);  
  90.                                 currElements.add(new EjbRefElement(method, pd));  
  91.                             }  
  92.                             //如果方法上配置了@Resource注解  
  93.                             else if (method.isAnnotationPresent(Resource.class) &&  
  94.                                     method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {  
  95.                                 if (Modifier.isStatic(method.getModifiers())) {  
  96.                                     throw new IllegalStateException(“@Resource annotation is not supported on static methods”);  
  97.                                 }  
  98.                                 Class[] paramTypes = method.getParameterTypes();  
  99.                                 if (paramTypes.length != 1) {  
  100.                                     throw new IllegalStateException(“@Resource annotation requires a single-arg method: “ + method);  
  101.                                 }  
  102.                                 if (!ignoredResourceTypes.contains(paramTypes[0].getName())) {  
  103.                                     PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);  
  104.                                     currElements.add(new ResourceElement(method, pd));  
  105.                                 }  
  106.                             }  
  107.                         }  
  108.                         //将当前类注解元信息存放到注解元信息集合中  
  109.                         elements.addAll(0, currElements);  
  110.                         //获取当前对象的基类  
  111.                         targetClass = targetClass.getSuperclass();  
  112.                     }  
  113.                     //如果基类不为null,且基类不是Object  
  114.                     while (targetClass != null && targetClass != Object.class);  
  115.                     metadata = new InjectionMetadata(clazz, elements);  
  116.                     //缓存给定类的注解元信息  
  117.                     this.injectionMetadataCache.put(clazz, metadata);  
  118.                 }  
  119.             }  
  120.         }  
  121.         return metadata;  
  122.     }  

 

 

从上面的源码中,我们可以看到,对于方法上面的注解,EJB和WebService相关注解以及@Resource只能在单个参数的方法上配置,否则会有异常抛出。

(3).根据给定名称或者类型获取资源对象:

WebService和EJB相关注解以及@Resource主要是为所添加的字段或者方法注入所需要的资源,CommonAnnotationBeanPostProcessor类中获取资源的源码如下:

[java] 
view plain
copy

  1. //根据给定名称或者类型获取资源对象  
  2. protected Object getResource(LookupElement element, String requestingBeanName) throws BeansException {  
  3.         //如果注解对象元素的mappedName属性不为空  
  4.         if (StringUtils.hasLength(element.mappedName)) {  
  5.             //根据JNDI名称和类型去Spring的JNDI容器中获取Bean  
  6.             return this.jndiFactory.getBean(element.mappedName, element.lookupType);  
  7.         }  
  8.         //如果该后置处理器的alwaysUseJndiLookup属性值为true  
  9.         if (this.alwaysUseJndiLookup) {  
  10.             //从Spring的JNDI容器中查找指定JDNI名称和类型的Bean  
  11.             return this.jndiFactory.getBean(element.name, element.lookupType);  
  12.         }  
  13.         if (this.resourceFactory == null) {  
  14.             throw new NoSuchBeanDefinitionException(element.lookupType,  
  15.                     “No resource factory configured – specify the ‘resourceFactory’ property”);  
  16.         }  
  17.     //使用autowiring自动依赖注入装配,通过给定的名称和类型从资源容器获取Bean对象  
  18.         return autowireResource(this.resourceFactory, element, requestingBeanName);  
  19.     }  
  20.     //自动依赖注入装配资源对象  
  21.     protected Object autowireResource(BeanFactory factory, LookupElement element, String requestingBeanName)  
  22.             throws BeansException {  
  23.         Object resource;  
  24.         Set<String> autowiredBeanNames;  
  25.         String name = element.name;  
  26.         if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&  
  27.                 factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {  
  28.             autowiredBeanNames = new LinkedHashSet<String>();  
  29.             //根据容器中Bean定义解析给定的依赖关系,将依赖以资源对象返回  
  30.             resource = ((AutowireCapableBeanFactory) factory).resolveDependency(  
  31.                     element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);  
  32.         }  
  33.         //根据给定JDNI名称和类型从Spring的JDNI容器查找资源  
  34.         else {  
  35.             resource = factory.getBean(name, element.lookupType);  
  36.             autowiredBeanNames = Collections.singleton(name);  
  37.         }  
  38.         //为指定的Bean注册依赖的Bean  
  39.         if (factory instanceof ConfigurableBeanFactory) {  
  40.             ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;  
  41.             for (String autowiredBeanName : autowiredBeanNames) {  
  42.                 beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);  
  43.             }  
  44.         }  
  45.         return resource;  
  46.     }  

 

 

(4).@Resource、WebService和EJB相关注解的解析和属性注入:

Spring中,@Resource注解是由类解析的,WebService相关注解是由类解析的,EJB相关注解是由EjbRefElement类解析的,下面就具体分析其解析的实现

a.ResourceElement解析@Resource注解和属性注入:

ResourceElement是Spring中用于解析@Resource注解和属性注入的类,源码如下:

[java] 
view plain
copy

  1. //解析@Resource注解  
  2. protected void initAnnotation(AnnotatedElement ae) {  
  3.             //获取元素对象的@Resource注解  
  4.             Resource resource = ae.getAnnotation(Resource.class);  
  5.             //获取@Resource注解的name属性值作为资源名称  
  6.             String resourceName = resource.name();  
  7.             //获取@Resource注解的type属性值作为资源类型  
  8.             Class resourceType = resource.type();  
  9.             //根据注解配置的资源名称是否为空,判断元素是否有默认名称  
  10.             this.isDefaultName = !StringUtils.hasLength(resourceName);  
  11.             //如果元素有默认名称  
  12.             if (this.isDefaultName) {  
  13.                 //获取元素对象名称作为资源名称  
  14.                 resourceName = this.member.getName();  
  15.                 //如果当前添加注解的对象是方法,且方法名称以set开头,且属性名称  
  16. //不为空(方法名长度大于3,即除了set之外还有其他字符)  
  17.                 if (this.member instanceof Method && resourceName.startsWith(“set”) && resourceName.length() > 3) {  
  18.                     //利用JDK的内省机制格式化对象名称,转换为Java标准的驼峰命名法  
  19.                     resourceName = Introspector.decapitalize(resourceName.substring(3));  
  20.                 }  
  21.             }  
  22.             //如果当前的容器是ConfigurableBeanFactory类型容器  
  23.             else if (beanFactory instanceof ConfigurableBeanFactory){  
  24.                 //解析给定的对象名的内嵌值做为资源名称  
  25.                 resourceName = ((ConfigurableBeanFactory) beanFactory).resolveEmbeddedValue(resourceName);  
  26.             }  
  27.             //如果注解配置的资源类型不为空,且不说Object类型  
  28.             if (resourceType != null && !Object.class.equals(resourceType)) {  
  29.                 //检查资源类型是字段还是方法  
  30.                 checkResourceType(resourceType);  
  31.             }  
  32.             else {  
  33.                 //如果注解中没有配置资源类型,则利用JDK反射机制判断是字段还是方法  
  34.                 resourceType = getResourceType();  
  35.             }  
  36.             //设置当前注解元素的资源名称  
  37.             this.name = resourceName;  
  38.             //设置当前注解元素的JNDI类型  
  39.             this.lookupType = resourceType;  
  40.             //获取@Resource注解的mappedName属性值,设置当前注解元素的JNDI名称  
  41.             this.mappedName = resource.mappedName();  
  42.         //获取@Resource注解的shareable属性值,设置当前注解元素是否在容器中共享  
  43.             this.shareable = resource.shareable();  
  44.         }  
  45.         //注入属性  
  46.         protected Object getResourceToInject(Object target, String requestingBeanName) {  
  47.             //调用我们在(3)中分析的源码,注入依赖的资源对象  
  48.             return getResource(this, requestingBeanName);  
  49.         }  

 

 

解析WebService相关的注解和属性注入:

WebServiceRefElement是Spring中用于解析WebService相关注解和属性注入的类,源码如下:

[java] 
view plain
copy

  1. //解析WebService相关的注解  
  2.         protected void initAnnotation(AnnotatedElement ae) {  
  3.             //获取元素对象上的@WebServiceRef注解  
  4.             WebServiceRef resource = ae.getAnnotation(WebServiceRef.class);  
  5.             //获取@WebServiceRef注解的name属性值作为资源名称  
  6.             String resourceName = resource.name();  
  7.             //获取@WebServiceRef注解的type属性值作为资源类型  
  8.             Class resourceType = resource.type();  
  9.             //根据资源名称是否为空判断当前元素是否有默认名称  
  10.             this.isDefaultName = !StringUtils.hasLength(resourceName);  
  11.             //如果当前元素有默认名称  
  12.             if (this.isDefaultName) {  
  13.                 //获取当前元素对象的名称作用资源名称  
  14.                 resourceName = this.member.getName();  
  15.         //如果添加注解的当前元素是方法,且方法名以set开头,且资源对象名称不为空  
  16.                 if (this.member instanceof Method && resourceName.startsWith(“set”) && resourceName.length() > 3) {  
  17. //利用JDK的内省机制,将格式化资源名称(将去掉set之后的名称首字//母小写),是资源名称符合java变量的驼峰命名规则  
  18.                     resourceName = Introspector.decapitalize(resourceName.substring(3));  
  19.                 }  
  20.             }  
  21.             //如果@WebServiceRef注解的type属性值不为空  
  22.             if (resourceType != null && !Object.class.equals(resourceType)) {  
  23.                 //根据注解配置的资源类型值检查资源对象是字段还是方法  
  24.                 checkResourceType(resourceType);  
  25.             }  
  26.             //如果@WebServiceRef注解没有配置type属性  
  27.             else {  
  28.                 //容器通过JDK的反射机制检查资源对象是字段还是方法类型  
  29.                 resourceType = getResourceType();  
  30.             }  
  31.             //将资源名称赋值给元素的名称  
  32.             this.name = resourceName;  
  33.             //为元素设置资源类型  
  34.             this.elementType = resourceType;  
  35.             //指定类型的资源可以Service被访问  
  36.             if (Service.class.isAssignableFrom(resourceType)) {  
  37.                 //设置JNDI的类型  
  38.                 this.lookupType = resourceType;  
  39.             }  
  40.             //如果指定类型的资源不能被Service访问  
  41.             else {  
  42. //根据@WebServiceRef注解的value属性值是否是Object,设置JNDI类型  
  43.                 this.lookupType = (!Object.class.equals(resource.value()) ? resource.value() : Service.class);  
  44.             }  
  45.             //获取@WebServiceRef注解的mappedName属性值,设置JNDI名称  
  46.             this.mappedName = resource.mappedName();  
  47.             //获取@WebServiceRef注解的wsdlLocation属性值,设置元素的wsdl路径  
  48.             this.wsdlLocation = resource.wsdlLocation();  
  49.         }  
  50.         //属性注入  
  51.         protected Object getResourceToInject(Object target, String requestingBeanName) {  
  52.             Service service;  
  53.             try {  
  54.                 //根据JNDI名称和类型获取指定资源对象  
  55.                 service = (Service) getResource(this, requestingBeanName);  
  56.             }  
  57.             catch (NoSuchBeanDefinitionException notFound) {  
  58.                 //如果JNDI类型是Service  
  59.                 if (Service.class.equals(this.lookupType)) {  
  60.                     throw new IllegalStateException(“No resource with name ‘” + this.name + “‘ found in context, “ +  
  61.                             “and no specific JAX-WS Service subclass specified. The typical solution is to either specify “ +  
  62.                             “a LocalJaxWsServiceFactoryBean with the given name or to specify the (generated) Service “ +  
  63.                             “subclass as @WebServiceRef(…) value.”);  
  64.                 }  
  65.                 //如果元素的wsdl路径不为空  
  66.                 if (StringUtils.hasLength(this.wsdlLocation)) {  
  67.                     try {  
  68.                         //根据wsdl获取构造方法  
  69.                         Constructor ctor = this.lookupType.getConstructor(new Class[] {URL.class, QName.class});  
  70.         //获取元素JDNI类型的@WebServiceClient注解,创建WebService客户端对象  
  71.                         WebServiceClient clientAnn = this.lookupType.getAnnotation(WebServiceClient.class);  
  72.                         if (clientAnn == null) {  
  73.                             throw new IllegalStateException(“JAX-WS Service class [“ + this.lookupType.getName() +  
  74.                                     “] does not carry a WebServiceClient annotation”);  
  75.                         }  
  76.                         //根据构造方法和wsdl文件WebService实例对象  
  77.                         service = (Service) BeanUtils.instantiateClass(ctor,  
  78.                                 new URL(this.wsdlLocation), new QName(clientAnn.targetNamespace(), clientAnn.name()));  
  79.                     }  
  80.                     catch (NoSuchMethodException ex) {  
  81.                         throw new IllegalStateException(“JAX-WS Service class [“ + this.lookupType.getName() +  
  82.                                 “] does not have a (URL, QName) constructor. Cannot apply specified WSDL location [“ +  
  83.                                 this.wsdlLocation + “].”);  
  84.                     }  
  85.                     catch (MalformedURLException ex) {  
  86.                         throw new IllegalArgumentException(  
  87.                                 “Specified WSDL location [“ + this.wsdlLocation + “] isn’t a valid URL”);  
  88.                     }  
  89.                 }  
  90.             //如果元素没有配置wsdl文件路径,则根据JNDI类型创建WebService实例  
  91.             //通过JDK的反射机制,调用合适的构造方法创建实例对象  
  92.                 else {  
  93.                     service = (Service) BeanUtils.instantiateClass(this.lookupType);  
  94.                 }  
  95.             }  
  96.             //根据资源类型创建WebService提供服务的代理对象  
  97.             return service.getPort(this.elementType);  
  98.         }  

 

 

通过上面的源码分析,我们知道Spring容器在对WebSerice进行注入时,首先通过JNDI查找容器中的实例对象,如果没有找到,则根据wsdl文件实例化WebService对象,如果没有指定wsdl文件的路径,则根据类型利用JDK的反射机制生成WebService实例对象,完成注入。

c.EjbRefElement解析EJB相关的注解和属性注入:

EjbRefElement是Spring中用于解析EJB相关注解和属性注入的类,源码如下:

[java] 
view plain
copy

  1. //解析EJB相关的注解  
  2. protected void initAnnotation(AnnotatedElement ae) {  
  3.             //获取元素上的@EJB注解  
  4.             EJB resource = ae.getAnnotation(EJB.class);  
  5.             //获取@EJB注解的beanName属性值,作为资源Bean名称  
  6.             String resourceBeanName = resource.beanName();  
  7.             //获取@EJB注解的name属性值,作为资源名称  
  8.             String resourceName = resource.name();  
  9.             //根据资源名称是否为空判断元素是否有默认名称  
  10.             this.isDefaultName = !StringUtils.hasLength(resourceName);  
  11.             //如果元素有默认名称  
  12.             if (this.isDefaultName) {  
  13.                 //获取元素对象名称作用资源名称  
  14.                 resourceName = this.member.getName();  
  15.                 //如果元素是方法,且是以set开头的方法,并且元素名称不为空  
  16.                 if (this.member instanceof Method && resourceName.startsWith(“set”) && resourceName.length() > 3) {  
  17.                     //利用JDK内省机制格式化资源名称  
  18.                     resourceName = Introspector.decapitalize(resourceName.substring(3));  
  19.                 }  
  20.             }  
  21.             //获取@EJB注解中的beanInterface属性值,作用资源类型  
  22.             Class resourceType = resource.beanInterface();  
  23.             //如果资源类型不为空,且不是Object  
  24.             if (resourceType != null && !Object.class.equals(resourceType)) {  
  25.                 //根据资源类型判断资源是字段还是方法  
  26.                 checkResourceType(resourceType);  
  27.             }  
  28.             //如果@EJB注解中没有指定资源类型  
  29.             else {  
  30.                 //利用JDK反射机制判断资源是字段还是方法类型  
  31.                 resourceType = getResourceType();  
  32.             }  
  33.             //设置元素的Bean名称为@EJB注解中配置的resourceBeanName属性值  
  34.             this.beanName = resourceBeanName;  
  35.             //设置元素名称为资源名称  
  36.             this.name = resourceName;  
  37.             //设置JNDI类型为资源类型  
  38.             this.lookupType = resourceType;  
  39.             //获取@EJB注解中的mappedName属性值,作为JDNI名称  
  40.             this.mappedName = resource.mappedName();  
  41.         }  
  42.         //属性注入  
  43.         protected Object getResourceToInject(Object target, String requestingBeanName) {  
  44.             //如果当前Bean名称不为空  
  45.             if (StringUtils.hasLength(this.beanName)) {  
  46.                 //如果容器不为null,并且容器中存在指定名称的Bean  
  47.                 if (beanFactory != null && beanFactory.containsBean(this.beanName)) {  
  48.                     //直接从本地容器中获取指定名称的Bean  
  49.                     Object bean = beanFactory.getBean(this.beanName, this.lookupType);  
  50.                     //向容器注册Bean名称  
  51.                     if (beanFactory instanceof ConfigurableBeanFactory) {  
  52.                         ((ConfigurableBeanFactory) beanFactory).registerDependentBean(this.beanName, requestingBeanName);  
  53.                     }  
  54.                     //返回从本地容器中获取到的Bean对象  
  55.                     return bean;  
  56.                 }  
  57.                 //如果元素有默认名称,且元素的JNDI名称为空  
  58.                 else if (this.isDefaultName && !StringUtils.hasLength(this.mappedName)) {  
  59.                     throw new NoSuchBeanDefinitionException(this.beanName,  
  60.                             “Cannot resolve ‘beanName’ in local BeanFactory. Consider specifying a general ‘name’ value instead.”);  
  61.                 }  
  62.             }  
  63.             //通过JNDI查找指定名称资源  
  64.             return getResource(this, requestingBeanName);  
  65.         }  
  66.     }  

 

 

从上面对@Resource、WebService和EJB相关注解解析源码的分析中,我们可以看出,Spring主要使用JDNI查找方式获取这三类注解资源,另外,由源码的“if (this.member instanceof Method&& resourceName.startsWith(“set”) && resourceName.length() > 3)”判断条件,我们可以看出这三类注解只能添加在字段上,或者set属性方法上,在get属性方法上添加这三类注解将是无法被解析的。

5.RequiredAnnotationBeanPostProcessor:

是Spring中用于处理@Required注解的,@Required注解强制要求Bean属性必须被配置,当Spring容器对Bean的属性进行依赖注入时,配置了@Required注解的属性,Spring容器会检查依赖关系是否设置,按照其主要功能分析其主要实现源码:

[java] 
view plain
copy

  1. //注入属性  
  2. public PropertyValues postProcessPropertyValues(  
  3.             PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)  
  4.             throws BeansException {  
  5.         //如果容器缓存中没有指定Bean名称  
  6.         if (!this.validatedBeanNames.contains(beanName)) {  
  7.             //如果指定Bean定义中没有设置skipRequiredCheck属性  
  8.             if (!shouldSkip(this.beanFactory, beanName)) {  
  9.                 List<String> invalidProperties = new ArrayList<String>();  
  10.                 //遍历所有属性  
  11.                 for (PropertyDescriptor pd : pds) {  
  12.                 //如果属性添加了@Required注解,且属性集合中不包含指定名称的属性  
  13.                     if (isRequiredProperty(pd) && !pvs.contains(pd.getName())) {  
  14.                         //当前属性为无效的属性  
  15.                         invalidProperties.add(pd.getName());  
  16.                     }  
  17.                 }  
  18.                 //如果无效属性集合不为空  
  19.                 if (!invalidProperties.isEmpty()) {  
  20.                     throw new BeanInitializationException(buildExceptionMessage(invalidProperties, beanName));  
  21.                 }  
  22.             }  
  23.             //将Bean名称缓存到容器中  
  24.             this.validatedBeanNames.add(beanName);  
  25.         }  
  26.         //返回经过验证的属性值  
  27.         return pvs;  
  28.     }  
  29. //检查给定属性上是否添加了@Required注解  
  30. protected boolean isRequiredProperty(PropertyDescriptor propertyDescriptor) {  
  31.         //获取给定属性的写方法(setter方法)  
  32.         Method setter = propertyDescriptor.getWriteMethod();  
  33.         //检查给定属性方法上是否存在指定类型的注解  
  34.         return (setter != null && AnnotationUtils.getAnnotation(setter, getRequiredAnnotationType()) != null);  
  35.     }  

 

 

6.

PersistenceAnnotationBeanPostProcessor是Spring中用于处理JPA相关注解的Bean后置处理器,主要解析和处理@PersistenceUnit、@PersistenceContext注解,其主要作用是为JPA的实体管理器工厂(EntityManagerFactory)和实体管理器(EntityManager)注入相应的持久化单元(PersistenceUnit)或持久化上下文(PersistenceContext)。按照其主要功能分析其主要实现源码:

(1).处理和查找持久化元信息:

[java] 
view plain
copy

  1. //处理持久化相关属性  
  2. public PropertyValues postProcessPropertyValues(  
  3.             PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {  
  4.         //查找给定类中持久化元信息  
  5.         InjectionMetadata metadata = findPersistenceMetadata(bean.getClass());  
  6.         try {  
  7.             //为Bean注入持久化属性  
  8.             metadata.inject(bean, beanName, pvs);  
  9.         }  
  10.         catch (Throwable ex) {  
  11.             throw new BeanCreationException(beanName, “Injection of persistence dependencies failed”, ex);  
  12.         }  
  13.         return pvs;  
  14.     }  
  15. //查找给定类中的持久化元信息  
  16.  private InjectionMetadata findPersistenceMetadata(final Class clazz) {  
  17.         //首先从容器缓存中查找给定类的元信息  
  18.         InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);  
  19.         //容器缓存中没有给定类的元信息  
  20.         if (metadata == null) {  
  21.             //线程同步,以确保容器中数据的一致性  
  22.             synchronized (this.injectionMetadataCache) {  
  23.                 metadata = this.injectionMetadataCache.get(clazz);  
  24.                 if (metadata == null) {  
  25.                     //创建一个存储所有注入元信息的集合  
  26.                     LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();  
  27.                     Class<?> targetClass = clazz;  
  28.                     //递归遍历给定类及其所有非Object类型的基类  
  29.                     do {  
  30.                         //创建一个存储当前类注入信息的集合  
  31.                         LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();  
  32.                        //遍历给定类的所有声明字段  
  33.                         for (Field field : targetClass.getDeclaredFields()) {  
  34.                             //获取当前字段上的@PersistenceContext注解  
  35.                             PersistenceContext pc = field.getAnnotation(PersistenceContext.class);  
  36.                             //获取当前字段上的@PersistenceUnit注解  
  37.                             PersistenceUnit pu = field.getAnnotation(PersistenceUnit.class);  
  38.             //当前字段上配置了@PersistenceContext或者@PersistenceUnit注解  
  39.                             if (pc != null || pu != null) {  
  40.                                 //持久化注解不支持在静态字段上配置  
  41.                                 if (Modifier.isStatic(field.getModifiers())) {  
  42.                                     throw new IllegalStateException(“Persistence annotations are not supported on static fields”);  
  43.                                 }  
  44.                         //将配置了持久化注解的字段添加到当前类的注入元信息集合中  
  45.                                 currElements.add(new PersistenceElement(field, null));  
  46.                             }  
  47.                         }  
  48.                         //遍历给定类的所有声明方法  
  49.                         for (Method method : targetClass.getDeclaredMethods()) {  
  50.                             //获取当前方法上的@PersistenceContext注解  
  51.                             PersistenceContext pc = method.getAnnotation(PersistenceContext.class);  
  52.                             //获取当前方法上的@PersistenceUnit注解  
  53.                             PersistenceUnit pu = method.getAnnotation(PersistenceUnit.class);  
  54. //当前方法上配置了@PersistenceContext或者@PersistenceUnit注解  
  55.                             if (pc != null || pu != null &&  
  56.                                 //静态方法上不支持配置持久化注解   method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {  
  57.                                 if (Modifier.isStatic(method.getModifiers())) {  
  58.                                     throw new IllegalStateException(“Persistence annotations are not supported on static methods”);  
  59.                                 }  
  60.                                //持久化注解只能配置了只有一个参数的方法上  
  61.                                 if (method.getParameterTypes().length != 1) {  
  62.                                     throw new IllegalStateException(“Persistence annotation requires a single-arg method: “ + method);  
  63.                                 }  
  64.                                 //获取当前方法的属性描述符  
  65.                                 PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);  
  66.                         //将配置了持久化注解的方法添加到当前类的注入元信息集合中  
  67.                                 currElements.add(new PersistenceElement(method, pd));  
  68.                             }  
  69.                         }  
  70.                         //将当前类的注入元信息添加到注入元信息集合中  
  71.                         elements.addAll(0, currElements);  
  72.                         //获取当前类的基类  
  73.                         targetClass = targetClass.getSuperclass();  
  74.                     }  
  75.                     //当前类的基类不为null,且不是Object,递归注入基类元信息  
  76.                     while (targetClass != null && targetClass != Object.class);  
  77.                     metadata = new InjectionMetadata(clazz, elements);  
  78.                     //向容器中缓存给定类的注入元信息  
  79.                     this.injectionMetadataCache.put(clazz, metadata);  
  80.                 }  
  81.             }  
  82.         }  
  83.         //返回查找到的注入元信息  
  84.         return metadata;  
  85.     }  

 

 

(2).根据持久化单元名称获取持久化上下文、持久化单元和实体管理器工厂:

PersistenceAnnotationBeanPostProcessor最重要的核心功能就是根据持久化单元名称获取相应的持久化上下文,持久化单元或者实体管理器工厂,源码如下:

[java] 
view plain
copy

  1. //根据持久化单元名称获取实体管理器工厂  
  2. protected EntityManagerFactory getPersistenceUnit(String unitName) {  
  3.         //如果持久化单元不为null  
  4.         if (this.persistenceUnits != null) {  
  5.             //获取持久化单元名称  
  6.             String unitNameForLookup = (unitName != null ? unitName : “”);  
  7.             //如果持久化单元名称为空  
  8.             if (“”.equals(unitNameForLookup)) {  
  9.                 //将默认的持久化单元名称作为持久化单元名称  
  10.                 unitNameForLookup = this.defaultPersistenceUnitName;  
  11.             }  
  12.             //获取持久化单元的JNDI名称  
  13.             String jndiName = this.persistenceUnits.get(unitNameForLookup);  
  14.             if (jndiName == null && “”.equals(unitNameForLookup) && this.persistenceUnits.size() == 1) {  
  15.                 //从持久化单元中获取JNDI名称  
  16.                 jndiName = this.persistenceUnits.values().iterator().next();  
  17.             }  
  18.             if (jndiName != null) {  
  19.                 try {  
  20.                     //查找指定JNDI名称的实体管理器工厂  
  21.                     return lookup(jndiName, EntityManagerFactory.class);  
  22.                 }  
  23.                 catch (Exception ex) {  
  24.                     throw new IllegalStateException(“Could not obtain EntityManagerFactory [“ + jndiName + “] from JNDI”, ex);  
  25.                 }  
  26.             }  
  27.         }  
  28.         return null;  
  29.     }  
  30. //查找给定持久化单元名称的实体管理器  
  31.     protected EntityManager getPersistenceContext(String unitName, boolean extended) {  
  32.         //获取持久化上下文  
  33.         Map<String, String> contexts = (extended ? this.extendedPersistenceContexts : this.persistenceContexts);  
  34.         //持久化上下文不为null  
  35.         if (contexts != null) {  
  36.             String unitNameForLookup = (unitName != null ? unitName : “”);  
  37.             if (“”.equals(unitNameForLookup)) {  
  38.                 unitNameForLookup = this.defaultPersistenceUnitName;  
  39.             }  
  40.             //从持久化上下文中获取给定持久化单元名称的JNDI  
  41.             String jndiName = contexts.get(unitNameForLookup);  
  42.             if (jndiName == null && “”.equals(unitNameForLookup) && contexts.size() == 1) {  
  43.                 jndiName = contexts.values().iterator().next();  
  44.             }  
  45.             if (jndiName != null) {  
  46.                 try {  
  47.                     //查找指定JNDI名称的实体管理器  
  48.                     return lookup(jndiName, EntityManager.class);  
  49.                 }  
  50.                 catch (Exception ex) {  
  51.                     throw new IllegalStateException(“Could not obtain EntityManager [“ + jndiName + “] from JNDI”, ex);  
  52.                 }  
  53.             }  
  54.         }  
  55.         return null;  
  56.     }  
  57.     //从Spring容器中查找给定名称的实体管理器工厂  
  58.     protected EntityManagerFactory findEntityManagerFactory(String unitName, String requestingBeanName)  
  59.             throws NoSuchBeanDefinitionException {  
  60.         //当前Spring容器为null  
  61.         if (this.beanFactory == null) {  
  62.             throw new IllegalStateException(“ListableBeanFactory required for EntityManagerFactory bean lookup”);  
  63.         }  
  64.         //获取持久化单元名称  
  65.         String unitNameForLookup = (unitName != null ? unitName : “”);  
  66.         //如果持久化单元名称为空,则将容器默认持久化单元名称作用持久化单元名称  
  67.         if (“”.equals(unitNameForLookup)) {  
  68.             unitNameForLookup = this.defaultPersistenceUnitName;  
  69.         }  
  70.         //如果持久化单元名称不为空,查找给定持久化单元名称的实体管理器工厂  
  71.         if (!“”.equals(unitNameForLookup)) {  
  72.             return findNamedEntityManagerFactory(unitNameForLookup, requestingBeanName);  
  73.         }  
  74.         //如果持久化单元名称为空,获取容器中默认的实体管理器工厂  
  75.         else {  
  76.             return findDefaultEntityManagerFactory(requestingBeanName);  
  77.         }  
  78.     }  
  79. //查找给定持久化单元名称的实体管理器工厂  
  80. protected EntityManagerFactory findNamedEntityManagerFactory(String unitName, String requestingBeanName)  
  81.             throws NoSuchBeanDefinitionException {  
  82.         //从Spring所有容器中查找给定名称的实体管理器工厂对象  
  83.         EntityManagerFactory emf = EntityManagerFactoryUtils.findEntityManagerFactory(this.beanFactory, unitName);  
  84.         //将持久化单元名称和查找到的实体管理器工厂对象向Spring容器注册  
  85.         if (this.beanFactory instanceof ConfigurableBeanFactory) {  
  86.             ((ConfigurableBeanFactory) this.beanFactory).registerDependentBean(unitName, requestingBeanName);  
  87.         }  
  88.         return emf;  
  89.     }  
  90.     //获取容器默认的实体管理器工厂  
  91.     protected EntityManagerFactory findDefaultEntityManagerFactory(String requestingBeanName)  
  92.             throws NoSuchBeanDefinitionException{  
  93.         //从Spring所有容器中查找给定类型的Bean的名称  
  94.         String[] beanNames =  
  95.     BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, EntityManagerFactory.class);  
  96.         //如果从Spring容器中刚好查找到一个Bean名称  
  97.         if (beanNames.length == 1) {  
  98.             //持久化单元名称就是查找到的Bean名称  
  99.             String unitName = beanNames[0];  
  100.             //从Spring容器中查找给定持久化单元名称的实体管理器工厂Bean  
  101.             EntityManagerFactory emf = (EntityManagerFactory) this.beanFactory.getBean(unitName);  
  102.             //将查找到的实体管理器工厂Bean和持久化单元名称向Spring容器注册  
  103.             if (this.beanFactory instanceof ConfigurableBeanFactory) {  
  104.                 ((ConfigurableBeanFactory) this.beanFactory).registerDependentBean(unitName, requestingBeanName);  
  105.             }  
  106.             return emf;  
  107.         }  
  108.         else {  
  109.             throw new NoSuchBeanDefinitionException(  
  110.                     EntityManagerFactory.class“expected single bean but found “ + beanNames.length);  
  111.         }  
  112.     }  

 

 

(3).

类是Spring中用于解析持久化相关注解,并提供相应的实体管理器工厂或者实体管理器,PersistenceElement解析持久化相关注解的源码如下:

[java] 
view plain
copy

  1. //解析持久化注解  
  2. public PersistenceElement(Member member, PropertyDescriptor pd) {  
  3.             super(member, pd);  
  4.             //获取当前元素对象  
  5.             AnnotatedElement ae = (AnnotatedElement) member;  
  6.             //获取当前元素对象的@PersistenceContext注解  
  7.             PersistenceContext pc = ae.getAnnotation(PersistenceContext.class);  
  8.             //获取当前元素对象的@PersistenceUnit注解  
  9.             PersistenceUnit pu = ae.getAnnotation(PersistenceUnit.class);  
  10.             //资源类型为实体管理器  
  11.             Class resourceType = EntityManager.class;  
  12.             //如果元素配置的持久化上下文不为null  
  13.             if (pc != null) {  
  14.                 //如果元素配置的持久化单元也不为null  
  15.                 if (pu != null) {  
  16.                     //持久化上下文和持久化单元只能二选一,不能同时配置  
  17.                     throw new IllegalStateException(“Member may only be annotated with either “ +  
  18.                             “@PersistenceContext or @PersistenceUnit, not both: “ + member);  
  19.                 }  
  20.                 Properties properties = null;  
  21.                 //获取持久化上下文的属性  
  22.                 PersistenceProperty[] pps = pc.properties();  
  23.                 //如果持久化上下文属性不为空  
  24.                 if (!ObjectUtils.isEmpty(pps)) {  
  25.                     properties = new Properties();  
  26.                     //将持久化上下文的属性名称和属性值保存到属性集合中  
  27.                     for (PersistenceProperty pp : pps) {  
  28.                         properties.setProperty(pp.name(), pp.value());  
  29.                     }  
  30.                 }  
  31.                 //设置元素的持久化单元名称  
  32.                 this.unitName = pc.unitName();  
  33.                 //设置元素的持久化类型为实体管理器(EntityManager)  
  34.                 this.type = pc.type();  
  35.                 //设置元素的持久化属性  
  36.                 this.properties = properties;  
  37.             }  
  38.             //如果持久化上下文为null  
  39.             else {  
  40.                 //持久化资源类型为实体管理器工厂  
  41.                 resourceType = EntityManagerFactory.class;  
  42.                 this.unitName = pu.unitName();  
  43.             }  
  44.             //检查给定的持久化资源类型是字段还是方法类型  
  45.             checkResourceType(resourceType);  
  46.         }  

 

 

从上面的源码我们可以看到,当配置了持久化上下文时,容器会自动选择实体管理器作用持久化资源类型,如果配置了持久化单元时,选择实体管理器工厂作为持久化资源类型。

(4).获取并注入持久化资源:

PersistenceElement类对持久化注解解析获取到基本的持久化信息之后,就可以根据注解配置的持久化信息获取并注入相应的持久化资源,源码如下:

[java] 
view plain
copy

  1. //获取并注入持久化资源  
  2. protected Object getResourceToInject(Object target, String requestingBeanName) {  
  3.             //持久化资源类型不为null,创建实体管理器  
  4.             if (this.type != null) {  
  5.                 return (this.type == PersistenceContextType.EXTENDED ?  
  6.                         resolveExtendedEntityManager(target, requestingBeanName) :  
  7.                         resolveEntityManager(requestingBeanName));  
  8.             }  
  9.             //持久化资源类型为null,创建实体管理器工厂  
  10.             else {  
  11.                 return resolveEntityManagerFactory(requestingBeanName);  
  12.             }  
  13.         }  
  14. //创建扩展的实体管理器  
  15. private EntityManager resolveExtendedEntityManager(Object target, String requestingBeanName) {  
  16.             //以持久化单元名称作为JNDI名称获取持久化上下文作为实体管理器  
  17.             EntityManager em = getPersistenceContext(this.unitName, true);  
  18.             //如果根据JNDI获取到的持久化上下文为null  
  19.             if (em == null) {  
  20.                 //以持久化单元名称作为JNDI名称获取实体管理器工厂  
  21.                 EntityManagerFactory emf = getPersistenceUnit(this.unitName);  
  22.                 //没有获取到指定JNDI名称的实体管理器工厂  
  23.                 if (emf == null) {  
  24.                     //根据持久化单元名称向Spring容器查找指定名称的实体管理器工厂  
  25.                     emf = findEntityManagerFactory(this.unitName, requestingBeanName);  
  26.                 }  
  27.                 //根据实体管理器工厂和持久化属性创建一个容器管理的实体管理器  
  28.                 em = ExtendedEntityManagerCreator.createContainerManagedEntityManager(emf, this.properties);  
  29.             }     
  30.             //创建实体管理器代理委派调用的实体管理器  
  31.             if (em instanceof EntityManagerProxy &&  
  32.                     beanFactory != null && !beanFactory.isPrototype(requestingBeanName)) {  
  33.                 extendedEntityManagersToClose.put(target, ((EntityManagerProxy) em).getTargetEntityManager());  
  34.             }  
  35.             return em;  
  36.         }  
  37.     }  
  38. //创建实体管理器  
  39. private EntityManager resolveEntityManager(String requestingBeanName) {  
  40.             //以持久化单元名称作为JNDI名称获取持久化上下文作为实体管理器           EntityManager em = getPersistenceContext(this.unitName, false);  
  41.             //如果根据JNDI获取到的持久化上下文为null  
  42.             if (em == null) {  
  43.                 //以持久化单元名称作为JNDI名称获取实体管理器工厂  
  44.                 EntityManagerFactory emf = getPersistenceUnit(this.unitName);  
  45.                 //没有获取到指定JNDI名称的实体管理器工厂  
  46.                 if (emf == null) {  
  47.                     //根据持久化单元名称向Spring容器查找指定名称的实体管理器工厂  
  48.                     emf = findEntityManagerFactory(this.unitName, requestingBeanName);  
  49.                 }  
  50.                 //创建一个共享事务管理的实体管理器代理  
  51.                 if (emf instanceof EntityManagerFactoryInfo &&  
  52.                         ((EntityManagerFactoryInfo) emf).getEntityManagerInterface() != null) {  
  53.                     //根据JPA实现提供商类型创建相应的实体管理器  
  54.                     em = SharedEntityManagerCreator.createSharedEntityManager(emf, this.properties);  
  55.                 }  
  56.                 else {  
  57.                     //根据持久化注解配置的持久化资源类型创建实体管理器  
  58.                     em = SharedEntityManagerCreator.createSharedEntityManager(emf, this.properties, getResourceType());  
  59.                 }  
  60.             }  
  61.             return em;  
  62.         }   
  63. //创建实体管理器工厂  
  64. private EntityManagerFactory resolveEntityManagerFactory(String requestingBeanName) {  
  65.             //以持久化单元名称作为JNDI名称获取实体管理器工厂         EntityManagerFactory emf = getPersistenceUnit(this.unitName);  
  66.             //没有获取到指定JNDI名称的实体管理器工厂  
  67.             if (emf == null) {  
  68.                 //根据持久化单元名称向Spring容器查找指定名称的实体管理器工厂  
  69.                 emf = findEntityManagerFactory(this.unitName, requestingBeanName);  
  70.             }  
  71.             return emf;  
  72.         }  

 

Spring中还有其他处理注解的Bean后置处理器,其基本的实现原理与上面分析的这4个最常用的注解Bean后置处理器类似,注解其实也没什么神秘的,和XML配置文件类似都是一种配置的方式而已,只不过利用JDK的反射机制,在编译时或者运行时动态获取所配置的信息而已,注解本身只是个标识,注解的真正意义在于通过注解标识获取注解所在对象的信息以及注解中配置的信息。

Spring的注解方式只是简化了XML配置文件,可以在读入Bean定义资源时可以动态扫描给定的路径,在解析和依赖注入时,XML方式配置的Bean,Spring需要解析XML文件,注解方式配置的Bean,Spring需要通过JDK的反射机制获取注解配置的信息。

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/lcczzu/article/details/46908301
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞