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

写在前面:在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字段
@Resource
private 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
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值