例子
配置Dao
操作接口,底层有通过Mysql
和Oracle
实现Dao
的两种方式;
配置UserService
接口和它的实现类UserServiceImpl
,在实现类中通过类依赖注入的方式,将对应的底层实现注入,为了解耦的方便,配置注入的名称通过properties
文件标注。
目录及代码说明
嫌啰嗦可以跳过这段:目录及代码说明
目录结构
Dao接口
public interface Dao {
public String getUserNameById();
}
Dao的Mysql实现类代码
public class MysqlDaoImpl implements Dao {
@Override
public String getUserNameById() {
return "mysql";
}
}
Dao的Oracle实现类代码
public class OracleDaoImpl implements Dao {
@Override
public String getUserNameById() {
return "oracle";
}
}
UserService接口
public interface UserService {
public String getUserNameByID();
}
UserService接口实现类代码
public class UserServiceImpl implements UserService {
@Override
public String getUserNameByID() {
return null;
}
}
步骤
第一步:需要将交给容器的类,用注解标注
- 在
MysqlDaoImpl
和OracleDaoImpl
两个类上面加上@Component
注解 - 在
UserServiceImpl
类上加上@Service
注解
说明:@Service
是基于@Component
的,它们的作用是一样的,只是作为架构方面来说,@Service能够提醒阅读代码的人,了解这是一个Service类。
第二步:配置配置类
@Configuration
@ComponentScan("juejin.autowrite")
public class AutoWriteConfig {
}
就是扫描配置注解的Bean
第三步:使用@Autowired注解
@Service
public class UserServiceImpl implements UserService {
private Dao dao;
@Autowired
public void setDao(Dao dao) {
this.dao = dao;
}
@Override
public String getUserNameByID() {
return dao.getUserNameById();
}
}
我们的目的是:在ServiceImpl
中需要用到Dao
的实现,所以通过set方式上添加@Autowired
注解,就可以自动将Spring
容器中对应的类型注入到该属性中。
第三步:写启动类,启动
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AutoWriteConfig.class);
UserServiceImpl bean = ctx.getBean(UserServiceImpl.class);
String name = bean.getUserNameByID();
System.out.println(name);
}
}
不出意外的话,你会得到一条报错信息NoUniqueBeanDefinitionException
,这个错误在自动注入时经常出现呢。
原因:
Dao
有两个实现类MysqlDaoImpl
和OracleDaoImpl
- 我们在Service中注入的是
private Dao dao;
@Autowired
public void setDao(Dao dao) {
this.dao = dao;
}
注意,上面有提到过@Autowired
是按照类型注入的,那么Dao
现在有两个实现类,Spring容器已经无法分清到底需要哪个了。
解决 NoUniqueBeanDefinitionException 报错
1. 使用@Qualifier配合@Autowired
@Autowired
@Qualifier("mysqlDaoImpl")
public void setDao(Dao dao) {
this.dao = dao;
}
输出:mysql
解释:这是因为@Qualifier
告诉了Spring容器,我需要注入的Bean名称,Spring容器根据id找Bean就不会出现不知道找哪个的问题啦。
2. 使用@Primary注解
在Service中还是老样子
@Autowired
public void setDao(Dao dao) {
this.dao = dao;
}
我们在Dao实现类OracleDaoImpl
上加上@Primary
注解
@Component
@Primary
public class OracleDaoImpl implements Dao {
@Override
public String getUserNameById() {
return "oracle";
}
}
输出:oracle
3.简化方法1,使用@Resource注解
@Resource = @Autowrite + @Qualifier
这个注解将两个注解合体使用啦,所以理解没有那么困难。
现状,硬编码的硬伤
@Autowired
@Qualifier("mysqlDaoImpl")
public void setDao(Dao dao) {
this.dao = dao;
}
这个mysqlDaoImpl
名字我是手动输入的,将它换成使用properties
注入,更加灵活
创建properties文件
daoName=mysqlDaoImpl
在配置类中使用@PropertySource
用法见Spring基础篇:利用注解将外部Properties属性注入到Bean中的方法 - 掘金 (juejin.cn)
使用@Resource注解
配置name属性,通过配置的读取的外部文件,注入到name属性中,实现通过配置文件修改底部注入的类。
@Resource(name = "${daoName}")
public void setDao(Dao dao) {
this.dao = dao;
}