博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring 系列之Spring常用注解总结
阅读量:6919 次
发布时间:2019-06-27

本文共 17443 字,大约阅读时间需要 58 分钟。

  传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、实物,这么做有两个缺点:

1、如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大;如果按需求分开.xml文件,那么.xml文件又会非常多。总之这将导致配置文件的可读性与可维护性变得很低。

2、在开发中.java文件和.xml文件之间不断切换,是一件麻烦的事,同时这种思维上的不连贯也会降低开发的效率。

  为了解决这两个问题,Spring引入了注解,通过“@XXX”的方  式,让注解与Java Bean紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性。

  不使用注解:

  先看一个不使用注解的Spring示例,在这个示例的基础上,改成注解版本的,这样也能看出使用与不使用注解之间的区别,先定义一个老虎:

package com.spring.model;public class Tiger{  private String  tigerName="TigerKing";  public String toString(){    return "TigerName:"+tigerName;  }}

  再定义一个猴子:

package com.spring.model;public class Monkey{    private String monkeyName="MonkeyKing";    public String toString(){       return "MonkeyName:"+monkeyName;     }}

  定义一个动物园:

package com.spring.model;public class Zoo{    private  Tiger tiger;    private Monkey monkey;        public Tiger getTiger(){       return tiger;     }     public void setTiger(Tiger tiger){        this.tiger=tiger;     }    public Monkey getMonkey(){        return monkey;     }    public void setMonkey(Monkey monkey){        this.monkey=monkey;    }     public String toString(){         return tiger+"\n"+monkey;    }}

  spring的配置文件这么写:

  测试方法:

public class TestAnnotation{  /**    *不使用注解    */      @Test   public void test(){      //读取配置文件      ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext2.xml");      Zoo zoo=(Zoo) ctx.getBean("zoo");     System.out.print(zoo.toString());  }}

  都很熟悉,权当复习一遍了。

  1、@AutoWired

  @Autowired顾名思义,就是自动装配,其作用是为了消除Java代码里面的getter/setter与bean属性中的property。当然,getter看个人需求,如果私有属性需要对外提供的话,应当予以保留。@Autowirred默认按类型匹配的方式,在容器查找匹配的Bean,当且仅有一个匹配的Bean时,Spring将其注入@AutoWired标注的变量中。

  因此,引入@AutoWired注解,先看下Spring配置文件怎么写:

1 
2
12 13
14 15
16
17
18 19

  注意第13行,使用必须告诉spring一下我要使用注解了,<context:component-scan base-package="XXX"/>是一种简单的,spring会自动扫描xxx路径下的注解。

  看到第15行,原来zoo里面应当注入两个属性tigger、monkey,现在不需要注入了。再看下,Zoo.java也很方便,把getter/setter都可以去掉:

package com.spring.model;import org.springframework.beans.factory.annotation.Autowired;public class Zoo{    @Autowired    private Tiger tiger;     @Autowired    private Monkey monkey; public String toString(){        return tiger+"\n"+monkey;    }     }

  这里@Autowired注解的意思就是,当Spring发现@Autowired注解时,将自动在代码上下文中找到和其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方去。

  有一个细节性的问题是,假如bean里面有两个property,Zoo.java里面又去掉了属性的getter/setter并使用@Autowired注解标注这两个属性那会怎么样?答案是Spring会按照xml优先的原则去Zoo.java中寻找这两个属性的getter/setter,导致的结果就是初始化bean报错。

  OK,假设此时我把.xml文件的16行、17行两行给去掉,再运行,会抛出异常:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'zoo': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.spring.model.Tiger com.spring.model.Zoo.tiger; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring.model.Tiger] found for dependency: 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.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1074)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)    at org.springframework.context.support.ClassPathXmlApplicationContext.
(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.
(ClassPathXmlApplicationContext.java:83) at com.spring.test.TestAnnotation.test(TestAnnotation.java:16) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.spring.model.Tiger com.spring.model.Zoo.tiger; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring.model.Tiger] found for dependency: 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.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:502) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:282) ... 36 moreCaused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring.model.Tiger] found for dependency: 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:920) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:789) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:474) ... 38 more

  因为,@Autowired注解要去寻找的是一个Bean,Tiger和Monkey的Bean定义都给去掉了,自然就不是一个Bean了,Spring容器找不到也很好理解。那么,如果属性找不到我不想让Spring容器抛出异常,而就是显示null,可以吗?可以的,其实异常信息里面也给出了提示了,就是将@Autowired注解的required属性设置为false即可:

package com.spring.model;import org.springframework.beans.factory.annotation.Autowired;public class Zoo {        @Autowired(required=false)    private Tiger tiger;        @Autowired(required=false)    private Monkey monkey;        public String toString(){        return tiger + "\n" + monkey;    }    }

此时,找不到tiger、monkey两个属性,Spring容器不再抛出异常而是认为这两个属性为null。

2、Qualifier(指定注入Bean的名称)

  如果容器中有一个以上匹配的Bean,则可以通过@Qualifier注解限定Bean的名称,看下面的例子:

定义一个Car接口:

package com.spring.service;public interface ICar {        public String getCarName();}

  两个实现类BMWCar和BenzCar:

package com.spring.service.impl;import com.spring.service.ICar;public class BMWCar implements ICar{        public String getCarName(){        return "BMW car";    }}
package com.spring.service.impl;import com.spring.service.ICar;public class BenzCar implements ICar{        public String getCarName(){        return "Benz car";    }}

  再写一个CarFactory,引用car(这里先不用@Qualifier注解):

package com.spring.model;import org.springframework.beans.factory.annotation.Autowired;import com.spring.service.ICar;public class CarFactory {        @Autowired    private ICar car;        public String toString(){        return car.getCarName();    }    }

  配置文件:

1 
2
12 13
14 15
16
17
18
19 20

  测试方法:

/** * Autowired注解配合Qualifier注解 */@Testpublic void test1(){    //读取配置文件    ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext2.xml");    CarFactory carFactory=(CarFactory) ctx.getBean("carFactory");    System.out.println(carFactory.toString());}

  运行一下,不用说,一定是报错的,Car接口有两个实现类,Spring并不知道应当引用哪个实现类。

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'carFactory': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.spring.service.ICar com.spring.model.CarFactory.car; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:No unique bean of type [com.spring.service.ICar] is defined: expected single matching bean but found 2: [bmwCar, benz]    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1074)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)    at org.springframework.context.support.ClassPathXmlApplicationContext.
(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.
(ClassPathXmlApplicationContext.java:83) at com.spring.test.TestAnnotation.test1(TestAnnotation.java:25) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.spring.service.ICar com.spring.model.CarFactory.car; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.spring.service.ICar] is defined: expected single matching bean but found 2: [bmwCar, benz] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:502) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:282) ... 36 moreCaused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.spring.service.ICar] is defined: expected single matching bean but found 2: [bmwCar, benz] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:796) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:474) ... 38 more

出现这种情况通常有两种解决办法:

(1)、在配置文件中删除其中一个实现类,Spring会自动去base-package下寻找Car接口的实现类,发现Car接口只有一个实现类,便会直接引用这个实现类。
(2)、实现类就是有多个该怎么办?此时可以使用@Qualifier注解来指定Bean的名称:

package com.spring.model;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import com.spring.service.ICar;public class CarFactory {        @Autowired    @Qualifier("bmwCar")    private ICar car;        public String toString(){        return car.getCarName();    }    }

此处会注入名为"bmwCar"的Bean。

3、Resource

@Resource注解与@Autowired注解作用非常相似,这个就简单说了,看例子:

package com.spring.model;import javax.annotation.Resource;public class Zoo1 {        @Resource(name="tiger")    private Tiger tiger;        @Resource(type=Monkey.class)    private Monkey monkey;        public String toString(){        return tiger + "\n" + monkey;    }}

这是详细一些的用法,说一下@Resource的装配顺序:

(1)、@Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配
(2)、指定了name或者type则根据指定的类型去匹配bean
(3)、指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错

然后,区分一下@Autowired和@Resource两个注解的区别:

(1)、@Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配
(2)、@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了
Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。

转载于:https://www.cnblogs.com/xianfengzhike/p/9096824.html

你可能感兴趣的文章
企业网络:安全只能靠两招
查看>>
中国CRM企业“学习”Salesforce,只是在集体自嗨?
查看>>
驱动智能制造的大数据时代
查看>>
智能家居独角兽将在传统企业中诞生
查看>>
IT仍是美国最佳就业岗位:人才稀缺令科技公司很着急
查看>>
Linux恶意软件将树莓派设备变成“矿工”
查看>>
拥抱开放式网络 通往下一代数据中心
查看>>
为了防止客户的丢失,请客服人员禁止做的四件事
查看>>
39人被骗147万 大麦网遭撞库带来的警醒
查看>>
SDN重塑企业网络 网络管理者的角色转变
查看>>
NGINX发布新版本,旨在解决应用程序安全性
查看>>
在SSH中增加JUNIT4单元测试
查看>>
阿里巴巴物联网战略软硬通吃 不做产品做生态
查看>>
柳传志:市场不理解联想控股 不会减持联想集团
查看>>
从雷军提案看涂鸦硬件智能化升级方案v2.0
查看>>
移动化办公:Saas的3种困境和新的模式
查看>>
Test Case所涵盖的范围足够了吗?
查看>>
Debian 移植到 OpenRISC 架构
查看>>
《大数据架构和算法实现之路:电商系统的技术实战》——1.4 分类效果评估...
查看>>
CoreOS 继续推进 Docker 容器替代 Rockets
查看>>