默认根据类型,匹配不到则根据bean名字
测试:
1.声明一个dao接口
public interface BaseDao { void add(); }
2.两个实现dao接口的实现类,并配置上@Repository注解,且不指定该注解的属性,默认在Ioc容器中的Bean名为类名首字母小写的字符串
@Repository public class OracleRepository implements BaseDao { @Override public void add() { System.out.println("oracle repository"); } }
@Repository public class MySqlRepository implements BaseDao { @Override public void add() { System.out.println("mysql repository"); } }
3.现在增加一个Service层的接口
public interface HelloService { void add(); }
4.为Service接口增加实现类
@Service public class HelloServiceImpl implements HelloService { @Autowired // @Qualifier(value = "mySqlRepository") private BaseDao baseDao; @Override public void add() { System.out.println("hello service impl"); baseDao.add(); } }
5.测试程序
public class AppTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // @Component, @Controller, @Service, @Repository如果不指定属性那么bean的名字默认都是类名首字母小写 // 所以 HelloServiceImpl 类的bean名字为 helloServiceImpl HelloService helloService = (HelloService) context.getBean("helloServiceImpl"); helloService.add(); } }
结果报错
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'helloServiceImpl':
Unsatisfied dependency expressed through field 'baseDao'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'com.convict.dao.BaseDao' available: expected single matching bean but found 2: mySqlRepository,oracleRepository
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'helloServiceImpl': Unsatisfied dependency expressed through field 'baseDao'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.convict.dao.BaseDao' available: expected single matching bean but found 2: mySqlRepository,oracleRepository
分析:
因为第2步中,声明了两个dao的实现类,但是@Repository 注解中没有指定这个Bean的名字,所以Spring默认给他们起了类名首字母小写为它们各自的名字,即
OracleRepository实例化后在IoC容器中的bean名字为 oracleRepository
MySqlRepository实例化后在Ioc容器中的bean名字为 mySqlRepository
而在 HelloServiceImpl 类中使用了@Autowired 注解修饰 private BaseDao baseDao; @Autowired注解会先去根据类型找,即找到这个接口的实例化对象,即子类,然后装配给这个属性,然而这个接口现在有两个实现类,所以此时@Autowired 注解无法识别找哪个,即报上面的异常
现在把第4步的注释取消,即显示的用 @Qualifier 注解指定了IoC容器的一个bean来装配,下面我指定用 mySqlRepository
@Service public class HelloServiceImpl implements HelloService { @Autowired @Qualifier(value = "mySqlRepository") private BaseDao baseDao; @Override public void add() { System.out.println("hello service impl"); baseDao.add(); } }
结果:
装配成功了
但是如果我不想用@Qualifier 注解呢,那么我们还有两种方法,第一种是在dao的实现类@Repository 注解中指定该bean的名字跟 注入的属性的名字一致即可
如修改OracleRepository 类
@Repository("baseDao") public class OracleRepository implements BaseDao { @Override public void add() { System.out.println("oracle repository"); } }
可看到,我指定了这个 bean名字就叫做baseDao,而MySQLRepository 类中@Repository注解不指定属性,则它由Spring自己命名,为 mySQLRepository
现在Service文件是这个样子,属性名字就叫做 baseDao,跟上面我指定的bean名字是一样的
@Service public class HelloServiceImpl implements HelloService { @Autowired // @Qualifier(value = "mySqlRepository") private BaseDao baseDao; @Override public void add() { System.out.println("hello service impl"); baseDao.add(); } }
测试程序启动,结果如下
装配成功了,把IoC中名字为 baseDao的对象 注入了
现在说一下最后一种,我不指定@Repository 的任何一个属性,我现在新增加一个类,也是实现BaseDao 接口的
@Repository public class SqlServerRepository implements BaseDao { @Override public void add() { System.out.println("SqlServer repository"); } }
现在Ioc中该bean的名字为 sqlServerRepository
现在修改Service文件,不叫baseDao了, 接口还是BaseDao,但名字叫做 sqlServerRepository,代码如下
@Service public class HelloServiceImpl implements HelloService { @Autowired // @Qualifier(value = "mySqlRepository") private BaseDao sqlServerRepository; @Override public void add() { System.out.println("hello service impl"); sqlServerRepository.add(); } }
结果如下:
总结:
要么不指定bean的名字,由spring自己生成,那么@Autowired 注解修饰的属性的名字,要跟spring生成的bean 的名字一致即可
要么指定一下bean的名字,且@Autowired 注解修饰的属性的名字,跟自己指定的bean的名字一致即可
要么不管@Repository,也不管属性怎么命名,那么需要在@Autowired 之后再加一个@Qualifier 注解,指明从IoC容器中拿哪个名字的bean