spring的@Autowired,@Qualifier和@Primary注解

1,@Autowired注解的使用

继续上文深入理解spring注解之@ComponentScan注解中的例子,现在我们需要在UserService中调用UserDao相关操作,那我们可以在UserService中增加如下代码:

import com.zhang.dao.UserDao;
@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    /**
     * 增加一个tostring方法 方便测试
     */
    @Override
    public String toString() {
        return "UserService [userDao=" + userDao + "]";
    }
}

测试代码如下:

AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainScanConfig.class);
UserService object = (UserService) applicationContext2.getBean("userService");
System.out.println("实例bean为 === "+object);

运行结果如下:

实例bean为 === UserService [userDao=com.zhang.dao.UserDao@51b279c9]

根据运行结果我们可以发现userDao已经成功注入到UserService中了

假设现在业务中有一种情况是UserDao是第三方提供的服务,我们也不能保证其是否可以成功加入到spring容器中,那我们也不能因为UserDao没能成功注入到spring容器而使我们整个UserService服务都不能使用,那这边我们就来演示一下这种情况,如下我们注释掉UserDao的@Repository注解:

import org.springframework.stereotype.Repository;
//@Repository
public class UserDao {
}

这个时候你再启动测试类会报如下错误:

警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.zhang.dao.UserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.zhang.dao.UserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1268)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
    at com.zhang.ApplicationTest.main(ApplicationTest.java:31)

其实很简单这个时候我们只需要在@Autowired注解中加上如下属性:

@Autowired(required=false)
private UserDao userDao;

再次运行测试类你会发现错误已经消失只是这个时候userDao是null如下:

实例bean为 === UserService [userDao=null]

2,@Qualifier注解的使用

把UserDao代码修改为如下:

import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
    // 给一个默认值
    private Integer version = 0;
    /**
     * 增加tostring方便测试
     */
    @Override
    public String toString() {
        return "UserDao [version=" + version + "]";
    }
    /**
     * @return the version
     */
    public Integer getVersion() {
        return version;
    }
    /**
     * @param version the version to set
     */
    public void setVersion(Integer version) {
        this.version = version;
    }
}

同时在配置类中增加一个@Bean的UserDao配置如下:

@Bean(value = "userDao2")
public UserDao getUserDao(){
        UserDao userDao = new UserDao();
        userDao.setVersion(2);
        return userDao;
}

运行测试类结果如下:

实例bean为 === UserService [userDao=UserDao [version=0]]

我们可以发现这个时候用的是默认的扫描到的UserDao,这个时候我们把UserService中注入的UserDao改成如下:

@Autowired(required=false)
private UserDao userDao2;

继续运行测试类结果如下:

实例bean为 === UserService [userDao=UserDao [version=2]]

从以上运行结果我们可以发现如果有多个同类型的bean默认是根据对应的bean名称注入的,那如果这个时候我们不想使用spring默认的注入方式而是希望根据自己业务需要指定固定的bean,那就是@Qualifier注解表现的时候了如下:

@Qualifier(value="userDao")
@Autowired(required=false)
private UserDao userDao2;

这个时候不管你UserDao定义什么名字永远只会注入userDao这个bean了

3,@Primary注解的使用

不管是因为洁癖还是什么也好可能有些同学不是特别喜欢使用@Qualifier注解,那么没关系,spring还为我们提供了另外一个注解@Primary同样可以实现以上功能

假设现在我们UserService中注入的UserDao是userDao2,这么这个时候我们可以在配置类中的UserDao上增加@Primary注解如下:

@Primary
@Bean(value = "userDao2")
public UserDao getUserDao(){
        UserDao userDao = new UserDao();
        userDao.setVersion(2);
        return userDao;
}

这个时候运行测试类你会发现UserService注入的就是userDao2了

注意:这个时候UserService中的UserDao就不能再加@Qualifier对应的注解了

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring中的@Primary和@Qualifier是两个常用的注解,用于解决当有多个同类型的bean需要注入时的歧义问题。 @Primary注解用在bean的定义上,表示该bean是优先选择的bean。当有多个同类型的bean需要注入时,Spring会优先选择被@Primary注解标记的bean作为注入的对象。 @Qualifier注解用在注入点上,可以和@Autowired、@Resource等注解一起使用,用来指定具体要注入的bean的名称。通过在@Qualifier中指定bean的名称,可以明确告诉Spring要选择哪个bean进行注入。 举个例子来说明,假设有一个接口类型的bean,下面有两个实现类A和B都实现了这个接口,并且都被Spring管理。 当我们在其他地方需要注入这个接口类型的bean时,如果不使用@Qualifier和@PrimarySpring会产生歧义,无法确定注入哪个实现类的对象。 使用@Primary注解,我们可以在实现类A上标注@Primary,表示A是优先选择的bean。 当需要注入接口类型bean时,Spring会自动选择A作为注入的对象。 使用@Qualifier注解,我们可以在注入点上标注@Qualifier,然后在@Qualifier中指定具体要注入的bean的名称。 比如,可以使用@Qualifier("beanA")明确指定要注入的bean是A。 以上就是@Primary和@Qualifier的基本用法和含义,通过使用这两个注解可以很方便地解决多个同类型bean的注入问题。 ### 回答2: spring中的@Primary和@Qualifier是依赖注入中的两个注解。 @Primary注解用于标注一个类为首选的bean。当有多个类型相同的bean存在时,spring将会优先选择被@Primary注解标注的bean进行注入。 @Qualifier注解可以与@Autowired一起使用,用于解决存在多个类型相同的bean时的歧义性。通过为@Autowired指定@Qualifier注解的value属性,可以指定具体注入哪个bean。 例如,假设我们有一个接口Person,有两个实现类:Student和Teacher。如果我们在Spring配置文件中同时注册了这两个bean,那么在注入Person类型的依赖时就会有歧义。此时,我们可以使用@Primary注解为其中一个实现类标注为首选bean。这样,在需要注入Person类型的地方,spring就会优先选择被@Primary注解标注的实现类进行注入。 另一种情况是,如果我们不想使用@Primary注解来标注首选bean,而是希望根据特定的条件进行选择注入,就可以使用@Qualifier注解。@Qualifier注解需要与@Autowired注解一起使用,通过指定value属性来指定注入哪个bean。比如,我们可以在@Autowired注解后添加@Qualifier("student")来指定注入的是Student类型的bean。 通过@Primary和@Qualifier注解,我们可以在存在多个类型相同的bean时,精确控制注入的对象,避免歧义性。 ### 回答3: Spring是一个开源的Java框架,提供了依赖注入(Dependency Injection)的功能。在Spring中,我们可以使用@Primary和@Qualifier注解来处理多个相同类型的实例。 @Primary注解用于标识在多个相同类型的Bean中,哪个Bean应该作为首选的Bean。当我们不使用@Qualifier注解指定具体的Bean时,Spring会自动选择使用带有@Primary注解Bean。例如,当我们有多个实现了同一个接口的类时,通过使用@Primary注解,我们可以指定一个类作为主要实现。 @Qualifier注解用于在多个相同类型的Bean中选择特定的Bean。当我们有多个相同类型的Bean需要注入时,在使用@Autowired或@Inject注入时,我们可以使用@Qualifier注解指定具体的Bean。@Qualifier注解的参数可以是Bean的名字或者是自定义的标识符。 举个例子来说,假设我们有一个接口Animal,有两个实现类Dog和Cat。如果我们希望将Cat作为首选的实现类,我们可以在Cat类上使用@Primary注解。如果有一个需要注入Animal类型的类,但我们想注入Dog,我们可以在注入的地方使用@Qualifier("dog")注解来指定具体的Bean。 总之,@Primary注解用于标识首选的Bean,@Qualifier注解用于指定特定的Bean。它们可以一起使用来处理多个相同类型的实例,使得依赖注入更加灵活和精确。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值