Spring整理系列(10)——@Autowired自动装配、结合@Qualifier过滤及与JSR-250@Resource注解、JSR-330@Inject注解的区别、@Named使用

来源:互联网 发布:js实现图片转base64 编辑:程序博客网 时间:2024/06/09 13:44

写在前面:在Spring整理系列(02)——spring依赖注入,组装对象之间的依赖关系文中,第三部分简单介绍了使用@Autowired注解自动装配bean的情况,此处引用一下。

一、使用@Autowired注解,实现自动装配

在使用注解装配之前,首先要开启注解装配的方式,那就是在配置文件中加上下面这句话<context:annotation-config></context:annotation-config>,也可以使用<context:component-scan>标签(两者的区别在Spring整理系列(01)——spring概念简介、bean扫描与注册实现方式中有提到)。

使用@Autowired注解,可以用在属性、setter方法、constructor构造方法上,实现自动装配。

spring的xml配置文件:

    <!-- 开启注解配置 -->    <context:annotation-config></context:annotation-config>    <!-- 注册bean -->    <bean id="userDao" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl"></bean>    <!-- 注册bean -->    <bean id="userService" class="com.jsun.test.springDemo.ioc.User.UserServiceImpl"></bean>

UserServiceImpl:

1、注解在setter方法上:

    private UserDao userDao;    //添加注解,匹配注入与参数类型有关,即byType,与参数名称、setter方法名称、成员变量属性名称无关    @Autowired    public void setUserDao(UserDao userDao) {        System.out.println("注解自动装配setUserDao注入");        this.userDao = userDao;    }

2、constructor构造方法上:

    private UserDao userDao;    //添加注解,匹配注入与参数类型有关,即byType,与参数名称、成员变量属性名称无关    @Autowired    public UserServiceImpl(UserDao userDao){        System.out.println("注解自动装配构造器UserServiceImpl注入");        this.userDao = userDao;    }

3、声明的属性上:

    //添加注解,先按照属性名称匹配注入,如果未找到则按照属性类型匹配注入,即byName-->byType    @Autowired    private UserDao userDao;


二、使用@Autowired抛出异常情况及与@Qualifier注解结合使用情况


抛出异常情况:
@Autowired使用的时候必须只有一个Bean适合装配,否则spring会抛出异常;

1、NoSuchBeanDefinitionException异常:如果在应用上下文当中找不到相应的bean去自动装配,那么spring也会抛出异常。

。。。Caused by: org.springframework.beans.factory.BeanCreationException:  。。。Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type。。。

要避免这种情况发生,而且需要装配的属性也不是必须要装配的话,可以使用@Autowired(required=false)注解:

    //在注入bean的时候该属性不是必须的,即使找不到对应bean注入,也不会报异常    @Autowired(required=false)    private UserDao userDao;

2、NoUniqueBeanDefinitionException异常:如果在同一个spring容器中出现了两个或多个都必须存在的bean,然而自动装配只需要装配期中一个,也会抛出异常。

父类接口:

public interface TestBeanInterface {    public void sayHello();}

两个实现子类:

@Component("testBean1")public class TestBean1 implements TestBeanInterface{    public void sayHello(){        System.out.println("TestBean1 sayHello...");    }}@Component("testBean2")public class TestBean2 implements TestBeanInterface{    public void sayHello(){        System.out.println("TestBean2 sayHello...");    }}

测试类中:

    //以接口父类声明的成员变量属性,在spring容器中有它两个子类的bean    private TestBeanInterface testBean;    //自动装配,按照参数类型匹配注入bean,此时spring容器中TestBeanInterface类型有两个bean    @Autowired    public void setTestBean(TestBeanInterface t){        this.testBean = t;    }

执行测试的异常:

。。。Caused by: org.springframework.beans.factory.BeanCreationException:。。。Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException:。。。

这个时候@Autowired可以结合使用@Qualifier注解指定一个Bean来装配:

    @Autowired    public void setTestBean(@Qualifier("testBean2")TestBeanInterface t){        this.testBean = t;    }


注:@Qualifier注解其实就是先按照bean的name过滤装配指定类型bean,把@Autowired放在成员变量属性上,也是先按照属性name查找,再按类型注入,所以把@Autowired放在成员变量属性上报NoUniqueBeanDefinitionException异常的概率比较低,并且不需要setter或构造器,推荐使用。



三、@Autowired可以装配的spring内部bean,不可以装配的bean

1、@Autowired可以注解的spring内部类型:

可以用@Autowired注解那些解析依赖性接口,比如BeanFactory、ApplicationContext、Environment、ResourceLoader、ApplicationEventPublisher、MessageSource等

    @Autowired    private ApplicationContext context;    @Test    public void testGetBean(){        TestBeanInterface tb = (TestBeanInterface)context.getBean("testBean1");        System.out.println(tb.getClass().getName());    }

2、@Autowired不可以注解的类型:

因为@Autowired是由Spring BeanPostProcessor处理的,所以不能在自己的BeanPostProcessor或BeanFactoryPostProcessor类型应用@Autowired注解,这些类型必须通过xml或者@Bean注解形式加载。



四、@Autowired与JSR-250提供的@Resource注解的区别

1、先说@Autowired注解:

@Autowired是Spring提供的注解,需导入Package:org.springframework.beans.factory.annotation.Autowired;

@Autowired用在setter和构造器上只按照byType注入,用在成员变量field上,先按照byName注入,找不到则按照byType注入;

结合@Qualifier注解,可让setter和构造器实现byName匹配注入。



2、再说@Resource注解:

@Resource由J2EE提供,需导入javax.annotation.Resource;

@Resource有两个中重要的属性:name和type ,Spring将name属性解析为bean的名字,type属性解析为bean的类型。所以如果使用name属性,则按照byName自动注入,使用type属性则按照byType自动注入。如果既不指定name也不指定type属性,这时将通过反射机制默认使用byName自动注入。@Resource自动装配注入顺序如下:

  (1). 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常;
  (2). 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常;
  (3). 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常;
  (4). 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。


@Resource分别可以用在field、setter上,无法应用在constructor构造器上

//用于field字段@Resourceprivate TestBeanInterface testBean;//用于setter@Resource(name = "testBean1")public void setTestBean(TestBeanInterface t){    this.testBean = t;}


注:@Resource放在setter方法上,setter方法的参数必须是一个参数,如果是多参数,则抛出如下异常:

...org.springframework.beans.factory.BeanCreationException: Error creating bean with name ......Caused by: java.lang.IllegalStateException: @Resource annotation requires a single-arg method:...


如果需要多参数setter或者构造器注入,还需要替换为@Autowired结合@Qualifier实现。



3、补充:集合或Map类型bean,无法通过@Autowired注解注入,因为没有类型匹配到这样的bean,必须通过@Resource注解注入,通过唯一名称引用集合或Map类型bean

五、JSR-330注解@Inject、@Name使用介绍

1、spring3.0开始支持JSR330标注注解,使用JSR330需要引入javax.inject包,使用maven引入:

    <!-- 引入对JSR330的注解支持包 -->    <dependency>        <groupId>javax.inject</groupId>        <artifactId>javax.inject</artifactId>        <version>1</version>    </dependency>

2、@Inject:
等效于@Autowired,可以用于成员变量属性、setter方法、构造器,包括匹配注入情况和抛出异常情况,可以互换使用,代码实例参照上面@Autowired注解。

3、@Named:
如果想使用特定名称进行依赖注入,可以使用@Named,此时与@Quarlifier注解作用相同。

    @Inject    private UserDao userDao1;    @Autowired    @Named("userDao2")    private UserDao userDao2;    @Inject    @Named("userDao2")    public void setUserDao2(UserDao ud2){        this.userDao2 = ud2;    }    @Inject    public UserServiceImpl(@Named("userDao1")UserDao ud1){        this.userDao1 = ud1;    }

用在类上,与@Component注解作用是等效的。

@Named("tb")public class TestBean {    @PostConstruct    public void start(){        System.out.println("TestBean 初始化。。。");    }    @PreDestroy    public void cleanUp(){        System.out.println("TestBean 销毁。。。");    }}
0 0
原创粉丝点击