Java-Spring各种依赖注入注解的区别.doc_第1页
Java-Spring各种依赖注入注解的区别.doc_第2页
Java-Spring各种依赖注入注解的区别.doc_第3页
Java-Spring各种依赖注入注解的区别.doc_第4页
Java-Spring各种依赖注入注解的区别.doc_第5页
已阅读5页,还剩18页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Spring对于Bean的依赖注入,支持多种注解方式:Resourcejavax.annotationJSR250 (Common Annotations for Java)Injectjavax.injectJSR330 (Dependency Injection for Java)Autowiredorg.springframework.bean.factorySpring直观上看起来,Autowired是Spring提供的注解,其他几个都是JDK本身内建的注解,Spring对这些注解也进行了支持。但是使用起来这三者到底有什么区别呢?笔者经过方法的测试,发现一些有意思的特性。区别总结如下:一、Autowired有个required属性,可以配置为false,这种情况下如果没有找到对应的bean是不会抛异常的。Inject和Resource没有提供对应的配置,所以必须找到否则会抛异常。二、 Autowired和Inject基本是一样的,因为两者都是使用AutowiredAnnotationBeanPostProcessor来处理依赖注入。但是Resource是个例外,它使用的是CommonAnnotationBeanPostProcessor来处理依赖注入。当然,两者都是BeanPostProcessor。Autowired和Inject- 默认 autowired by type- 可以 通过Qualifier 显式指定 autowired by qualifier name。- 如果 autowired by type 失败(找不到或者找到多个实现),则退化为autowired by field nameResource- 默认 autowired by field name- 如果 autowired by field name失败,会退化为 autowired by type- 可以 通过Qualifier 显式指定 autowired by qualifier name- 如果 autowired by qualifier name失败,会退化为 autowired by field name。但是这时候如果 autowired by field name失败,就不会再退化为autowired by type了。TIPS Qualified name VS Bean name在Spring设计中,Qualified name并不等同于Bean name,后者必须是唯一的,但是前者类似于tag或者group的作用,对特定的bean进行分类。可以达到getByTag(group)的效果。对于XML配置的bean,可以通过id属性指定bean name(如果没有指定,默认使用类名首字母小写),通过标签指定qualifier name: 如果是通过注解方式,那么可以通过Qualifier注解指定qualifier name,通过Named或者Component(Service,Repository等)的value值指定bean name:Component(lamborghini)Qualifier(luxury)public class Lamborghini implements Car 或者ComponentNamed(lamborghini)Qualifier(luxury)public class Lamborghini implements Car 同样,如果没有指定bean name,那么Spring会默认是用类名首字母小写(Lamborghini=lamborghini)。三、 通过Anotation注入依赖的方式在XML注入方式之前进行。如果对同一个bean的依赖同时使用了两种注入方式,那么XML的优先。但是不同担心通过Anotation注入的依赖没法注入XML中配置的bean,依赖注入是在bean的注册之后进行的。四、目前的autowired by type方式(笔者用的是3.2.3.RELEASE版本),Spring的AutowiredAnnotationBeanPostProcessor实现都是有”bug”的,也就是说Autowired和Inject都是有坑的(称之为坑,不称之为bug是因为貌似是故意的。)。这是来源于线上的一个bug,也是这边文章的写作原因。现场如下:application-context.xml中有如下定义: 其中static-field应用的常量定义在如下类中:package me.arganzheng.study.spring.autowired;public interface Constants public interface Language public static final String EN = CommonConstants.LANG_ENGLISH; public static final String JP = CommonConstants.LANG_JAPANESE; public static final String IND = CommonConstants.LANG_INDONESIAN; public static final String PT = CommonConstants.LANG_PORTUGUESE; public static final String TH = CommonConstants.LANG_THAI; public static final String EN_RIN = CommonConstants.LANG_ENGLISH_INDIA; public static final String AR = CommonConstants.LANG_Arabic; 然后如果我们在代码中如下声明依赖:public class AutowiredTest extends BaseSpringTestCase Autowired private Map languageChangesMap; Test public void testAutowired() notNull(languageChangesMap); System.out.println(languageChangesMap.getClass().getSimpleName(); System.out.println(languageChangesMap); Guess what,诡异的事情发生了!运行结果如下:LinkedHashMapen=CommonConstants.LANG_ENGLISH, ja=CommonConstants.LANG_JAPANESE, ind=CommonConstants.LANG_INDONESIAN, pt=CommonConstants.LANG_PORTUGUESE, th=CommonConstants.LANG_THAI, ar=CommonConstants.LANG_Arabic, en-rIn=CommonConstants.LANG_ENGLISH_INDIA也就是说Map严重: Caught exception while allowing TestExecutionListener org.springframework.test.context.support.DependencyInjectionTestExecutionListener5c51ee0a to prepare test instance me.arganzheng.study.spring.autowired.AutowiredTest6e301e0org.springframework.beans.factory.BeanCreationException: Error creating bean with name me.arganzheng.study.spring.autowired.AutowiredTest: Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.Map me.arganzheng.study.spring.autowired.AutowiredTest.languageChangesMap; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type java.lang.String found for dependency map with value type java.lang.String: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: org.springframework.beans.factory.annotation.Autowired(required=true) .Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type java.lang.String found for dependency map with value type java.lang.String: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: org.springframework.beans.factory.annotation.Autowired(required=true) at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486) . 28 moredebug了一下,发现确实是Spring的一个bug。在DefaultListableBeanFactory的这个方法出问题了:protected Object doResolveDependency(DependencyDescriptor descriptor, Class type, String beanName, Set autowiredBeanNames, TypeConverter typeConverter) throws BeansException . else if (Map.class.isAssignableFrom(type) & type.isInterface() Class keyType = descriptor.getMapKeyType(); if (keyType = null | !String.class.isAssignableFrom(keyType) if (descriptor.isRequired() throw new FatalBeanException(Key type + keyType + of map + type.getName() + must be assignable to java.lang.String); return null; Class valueType = descriptor.getMapValueType(); if (valueType = null) if (descriptor.isRequired() throw new FatalBeanException(No value type declared for map + type.getName() + ); return null; Map matchingBeans = findAutowireCandidates(beanName, valueType, descriptor); if (matchingBeans.isEmpty() if (descriptor.isRequired() raiseNoSuchBeanDefinitionException(valueType, map with value type + valueType.getName(), descriptor); return null; if (autowiredBeanNames != null) autowiredBeanNames.addAll(matchingBeans.keySet(); return matchingBeans; . 关键在这一句:Map严重: Caught exception while allowing TestExecutionListener org.springframework.test.context.support.DependencyInjectionTestExecutionListener9476189 to prepare test instance me.arganzheng.study.spring.autowired.AutowiredTest2d546e21.Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type java.lang.String found for dependency map with value type java.lang.String: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: org.springframework.beans.factory.annotation.Autowired(required=true), org.springframework.beans.factory.annotation.Qualifier(value=languageChangesMap) at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486) . 28 moredebug了一下,发现跟没有指定qualifie name是一样的执行路径。不是指定了bean name了吗?为什么还是autowired by type呢?仔细查看了一下才发现。DefaultListableBeanFactory的doResolveDependency方法对首先对类型做了区别:protected Object doResolveDependency(DependencyDescriptor descriptor, Class type, String beanName, Set autowiredBeanNames, TypeConverter typeConverter) throws BeansException Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); 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(); return (descriptor.getField() != null ? converter.convertIfNecessary(value, type, descriptor.getField() : converter.convertIfNecessary(value, type, descriptor.getMethodParameter(); if (type.isArray() Class componentType = type.getComponentType(); Map matchingBeans = findAutowireCandidates(beanName, componentType, descriptor); if (matchingBeans.isEmpty() if (descriptor.isRequired() raiseNoSuchBeanDefinitionException(componentType, array of + componentType.getName(), descriptor); return null; if (autowiredBeanNames != null) autowiredBeanNames.addAll(matchingBeans.keySet(); TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter(); return converter.convertIfNecessary(matchingBeans.values(), type); else if (Collection.class.isAssignableFrom(type) & type.isInterface() Class elementType = descriptor.getCollectionType(); if (elementType = null) if (descriptor.isRequired() throw new FatalBeanException(No element type declared for collection + type.getName() + ); return null; Map matchingBeans = findAutowireCandidates(beanName, elementType, descriptor); if (matchingBeans.isEmpty() if (descriptor.isRequired() raiseNoSuchBeanDefinitionException(elementType, collection of + elementType.getName(), descriptor); return null; if (autowiredBeanNames != null) autowiredBeanNames.addAll(matchingBeans.keySet(); TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter(); return converter.convertIfNecessary(matchingBeans.values(), type); else if (Map.class.isAssignableFrom(type) & type.isInterface() Class keyType = descriptor.getMapKeyType(); if (keyType = null | !String.class.isAssignableFrom(keyType) if (descriptor.isRequired() throw new FatalBeanException(Key type + keyType + of map + type.getName() + must be assignable to java.lang.String); return null; Class valueType = descriptor.getMapValueType(); if (valueType = null) if (descriptor.isRequired() throw new FatalBeanException(No value type declared for map + type.getName() + ); return null; Map matchingBeans = findAutowireCandidates(beanName, valueType, descriptor); if (matchingBeans.isEmpty() if (descriptor.isRequired() raiseNoSuchBeanDefinitionException(valueType, map with value type + valueType.getName(), descriptor); return null; if (autowiredBeanNames != null) autowiredBeanNames.addAll(matchingBeans.keySet(); return matchingBeans; else Map matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty() if (descriptor.isRequired() raiseNoSuchBeanDefinitionException(type, , descriptor); return null; if (matchingBeans.size() 1) String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor); if (primaryBeanName = null) throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet(); if (autowiredBeanNames != null) autowiredBeanNames.add(primaryBeanName); return matchingBeans.get(primaryBeanName); / We have exactly one match. Map.Entry entry = matchingBeans.entrySet().iterator().next(); if (autowiredBeanNames != null) autowiredBeanNames.add(entry.getKey(); return entry.getValue(); 如果是Array,Collection或者Map,则根据集合类中元素的类型来进行autowired by type(Map使用value的类型)。为什么这么特殊处理呢?原来,Spring是为了达到这样的目的:让你可以一次注入所有符合类型的实现,也就是说可以这样子注入:Autowiredprivate List cars;如果你的car有多个实现,那么都会注入进来,不会再报org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type me.arganzheng.study.spring.autowired.Car is defined: expected single matching bean but found 2: audi, toyota.然而,上面的情况如果你用Resource则不会有这个问题:public class AutowiredTest extends BaseSpringTestCase Resource Qualifier(languageChangesMap) private Map languageChangesMap; Test public void testAutowired() assertNotNull(languageChangesMap); System.out.println(languageChangesMap.getClass().getSimpleName(); System.out.println(languageChangesMap); 正常运行:LinkedHashMappt=pt, br=pt, jp=ja, ja=ja, ind=ind, id=ind, en-rin=en-rIn, in=en-rIn, en=en, gb=en, th=th, ar=ar, eg=ar当然,你如果不指定Qualifier(“languageChangesMap”),同时field name不是languageChangesMap,那么还是一样报错的。Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type java.lang.String found for dependency map with value type java.lang.String: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: javax.annotation.Resource(shareable=true, mappedName=, description=, name=, type=class java.lang.Object, authenticationType=CONTAINER, lookup=)at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:986)at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:843)at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDepen

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论